2

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?

3 Answers 3

2

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();      
});
Sign up to request clarification or add additional context in comments.

Comments

1

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

2 Comments

Nice, this is a nicely elegant (and jQuery) way of solving the actual problem.
@cincodenada Thanks. Probably can be improved much better though... But guess would be more reusable if OP is interested in extending the functionality...
1

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.

1 Comment

Very nice point about the XY problem. OP should probably adhere to your answer more than mine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.