0

I'm new to using jQuery/javascript and am working on using the jsPlumb library to build some dynamic nodes, where the user can click on a shape and a new draggable node will appear.

My issue is I am building the list through a for loop, and the last element iterated over is being assigned to all other "clicks".

Here is the offending piece of code:

var sourceNodes = {
InputFiles:{
    cssClass:".data_source",
    name:"Input Files1",
    options:[{
        name:"Input Files1",
        connectsFrom:[],
        connectsTo:["IF1.1", "IF1.2"],
    },
    {
        name:"Input Files2",
        connectsFrom:[],
        connectsTo:["IF1.1"],
    }]
},
InputFiles2:{
    cssClass:".data_source",
    name:"Input2.1",
    options:[{
        name:"Input2.1",
        connectsFrom:["Input1"],
        connectsTo:["Input2.1"],
    },
    {
        name:"Input2.2",
        connectsFrom:["Input1"],
        connectsTo:["Input2.2"],
    }]
},
InputFiles3:{
    cssClass:".data_source",
    name:"Input3.1",
    options:[{
        name:"Input3.1",
        connectsFrom:["Input2"],
        connectsTo:["Input3.1"],
    }]
}
};

for( var m in sourceNodes ){
var sourceNode = sourceNodes[m];
var sourceClass = jsPlumb.getSelector(sourceNode.cssClass);
console.log(sourceClass);
sourceClass.bind("click", function(connection){
    var selectorClass = sourceNode.cssClass.concat("_window").substring(1);
    var toFind = "div[id^='".concat(selectorClass,"']");
    var DivIndex = $('#render').find(toFind).length+1;
    var DivName = selectorClass.concat(DivIndex);
    var Div = $('<div>', { id: DivName },
                 { class: selectorClass });
    Div.css({ 
        top: connection.clientY,
        left:  connection.clientX,
    });
    Div.appendTo('#render');
    Div.text(sourceNode.name);
    jsPlumb.draggable($(Div));
    $(Div).addClass(selectorClass);         
    _addEndpoints(DivName, ["BottomCenter"], ["TopCenter"]);
    var selectOption = $('<select>', { id: DivName });
    for( var n=0; n< sourceNode.options.length; n++){
        var option = $('<option>', { value: n,
        connectsTo: sourceNode.options[n].connectsTo,
        connectsFrom: sourceNode.options[n].connectsFrom });
        option.text(sourceNode.options[n].name);
        $(selectOption).append(option);
    }
    $(Div).append(selectOption);
 });
};

What happens is each item wihin sourceNodes that is clicked take on the values in InputFiles3, which is the last entry that is bound via sourceClass.bind. Any insight into what concept I am missing here, and how I can make each object within the loop independent?

3
  • also As of jQuery 1.7 .bind() is deprecated and should be replaced with .on() or .delegated() depending on your needs. see api.jquery.com/on for more info. Commented Oct 1, 2013 at 19:39
  • 2
    @chausser superseeded, not deprecated. There's no rush in removing it from existing code. And no, you should not be using delegate either. It was superseeded by on as well. Commented Oct 1, 2013 at 19:44
  • Good to know, .on() doesnt seem to bind to events added to the DOM after the page load but that is an issue for another question. Commented Oct 1, 2013 at 23:24

2 Answers 2

2

By the time the click happens, sourceNode is set to the last item in the list. One solution is to create a closure using an immediately-invoked function expression:

for (var m in sourceNodes) {
    (function (sourceNode) {
        ...        
    })(sourceNodes[m]);
};
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, glad I asked before fiddling around for another hour. I would have never figured this out.
0

Use $.proxy for passing the current source node as the first parameter to the click handler:

for( var m in sourceNodes ){
    var sourceNode = sourceNodes[m];
    var sourceClass = jsPlumb.getSelector(sourceNode.cssClass);
    console.log(sourceClass);

    sourceClass.bind("click", $.proxy(function(currentNode, connection){
        //currentNode is a reference to sourceNode[m] when
        //this click handler was registered
     }, null, sourceNode));
};

Comments

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.