简体   繁体   中英

Why is observableArray not observable in Knockout JS?

I am new to programming (especially in JS and even more with KO) and I'm trying to come up with an interactive quiz destined to be used in class by high-school students. Thanks to this article (which provided the how-to and the code, which I used as a base, trying to readapt it to my needs) and some good people's help here, I have now come up with something that looks like this:

http://jsfiddle.net/sNJm3/2/

All is well because this is functional. But... :p I would now like to add an observableArray where I would push() all the selectedAnswer each time the user clicks one so that I could, at the end, compare selectedAnswers().length to questions().length and, if they are the same, I'd make a (not included in the code yet) visible.

I declared my array in the QuizViewModel constructor like so (as it concerns the whole quiz, so I think that's where it should go):

var selectedAnswers = ko.observableArray();

And then I need, each time, to push the selectedAnswer property from the Question constructor into it. And that's where the rub is... Here's the part of my script:

//Construction
$.each(quizName.controls, function(index, question) {
    quiz.questions.push(new Question(index + 1, question));
    quiz.selectedAnswers().push(question.selectedAnswer);
});

This does populate an array called selectedAnswers() but it is only populated with Undefineds, which 1) do not vary even when I click an answer (undefined is not replaced with clicked selectedAnswer...) and selectedAnswers().length is already equal to the total number of questions, which means the comparison I wanted to make will not work...

There must be some fundamental KO logic I'm not getting here (or is it JS logic, which definitely seems to be eluding me!) Any thoughts on the matter would be greatly appreciated!

Use a computed for your "selected answers" list.

function Question(config) {
    this.text = text;
    this.questionText = config.questionText;
    this.answers = config.answers;
    this.selectedAnswer = ko.observable();
}

function QuizViewModel(quizName) {
    this.questions = ko.observableArray(
        ko.utils.arrayMap(quizName.controls, function (control) {
            return new Question(control);
        })
    );
    this.selectedAnswers = ko.computed(function () {
        return ko.utils.arrayMap(this.questions(), function (q) {
            return q.selectedAnswer();
        }
    });
}

There is no need to maintain a separate stack (ie observable array) of answers when the answer already is a property of the question itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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