Madzergling
Madzergling

Reputation: 43

jquery each adding custom method over iteration

I have a collection of checkboxs and I want to create a custom method for them depending on which class they have.

var checkboxs = $("input[type=checkbox]");
    checkboxs.each(function(){
        if($(this).hasClass("class1")){
            $(this).method1 = function(){
                $(this).removeAttr("checked");
                return $(this);
            }
        }
        if($(this).hasClass("class2")){
            $(this).method1 = function(){
                $(this).parents("tr").next().hide();
                $(this).removeAttr("checked");
                return $(this);
            }
        }
    });

Then if, I want to do this:

checkboxs.each(function(){
        $(this).method1();
    });

It tells me that there's no method1 method. Why doesn't that work?

Upvotes: 2

Views: 87

Answers (3)

PSL
PSL

Reputation: 123739

Or you could write an common function extending jquery prototype.

$.fn.method1 = function(){
    if(!this.is(':checkbox')) return this; //If it is called on a non check box just do nothing
    if(!this.is('.class1, .class2')) return this; //if this is not of targetted classes return

    if(this.is('.class2')){ //if class2 hide the next of its closest tr which comes up in its parent hierarchy.
        this.closest('tr').next().hide();  //using closest assuming you want to check only its immediate tr in its parent hierarchy
    }
    this.prop("checked", false); //uncheck it if it is class 1 or 2
    return this;
}

Demo

  • This way you can extend this functionality to any other elements.
  • You can customize by setting options, (ex: to specify classes callbacks etc)

With the below you can avoid iteration at source:

Method:

$.fn.method1 = function () {
    this.each(function(){
        var $this = $(this);
        if (!$this.is(':checkbox')) return true;
        if (!$this.is('.class1, .class2')) return true;
        if ($this.is('.class2')) {
            $this.next().css('color', 'red');
        }
        $this.prop("checked", false);
    });
    return this;
}

Usage:

$("input[type=checkbox]").method1();

Demo

Upvotes: 1

cincodenada
cincodenada

Reputation: 3097

You can't just assign properties like that to a jQuery object, as it's just a wrapper around the element and will be re-created each time.

If you want to attach attributes to an element, use the data() method. I'm not sure if this works for functions, but it's worth a shot.

In your case though, I suspect we have a bit of an XY problem. I would simply check the class of the object in the callback.

An example of what this might look like:

method1 = function() {
    if($(this).hasClass("class2")) {
        $(this).parents("tr").next().hide();
    }
    $(this).removeAttr("checked");
    return $(this);
}

checkboxs.each(function(){
    method1();
});

Depending on your use case, it may also work to just call each() on selections, which might look something like just running this instead of the last bit of code:

$('input[type=checkbox].class1').each(function(){
    $(this).method1 = function(){
        $(this).removeAttr("checked");
        return $(this);
    }
});
$('input[type=checkbox].class2').each(function(){
    $(this).method1 = function(){
        $(this).parents("tr").next().hide();
        $(this).removeAttr("checked");
        return $(this);
    }
});

Without some actual code and context, we can't really tell you how best to do what you want.

Upvotes: 1

Hugo Tunius
Hugo Tunius

Reputation: 2879

The problem is that $(this) creates a new jQuery object with the this variable. This is done each time you call $(this) therefor adding a method to $(this) in one place will not make the method last in subsequent calls to $(this).

This jsFiddle shows the problem http://jsfiddle.net/92cub/1/

EDIT: I that the function could differ for each element, I've changed the given code to use the data function in jQuery instead. Also you were doing $(this) repeatedly so I removed that. The call $(this) is quite heavy to do over and over again.

Instead you could do something likes this:

var checkboxs = $("input[type=checkbox]");
    checkboxs.each(function(){
      var $this = $(this);  

      if($this.hasClass("class1")){
           $this.data("func", function (){
                $this.removeAttr("checked");
                return $this;
            });
        }
        if($this.hasClass("class2")){
            $this.data("func", function(){
                $this.parents("tr").next().hide();
                $this.removeAttr("checked");
                return $this;
            });
        }
    });

To call the function use:

checkboxs.each(function(){
    $(this).data("func").apply();      
});

Upvotes: 2

Related Questions