learningtech
learningtech

Reputation: 33715

HTML IDs turning out to be like intrusive javascript?

Hey everyone, take a look at the code below and appreciate how messy the id attributes are

View File

<?php foreach($array_project as $prj) : ?>
   <div id="prj-p<?=$item['project_id'] ?>">
    <?php foreach($arr_skill as $skill) : ?>
        <h2><?=$skill['name'] ?></h2>
        <a class="view" id="skill-p<?=$prj['project_id'] ?>-s<?=skill['skill_id'] ?>">view</a>
        <a class="edit" id="edit-p<?=$prj['project_id'] ?>-s<?=skill['skill_id'] ?>">edit</a>
        <a class="delete" id="delete-p<?=$prj['project_id'] ?>-s<?=skill['skill_id'] ?>">delete</a>
    <?php endforeach; ?>
   </div>
<?php endforeach; ?>

Javascript File (using Jquery)

$('.view').live('click', onClick);
$('.edit').live('click', onClick);
$('.delete').live('click', onClick);

function onClick()
{
    // prjId and skillId are effectively arguments that are
    // traditionally passed via onClick(prjId, skillId), but here
    // we've attached them to element ids
    prjId = this.id.replace(/(skill\-p)|(\-s\d+)/g, '')
    skillId = this.id.replace(/(skill\-p\d+)|(\-s)/,'');

    // do stuff with the prjId and skillId
}

So my issue with the above code is that doing something like this in the view file

<a class="view" id="skill-p<?=$prj['project_id'] ?>-s<?=skill['skill_id'] ?>">view</a>

is effectively the same as

<a onclick="onClick(<?=$prj['project_id'] ?>,<?=skill['skill_id'] ?>)">view</a>

With the latter actually being more readable to the programmer. In the former, I don't like how I have to derive my own id naming convention to keep track of database entity ids: for example, -p prefix denotes project id, and -s prefix denotes skill_id. And then I have to use regular expression to parse it. I don't liek the latter of inline js event handlers, because that's intrusive javascript.

I thought about simplifying the code like this:

View File

<?php foreach($array_project as $prj) : ?>
   <div id="prj-p<?=$item['project_id'] ?>">
    <?php foreach($arr_skill as $skill) : ?>
        <h2><?=$skill['name'] ?></h2>
        <input type="hidden" class="project_id" value="<?=$prj['project_id'] ?>" />
        <input type="hidden" class="skill_id" value="<?=$prj['skill_id'] ?>" />
        <a class="view">view</a>
        <a class="edit">edit</a>
        <a class="delete">delete</a>
    <?php endforeach; ?>
   </div>
<?php endforeach; ?>

Javascript File (using Jquery)

$('.view').live('click', onClick);
$('.edit').live('click', onClick);
$('.delete').live('click', onClick);

function onClick()
{
    prjId = this.parentNode.childNodes[1].value;
    skillId = this.parentNode.childNodes[2].value;

    // do stuff with the prjId and skillId
}

This is much easier less coding when I have A LOT of db entity ids to reference between the js and view files (eg. i only have to print the project_id and skill_id ONCE). But the problem with this solution is that as soon as my designer changes the xhtml schema, I have to update my javascript file to re-reference the hidden input fields.

Is there an easier and less code-redundant way for html elements to pass data to javascript functions?

Upvotes: 0

Views: 190

Answers (2)

Dave Aaron Smith
Dave Aaron Smith

Reputation: 4567

This is a little less sensitive too, though I like @Nick's a little better.

function onClick()
{
    prjId = $(this).parent().find(".project_id").attr("value");
    skillId = $(this).parent().find(".skill_id").attr("value");

    // do stuff with the prjId and skillId
}

Upvotes: 1

Nick Craver
Nick Craver

Reputation: 630549

You could use data attributes, like this:

<?php foreach($array_project as $prj) : ?>
   <div id="prj-p<?=$item['project_id'] ?>" data-pid="<?=$prj['project_id'] ?>" data-sid="<?=$prj['skill_id'] ?>">
    <?php foreach($arr_skill as $skill) : ?>
        <h2><?=$skill['name'] ?></h2>
        <a class="view">view</a>
        <a class="edit">edit</a>
        <a class="delete">delete</a>
    <?php endforeach; ?>
   </div>
<?php endforeach; ?>

Then access them in jQuery:

$('.view, .edit, .delete').live('click', onClick);

function onClick()
{
    var div = $(this).closest("div"), 
        prjId = div.attr("data-pid"),
        skillId = div.attr("data-did");

    // do stuff with the prjId and skillId
}

This work in HTML4 and is a part of the HTML5 standard, so no conflicts now, completely compliant HTML later. with this approach you may not even needs the id on the <div>, if that's the case you can remove the attribute, since it's not needed, only the data- ones are used in the onClick() function above. You may also want to give that container <div> a class, like class="project" and change the call to find it to .closest(".project") to make it a bit more resilient.

Upvotes: 3

Related Questions