简体   繁体   English

为什么这个jQuery .change事件在.click事件之后停止工作

[英]Why does this jQuery .change event stop working after .click event

I have a script that displays questions from an array and switches from one question to the next using the .click event on two buttons: previous and next. 我有一个脚本显示数组中的问题,并使用两个按钮上的.click事件从一个问题切换到下一个问题:上一个和下一个。 When I load the page the $(":radio").change selector works fine, but when I click on previous or next it stops working. 当我加载页面$(":radio").change选择器工作正常,但当我点击上一个或下一个它停止工作。

I tried changing the $("#previous) to a console.log to see if .click was the culprit and it seems to be working. I assume there is something wrong with my display function but I can't seem to figure out why. 我尝试将$("#previous)更改为console.log以查看.click是否是罪魁祸首,它似乎正在工作。我认为我的显示功能有问题,但我似乎无法弄清楚为什么。

Here is the jsFiddle . 这是jsFiddle And here is the project on GitHub 这是GitHub上的项目

Questions Array 问题数组

var quizQuestions =
[{
    question: "1. Who is Prime Minister of the United Kingdom?",
    choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
    correctAnswer:0
},
{
    question: "2. Who is Prime Minister of the United Kingdom?",
    choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
    correctAnswer:2
},
{
    question: "3. Who is Prime Minister of the United Kingdom?",
    choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
    correctAnswer:1
}];

JavaScript Code (jQuery) JavaScript代码(jQuery)

$(document).ready(function(){
    var all = quizQuestions,
        q = $("#question"),
        c = $("#choices"),
        ans = [],
        current = 0;

    display(current);

    function display (id) {
        var question = all[id].question;
        var choices = all[id].choices;

        q.html(question);
        c.html(function(){
            var output = "<form>";
            for (var i = 0; i < choices.length; i++) {
                output += "<input type='radio' name='question" +id
                + "' value='" + choices[i] + "'> "
                + choices[i] + "<br>";
            };
            output += "</form>"
            // console.log(output);
            return output;
        });
    };

    function changeDisplay (dir) {
        if (dir == 'next' && current < all.length-1) current++;
        if (dir == 'prev' && current > 0) current--;
        display(current);
    }

    function answerQ (q, a) {
        ans[q] = a;
        console.log(ans);
    }

    $(":radio").change(function(){
        answerQ( $(this)[0].name, $(this).val() );
    });

    $("#previous").click(function (){ changeDisplay('prev'); });
    $("#next").click(function (){ changeDisplay('next'); });

    // console.log("all.length: " + all.length + " | ans: " + ans + " | current: " + current);
});

This is most likely because the event is not delegated. 这很可能是因为事件未被委派。 When the page is loaded you bind the click events. 加载页面时,您绑定单击事件。 But as the dom is manipulated (elements removed) the events are deleted. 但是当操作dom(删除元素)时,事件将被删除。 You would have to use a delegate for this. 您必须为此使用委托

Like this: 像这样:

$('.container').on('change', ':radio', function(){
    answerQ( $(this)[0].name, $(this).val() );
});

Edit: I would suggest that you save or hide the answers instead of overwriting them. 编辑:我建议你保存或隐藏答案而不是覆盖它们。 That would make it easier to implement the previous function. 这样可以更容易地实现以前的功能。

It looks like when you move to the next set of questions you replace the HTML on the page for each radio button. 看起来当您转到下一组问题时,您将替换每个单选按钮的页面上的HTML。 However you never assign click handlers to the new radio buttons. 但是,您永远不会将点击处理程序分配给新的单选按钮。 You do this initially to all radio buttons when the page is loaded, but after you change the display you don't reapply the click handler to the radio buttons. 最初在加载页面时对所有单选按钮执行此操作,但在更改显示后,不会将单击处理程序重新应用于单选按钮。

In your document.ready handler you have this near the bottom: 在你的document.ready处理程序中,你有这个接近底部:

    $(":radio").change(function(){
        answerQ( $(this)[0].name, $(this).val() );
    });

But in the display function (called when you choose previous or next) you have this: 但是在显示功能(当你选择上一个或下一个时调用)你有这个:

        c.html(function(){
            var output = "<form>";
            for (var i = 0; i < choices.length; i++) {
                output += "<input type='radio' name='question" +id
                + "' value='" + choices[i] + "'> "
                + choices[i] + "<br>";
            };
            output += "</form>"
            // console.log(output);
            return output;
        });

Which doesn't add a click handler to any of the new input options. 这不会为任何新的输入选项添加点击处理程序。

Here's the problem, when you directly add listeners like ".click()" or ".change()", etc, to an element, you're only setting the listener for that object specifically. 这是问题所在,当您直接将“.click()”或“.change()”等侦听器添加到元素时,您只是专门为该对象设置侦听器。 To create a listener that applies to all elements currently on the page, and also any future elements created through dynamic means (ajax, new elements added via javascript after page load completes) you should set a document level "on" function: 要创建一个适用于当前页面上所有元素的侦听器,以及通过动态方式创建的任何未来元素(ajax,在页面加载完成后通过javascript添加的新元素),您应该设置document级别“on”函数:

Change what you have here: 改变你在这里的内容:

$(":radio").change(function(){
    answerQ( $(this)[0].name, $(this).val() );
});

to this: 对此:

$(document).on("change", ":radio", function(){
    answerQ($(this).name, $(this).val());
});

(I don't think the [0] on $(this) means anything, because at that moment it would only apply to the element that was just changed anyway). (我不认为$(this)上的[0]意味着什么,因为在那一刻它只适用于刚刚改变的元素)。

Hope that helps! 希望有所帮助!

Here's a link for futher reading on the subject: http://api.jquery.com/on/ 以下是关于该主题的更多阅读链接: http//api.jquery.com/on/

I would move the display function out of the callback method for the $(document).ready() event. 我会将显示功能移出$(document).ready()事件的回调方法。 IMHO, it belongs in the global space because it's being invoked by other functions in the global space. 恕我直言,它属于全球空间,因为它被全球空间中的其他功能调用。 It's just cleaner than relying on a Closure to keep a reference to an object hidden in an event handler. 它比依赖Closure来保持对隐藏在事件处理程序中的对象的引用更干净。

EDIT: I imagine the problem is the use of this, without stepping through the code. 编辑:我想问题是使用这个,而不是单步执行代码。 Would things change if you use pass in the event object in your handler .change(), and use that to get a reference to the element? 如果在处理程序.change()中使用事件对象中的pass,并使用它来获取对元素的引用,情况会发生变化吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM