views:

336

answers:

8

To be specific, I'm talking about avoiding this type of code:

<input type='text' id='title_33' class='title'
  onfocus='updateCharsLeft(33);' 
  onkeypress='updateCharsLeft(33);' />

Here I would like to put the onfocus and onkeypress event handles separately, i.e in a .js file. Like this:

$(document).ready(function()
  {
    $(".title").focus(updateCharsLeft);
    $(".title").keypress(updateCharsLeft);
);

However here the problem is that the ID of the textbox needs to be passed onto the function updateCharsLeft(). It would suck to have to extract out the id from the ID of the textbox in that function, so it would actually be cleaner to just put in the event handlers within the HTML code.

Thoughts?

+7  A: 

Can't you do this:

$(document).ready(function()
  {
    $(".title").focus(function() {
        updateCharsLeft(this.id);
    });
    $(".title").keypress(function() {
        updateCharsLeft(this.id);
    });
);

or more neatly:

$(document).ready(function()
  {
    $(".title .another .someother .andAnother").focus(function() {
        updateCharsLeft(this.id);
    }).keypress(function() {
        updateCharsLeft(this.id);
    });
);
karim79
Like I said in the question, it would suck to have to extract out the numerical id from 'title_xx' in the function using this.id. And also, this isn't the only element i need to set an event handler on, I'll need to set them on 10 elements and i don't want to duplicate the code for extracting the numerical id from this.id in each of those functions
Click Upvote
@Click Upvote - So specify multiple elements within your selector e.g. $('.title .foo .blah .g .f').keypress(blah...
karim79
If you don’t want to use a contextual value (from the “this” object) then essentially the values you are passing in (“33”) are magic numbers. If you want to refactor your code to bind these event handlers on a common way you will need to use something contextual. You will have to pass this.Id and process it. Unless...see below...
Andy McCluggage
Extracting the number doesn't have to be hard - if they are all in that format you can just do this.id.replace(/[^\d]/gi,"") and you're done.
Hugoware
+1  A: 

I definitely think you should separate your JavaScript and HTML. It will be easier to find/maintain, and you can edit one place rather than 10. Don't repeat yourself.

I would look into using jQuery's live functionality. If you have 10 text input's, your adding 20 event handlers this way as opposed to 2 (one for EVERY focus handler on the page and one for EVERY keypress handler on the page).

Also re your comment to karim, I don't see why you would be duplicating yourself. It should be trivial to pass the id or transform it with a regular expression if necessary as long as your consistent in your naming convention For example, this.id.replace(/.*(\d+)$/,''). However, it would probably even be better to pass the direct DOM element reference instead, and work with that in your function.

Lastly, you seem to think that some aspect of this will suck. Maybe I'm missing the point, but can you clarify what's so difficult about mainupaliting the id or the DOM reference or whatever else that you need to do? Maybe post a longer code sample of what you're doing next.

Keith Bentrup
its not that it will be hard to extract the numeric id from the dom element's id, just that this code will need to be repeated throughout all my event handler functions.
Click Upvote
+2  A: 

I've had to do something similar before and also wasn't happy with parsing the value out the ID attribute. The best thing I can suggest is that you use another attribute for the value you need, like the rel attribute:

<input type='text' id='title_33' class='title' rel='33' />

Or depending on how religious you are about validation, just use a custom attribute:

<input type='text' id='title_33' class='title' myval='33' />
roryf
how do you get the value of the rel in the function? can you use this.rel?
Click Upvote
Since you're already using jQuery, just use $(this).attr('rel')
roryf
A: 

I would try to manage the all events from a single JavaScript block. As long as you are able to reference elements on the page, this should be possible.

G Berdal
A: 

You could always use the string functions to parse out the value and pass it along, e.g.

$(".title").focus(function() {
   var thisid = this.id;
   updateCharsLeft(thisid.substring(thisid.indexOf("_") + 1));
});

I'm not sure what the performance implications would be if you had to do this for a lot of elements though.

Olly Hodgson
+1  A: 

If you really don’t want to pass this.Id then you could add a custom attribute to the input tag...

<input type='text' id='title_33' idSuffix='33' class='title'/>

You then set the event handlers like this...

$(document).ready(function()
{
    $(".title").focus(function() {
        updateCharsLeft(this.idSuffix);
    });
    $(".title").keypress(function() {
        updateCharsLeft(this.idSuffix);
    });
);

I personally like custom attributes. They provide a way to give Html tags custom metadata and keep it all in the markup. Html validators don’t like them though :-(

Andy McCluggage
A: 
$(document).ready(function(){
 var update = function(){ updateCharsLeft(this.id.split("_")[1]); };
 $("input.title")
  .focus(update)
  .keypress(update);
});
A: 

This is exactly what Unobtrusive Javascript technique focuses on.

Grzegorz Oledzki