views:

369

answers:

3

I have a custom jQuery script that works fine in all bowsers but one (Explorer 6, 7, 8?).

The purpose of the code is to allow a user to add multiple form fields to their form (if the user want more than one phone number or more than one web address).

It is written so that any "A" tag with a class containing "add" is bound to the jQuery function.

The error I am getting is as follows:

///////////////////////////////
Line: 240
Char: 5
Error: 'this.id.3' is null or not an object
Code: 0
///////////////////////////////

HTML of form: (please note that I am aware that the form tags are not here, this is a small portion of a larger form.

<ul>
<li>
    <ul>
    <li class="website">
     <input id="website1_input" name="website[1][input]" type="text" value="www.test.org"/>
     <input type="checkbox" id="website1_delete" name="website[1][delete]" class="element radio" value="1" />
     <label for="website1_delete">Delete</label>     
    </li>
    </ul>
    <a href="#" id="addWebsite">add another website</a>
    </li>
</ul>

And now the jQuery:

There should be on a page a ul containing at least one li. All the lis should have a certain class like "phone" or "address" After the /ul There should be a link with a matching id, like "addPhone" or "addAddress". The href attribute should be "#".

function makeAddable(theClass) {
  $('#add' + theClass[0].toUpperCase() + theClass.substr(1)).click(function() {
    var numItems = $('.' + theClass).length;
    var newItem = $('.' + theClass).eq(numItems - 1).clone();
    newItem.find('input[type=text]').val('');
    numItems++; // number in the new IDs

    // keep ids unique, linked to label[for], and update names
    // id & for look like: phone1_type, phone1_ext, phone13_p1, etc.
    // names look like: phone[1][type], phone[1][ext], phone[13][p1], etc.
    newItem.find('[id^=' + theClass + ']').each(function(i) {
      var underscoreIndex = this.id.indexOf('_');
      var idNum = this.id.substring(theClass.length, underscoreIndex);
      this.id = this.id.replace(idNum, numItems);
    });
    newItem.find('[for^=' + theClass + ']').each(function(i) {
        var jqthis = $(this);
        var forAttr = jqthis.attr('for');
        var underscoreIndex = forAttr.indexOf('_');
        var idNum = forAttr.substring(theClass.length, underscoreIndex);
        forAttr = forAttr.replace(idNum, numItems);
        jqthis.attr('for', forAttr);
    });
    newItem.find('[name^=' + theClass + ']').each(function(i) {
        var jqthis = $(this);
        var nameAttr = jqthis.attr('name');
        var bracketIndex = nameAttr.indexOf(']');
        var idNum = nameAttr.substring(theClass.length + 1, bracketIndex);
        nameAttr = nameAttr.replace(idNum, numItems);
        jqthis.attr('name', nameAttr);
    });

    $(this).prev('ul').append(newItem);
    return false;
  });
}

// Automatically enable all <a href="#" id="addSomething"> links
$(function() {
  $('a[href=#][id^=add]').each(function(i) {
    makeAddable( this.id[3].toLowerCase() + this.id.substr(4) );
  });
});
+4  A: 
this.id.charAt(3).toLowerCase()
Fabien Ménager
When I change "this.id[3].toLowerCase()" to "this.id.charAt(3).toLowerCase()" I get: "Error: '0' is null or not an object"
superUntitled
Apparently in IE string[index] is not defined. So for your second error, it would be theClass.charAt(0), instead of theClass[0]. Same goes for everwhere else you use stringName[number].
Sean Nyman
+1  A: 

Change this...

this.id[3]

To this...

this.id.substr(3, 1);
Josh Stodola
substr() is deprecated.
J-P
can you give a link to the documentation on substr() being deprecated?
thief
The substr function is certainly not deprecated, nor will it ever be.
Josh Stodola
Haha yeah thats what I was thinking!
thief
+1  A: 

Something like this will achieve the same affect but makes greater use of jquery, thereby avoiding the crossbrowser compatibility problems so common with javascript:

function addInput(inputType) {
 var items, itemNumber, lastItem, newListItem, parentList, inputName, inputId, deleteId, thisId;

 items = $('li.' + inputType);
 itemNumber = items.length + 1;
 lastItem = $(items[itemNumber-2]);
 newListItem = lastItem.clone();
 parentList = lastItem.parents('ul:first');

 inputId = inputType + itemNumber + '_input';
 deleteId = inputType + itemNumber + '_delete';

 $(':input', newListItem).each(function() {
  inputName = $(this).attr('name').replace(/\[\d*\]/, '['+itemNumber+']');
  thisId = $(this).attr('id').match(/_delete/) ? deleteId : inputId

  $(this)
   .val('')
   .removeAttr('checked')
   .attr('id', thisId)
   .attr('name', inputName)
  }).end()
  .find('label').attr('for', deleteId).end()
  .appendTo(parentList)
 ;
}

$(function() {
 $('a[href=#][id^=add]').live('click', function() {
  addInput(this.id.substr(3).toLowerCase());
 });
});
thief