jQuery / javaScript - click / onclick事件监听器尽管关闭但在循环内部无效

时间:2014-03-16 05:04:14

标签: javascript jquery loops closures event-listener

我和我的循环...... 我试图在几个for之间运行div循环,每个循环都在班级&​​#34; tooltipBox"但是使用不同的id s。在这些div中的每一个中都有一个带有" tttFalloutOrder"类的输入文本字段。我想在for循环中做的是在每个.tttFalloutOrder输入字段上附加一个click-event-listener。

到目前为止,这是我的代码:

function installListener(elementId) {
    $( "div#" + elementId + " > .tttFalloutOrder" ).on("click", function() {
        alert("clicked on " + elementId);
    });
}

function runSimulation() {
    alert("running simulation...");

    $( "#lContent h2" ).html("Simulation <b>in progress...</b>");

    var agents = $( "div.tooltipBox" );
    var rFOs = $( ".rFO" );

    var i, j = 0;

    for(i = 0, j = 0; i < agents.length, j < rFOs.length; i++, j++) {
        var ttl = rFOs[j].value;

        if((ttl == "undefined") || (ttl == "n")) {
            continue;
        } else {
            // function-factory als gscheite closure,
            // siehe http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
            // und http://stackoverflow.com/questions/3572480/please-explain-the-use-of-javascript-closures-in-loops?answertab=votes#tab-top
            (function(i, ttl) {
                var agentId = agents[i].id;

                installListener(agentId);

                /*
                $( "div#" + agentId + " > .tttFalloutOrder" ).on("change keypress paste focus textInput input", function() {
                    alert(agentId + "just got changed!");
                });
                */
                setTimeout(function() {
                    $("div#" + agentId + " > div.offlineCover").fadeIn(500);
                }, ttl*1000);
            })(i, ttl);
        }
    }
    $( "#lContent h2" ).html("Simulation <b>complete</b>");
}

正如你所看到的,我正在使用一个闭包,甚至委托将听众附加到另一个函数的实际任务,在阅读了几个与循环中的事件监听器相关的SO-answers后,这会有所帮助......虽然我老实说,不要太明白这会有什么不同。无论如何,点击听众仍然不会开火,坦率地说,我不明白这是什么 - 或者更确切地说是什么 - 发生在这里。

提前致谢 - 你们这些人总是找到一种方法来指出像我这样的不知名的灵魂正确的方向,我真的很感激。

更新 案件由于我自己的愚蠢而关闭...... 首先,是的,我有一个未定义的成员坐在我的installListener()函数中。 其次,jQuery选择器$( "div#" + elementId + " > .tttFalloutOrder" )返回undefined,因为>运算符选择第二个元素,第一个元素作为直接父元素。但是,由于.tttFalloutOrder是位于<form>标记内的输入字段,因此情况并非如此......

我现在废弃了函数installListener()并使用以下代码解决了问题:

function runSimulation() {
    alert("running simulation...");

    $( "#lContent h2" ).html("Simulation <b>in progress...</b>");

    var agents = $( "div.tooltipBox" );
    var rFOs = $( ".rFO" );

    var waitUntilEvaluate = 0;

    var i, j = 0;

    for(i = 0, j = 0; i < agents.length, j < rFOs.length; i++, j++) {
        var ttl = rFOs[j].value;

        if((ttl == "undefined") || (ttl == "n")) {
            continue;
        } else {
            // function-factory als gscheite closure,
            // siehe http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
            // und http://stackoverflow.com/questions/3572480/please-explain-the-use-of-javascript-closures-in-loops?answertab=votes#tab-top
            (function(i, ttl) {
                var agentId = agents[i].id;

                $( "div#" + agentId + " .tttFalloutOrder" ).on("input", function() {
                    alert(agentId + "just got changed!");
                    $( "div#" + agentId + " .wasChanged" ).prop("checked", true);
                });

                setTimeout(function() {
                    $("div#" + agentId + " > div.offlineCover").fadeIn(500);
                }, ttl*1000);

                waitUntilEvaluate = waitUntilEvaluate + ttl * 1000;
            })(i, ttl);
        }
    }

    console.log(waitUntilEvaluate);
    setTimeout(function() {
        $( "#lContent h2" ).html("Simulation <b>complete</b>");
        evaluate();
    }, waitUntilEvaluate);
}

1 个答案:

答案 0 :(得分:1)

您会发现使用jQuery.each()而不是for()循环更容易。 .each()回调函数会自动捕获所需的var,因此不需要再创建另一个内部闭包。

阻止点击处理程序工作的最可能的事情是listenerKind。如果不存在这样的成员,则将抛出错误并且事件线程将死亡。

您最大的问题是知道何时将“进行中”消息更改为“完成”。就目前而言,消息将立即更改回来,而无需等待任何setTimeout完成,更不用说所有这些了。

就个人而言,我会做这样的事情(见代码中的评论):

function runSimulation() {
    var $agents = $("div.tooltipBox"),
        $rFOs = $(".rFO"),
        $message = $("#lContent h2");
    if($agents.filter('.running').length > 0) {
        //Inhibit simulation if any part of an earlier simulation is still running.
        return;
    }
    $message.html("Simulation <b>in progress...</b>");
    $agents.each(function(i, agent) {
        var ttl, $agent;
        if(i >= $rFOs.length) {
            return false;//break out of .each()
        }
        ttl = Number($rFOs.eq(i).val());//Any failure to cast as Number will result in NaN.
        if(isNaN(ttl)) {
            return true;//continue with .each()
        }
        $agent = $(agent).addClass('running');//Provide a testable state (see below and above)
        $agent.children(".tttFalloutOrder").on('click.sim', function() {//Note: namespaced click event allows .off('click.sim') without affecting any other click handlers that might be attached.
            alert("click on " + $agent.attr('id'));
        });
        setTimeout(function() {
            $agent.children(".tttFalloutOrder").off('click.sim');//detach the handler attached with .on('click.sim') .
            $agent.removeClass('running').children(".offlineCover").fadeIn(500);
            if($agents.filter('.running').length == 0) {//if neither this nor any other agent is "running"
                $message.html("Simulation <b>complete</b>");//Signify complete when all parts are complete
            }
        }, ttl*1000);
    });
}

未测试

如果点击操作仍无效,我会怀疑$agent.children(".tttFalloutOrder")选择器不正确。

还有其他方法可以做这种事情,特别是利用Deferreds / promises和jQuery.when()的方法,但上面的代码(经过适当调试)应该足够了。