Ad

Managing "this" Context When Creating Multiple Instances Of Objects At Once Based On DOM Elements

- 1 answer

I'm trying to write more structured / object-oriented JS, as opposed to my old trusted "jQuery spaghetti" approach. Below I have a bit of JS to create multiple widgets on a page, and each widget has a "close" and "favorite" button.

My question is twofold:

1) Let's say we have 10-20 items/widgets on the page/dom (with a class of "item") that we want to apply JS functionality to. Is there a better way of creating a new instance of our "Item" class for each element than how I'm doing this at the very bottom of the code below?

2) Is there another way of accessing an object's properties and methods while inside a method? For example, something like "this.methodName" works in some instances, but in other instances the context of "this" will not be the object, so I'm not sure how to access things.

You'll see in my "events" method I use ".bind(this)" to alter the context of "this" so I can access object properties once I'm in the "close" or "favorite" methods. I'm thinking this use of "bind" isn't the best approach here - is there a more consistent / clean way of accessing object properties & methods without micromanaging "this" context?

var Item = function(el) {
    // define variables we will need
    this.elem = el;
    this.closeButton = el.find(".close");
    this.favoriteButton = el.find(".favorite");

  // run ui event listeners when instance is created
    this.events();
};

// ui event listeners - call appropriate method
Item.prototype.events = function() {
    this.closeButton.on("click", this.close.bind(this));
    this.favoriteButton.on("click", this.favorite.bind(this));
};

// close method
Item.prototype.close = function() {
    this.elem.remove();
};

// favorite method
Item.prototype.favorite = function() {
    this.favoriteButton.remove();
    this.elem.append("Favorited!")
};

/* all elements with a class of item should
 receive our Item class features */
$(".item").each(function() {
    new Item($(this));
});

Basically, I'm wondering how to write well structured OO JS while interacting with multiple DOM elements. I've seen a lot of great "module pattern" guides online but a lot of these follow the "singleton" approach. Or I might just be misunderstanding everything :)

Any help is appreciated!

Not sure if this is helpful or not: but here is a JSFiddle of this example - I know we shouldn't rely on JSFiddle links for questions or answers because they aren't useful for SO archiving purposes, but I have the JS above for reference, hopefully this fiddle is just a bonus help.

Ad

Answer

My thoughts

  1. At the end of the day you have to register event handlers to dom elements so I think creating a new object for everything in your model is a good solution. Your code is clear which event handlers are registered for which parent item.

  2. The way this is resolved at runtime is covered really well in this S.O. question. Basically the jquery event handling mechanism is ultimately what is calling the handler you are associating and therefore it has a lot of control over what the this keyword is. However you can hand the handler a function that you bind the this arg explicitly. You are already doing this in your example and it shouldn't let you down. I would be interested in seeing an example where this doesn't work.


var obj = {x: 'hello world'};
$('#btn').on('click', (function () {
    console.log(this.x);
}).bind(obj));
Ad
source: stackoverflow.com
Ad