Coffeescript 'this' inside jQuery .each()

JavascriptCoffeescript

Javascript Problem Overview


I have some coffeescript like the following:

class foo:
    @bar = 'bob loblaw'

    processRows: ->
        $("#my-table>tr").each ->
            id = $(this).attr("id")
            @processRow id

    processRow: (id) ->
        console.log @bar + id

So my problem is: I need this to reference the .each context inside the loop to get at id, but I also would like this to reference the class instance inside foo.processRow()---which it does not currently do.

Using something like _this = this outside the .each function and passing it around isn't a great solution, either, since I reference many class variables inside processRow.

Any thoughts? Am I missing something obvious? Thanks!

Javascript Solutions


Solution 1 - Javascript

jQuery.each passes the current element as second parameter of the callback, so you don't have to reserve this for jQuery:

processRows: ->
    $("#my-table>tr").each (index, element) =>
        id = $(element).attr("id")
        @processRow id

Notice the use of the fat arrow (=>) syntax for the callback function; it binds the function's context to the current value of this. (this in the callback function is always the same this as the one at the time you defined the function.)

Solution 2 - Javascript

You say

> Using something like _this = this outside the .each function and passing it around isn't a great solution, either, since I reference many class variables inside processRow.

This is the most efficient solution, though. JavaScript's this is a strange beast; you can keep it fixed inside of a nested function using the => operator, as arnaud576875 sugests in his answer (which is elegant but inefficient), or you can copy this to another variable (which is efficient but inelegant). The choice is yours.

Note that some modern browsers support a bind method on every function, which is more efficient than CoffeeScript's =>. There's an open ticket to have => use the native bind when available: https://github.com/jashkenas/coffee-script/pull/1408

Addendum: Of course, a more efficient alternative than any of the above would be to write

for element, index in $('#my-table>tr')
  ...

which would also solve your this problem.

Solution 3 - Javascript

Your code...

class foo
    @bar = 'bob loblaw'

    processRows: ->
        $("#my-table>tr").each ->
            id = $(this).attr("id")
            @processRow id

    processRow: (id) ->
        console.log @bar + id

Is transpiled to...

var foo;
foo = (function() {
  function foo() {}
  foo.bar = 'bob loblaw';
  foo.prototype.processRows = function() {
    return $("#my-table>tr").each(function() {
      var id;
      id = $(this).attr("id");
      return this.processRow(id);
    });
  };
  foo.prototype.processRow = function(id) {
    return console.log(this.bar + id);
  };
  return foo;
})();

Which has assumed much about about the current context that it is translating to. Unfortunately, since jQuery manages context, you'll have to be explicit or declare a reference to your class's this.

Incidentally, there are other issues with that generated code, take a look at this reduced case:

class foo
    @bar = 'bob loblaw'
    
    getBar: () ->
        @bar

Transpiles to:

var foo;
foo = (function() {
  function foo() {}
  foo.bar = 'bob loblaw';
  foo.prototype.getBar = function() {
    return this.bar;
  };
  return foo;
})();

The results of attempting to use this piece of code:

> foo.bar;
"bob loblaw"
    
> var f = new foo();
undefined

> f.getBar();
undefined

Your code seems to expect that @bar is an own property, but it's being created as a static property of the foo function

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser524276View Question on Stackoverflow
Solution 1 - JavascriptArnaud Le BlancView Answer on Stackoverflow
Solution 2 - JavascriptTrevor BurnhamView Answer on Stackoverflow
Solution 3 - JavascriptRickView Answer on Stackoverflow