1

I am building a small app which is part of a sales-enquiry process. It has 'pages' which the visitor progresses through. I have laid out these pages as part of a large object literal. In the following code, branch-select is one of those pages. As you can see, the init() function sets a sibling value by using this to refer to the parent branch-select. However, the save() function is called from a click event, so instead of using this, it seems I have to laboriously write out the full object reference each time to set values? Please see the code & comments below to illustrate the problem:

    // This is part of a larger object called "stepData"

        "previous page": {
            // ...
        }
        "branch-select": {
            ref: "Select Type",
            visited: false, 
            init: function(){
                this.visited = true;  // Here I can use "this" to set other values in the parent object
                // ....
            },
            next: "",
            save: function(){
                branchKey = $(this).attr('data-value');   // this function is invoked from a click event, so "this" refers to the DOM element that was clicked. Therefore throughout the rest of the function if I want to set values on the parent object, I have to write out the full object reference each time...
                switch(branchKey){
                    case "Lodges":
                        stepData['branch-select'].ref = "Lodges";
                        stepData['branch-select'].values[0].a = "Lodges";
                        stepData['branch-select'].next = "lodge-2";     // Do I really have to write out stepData['branch-select'] each time?
                        break;
                    case "Caravans":
                        stepData['branch-select'].ref = "Caravans";
                        stepData['branch-select'].values[0].a = "Caravans";
                        stepData['branch-select'].next = "van-2";
                        break;
                }
                stepData[stepData['branch-select'].next].init();
            }
        },
        "next page": {
            // ...
        }

In the interests of DRY (Don't repeat yourself) code, I was wondering if there is any neat solution to this?

EDIT:

Webkit's answer presents a new problem; the clicked DOM element (.branch-select) is dynamically introduced, so to bind the click event, I have to use:

    $("#template-holder").on('click', ".branch-select", stepData['branch-select'].save);

(template-holder is the parent element which is always present). How would I integrate the call() method into the above code?

Inigo
  • 6,604
  • 15
  • 52
  • 94
  • how you bind `save` function to onclick? – Grundy Sep 14 '14 at 13:01
  • why don't you just use a reference variable to your object.. as in > var stepData = function() { var _ref = this; ........ } – webkit Sep 14 '14 at 13:12
  • @Grundy: By calling `$("#template-holder").on('click', ".branch-select", stepData['branch-select'].save);` – Inigo Sep 14 '14 at 13:14
  • @Webkit: OK, so I should turn stepData into a function? At the moment, it's a collection of child objects, ie. `stepData = { ... }` (Sorry if terminology is incorrect, I'm still relatively new to this) – Inigo Sep 14 '14 at 13:15
  • 1
    See this answer to understand how `this` works in javascript: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman Sep 14 '14 at 14:18
  • Great link, @Slebetman, thank you. – Inigo Sep 14 '14 at 14:33

1 Answers1

0

Another way to have "this" reference your object when handling an event is using 'call'.

for example:

var setData = {
    save: function(){
        // 'this' shall be setData!
        var _bs = this['branch-select'];

        _bs.ref = "Lodges"...
    }
}

then:

$(".someElement").on('click', function() {
    setData.save.call(setData)
});

**updated (I'm pretty sure this should work just the same):

$("#template-holder").on('click', ".branch-select", function() {
    stepData['branch-select'].save.call(setData)
});
webkit
  • 3,251
  • 1
  • 12
  • 17
  • Thanks. But surely _bs is then just a copy of branch-select, so using `_bs.ref = "Lodges"` would only be updating the _bs variable? – Inigo Sep 14 '14 at 13:45
  • No, _bs would be a reference to branch-select, if you update it, your object will be updated. – webkit Sep 14 '14 at 13:49
  • Oh OK. Right this is looking good.. however, this actually presents another small problem, perhaps you can help...? see edit ^ Thank you! – Inigo Sep 14 '14 at 13:55
  • sure, I don't think that would be any different.. see above edit – webkit Sep 14 '14 at 13:59
  • OK, awesome. I think you've got this. The only other thing (which you can see in the OP) is that I also need to get the data-value attribute of the clicked element, but I guess I can just pass that as the second parameter of the call() function (reading [call documention](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) at the moment)? Thanks for your help! – Inigo Sep 14 '14 at 14:06
  • Note that using call in this case is completely unnecessary. This always resolves to the thing before the last dot (or square bracket if the object is accessed using that notation). Therefore there is never a case where `setData.save()` will be called where `this` is not `setData`. If you assign `save` to some other variable or to another object where there is either no dot (or square bracket) in the function call or the the object before the last dot is not `setData` then you need to use `call()`. Which is not the case here. – slebetman Sep 14 '14 at 14:17
  • @slebetman lol, true.. but also, in this case there are square brackets, so the 'this' would reference that.. in the function itself there's a reference to the parent object.. so if you'd like the 'this' to be the parent object.. what would you do? – webkit Sep 14 '14 at 14:25