ReinaDelSur
ReinaDelSur

Reputation: 131

undefined binding in knockout.js

Being a beginner in developing JS apps, I am, for now, restricting myself to observing existing code and trying to reproduce it while fiddling with variable names (so I can see whether I've understood things properly).

This is what I've been doing with this JS quiz code written with KO.js... Here is "my" version (not many changes at all...)

http://jsfiddle.net/s6EsB/

My problem is that when I try to run the code, I get a "isCorrect is undefined" not in my script but in the KO library. When I comment the lines containing isCorrect in the HTML, I then get "correctNbrAnswers is undefined", still in the KO library...

It is like KO doesn't understand the data parameters I use in referring to the appropriate templates...

<script id="questionView" type="text/html">
        <div>Question <span data-bind="text: index"></span></div>
        <div data-bind="visible: selectedAnswer() === undefined">
            <div data-bind="text: questionText"></div>
            <ul data-bind="template: { name: 'answerView', foreach: answers }"></ul>
        </div>
        <div data-bind="visible: selectedAnswer() !== undefined">
            <div data-bind="template: { name: 'questionResultView', data: selectedAnswer }"></div> <!-- isCorrect id defined for answers, so if KO respects this scope, this should work... But it doesn't! -->
            <a href="#" data-bind="click: $parent.nextQuestion">Next</a>
        </div>
    </script>
    <script id="questionResultView" type="text/html">
        <div data-bind="visible: isCorrect">Bonne réponse !</div> <!-- Returns isCorrect is undefined (knockout.js line blablabla) -->
        <div data-bind="visible: !isCorrect">Non. La bonne réponse était <span data-bind="text: $parent.correctAnswer.answerText"></span></div>
    </script>

I'd love it if anyone could shed some light on the matter...

Thank you!

Ari ;o)

Upvotes: 1

Views: 1996

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134811

The problem is that the selectedAnswer may or may not be undefined. And that's fine usually, however the logic in your view is a bit flawed.

<script id="questionView" type="text/html">
    <div data-bind="visible: selectedAnswer() === undefined">
        <!-- _visible_ if selectedAnswer is undefined -->
    </div>
    <div data-bind="visible: selectedAnswer() !== undefined">
        <!-- _not visible_ if selectedAnswer is undefined -->
        <div data-bind="template: { name: 'questionResultView', data: selectedAnswer }"></div>
    </div>
</script>

Take note of the comments I've added.

The first div is visible when the selectedAnswer is undefined. Meaning the body of the div is still evaluated, only the results are not made visible.

The second div is not visible when the selectedAnswer is undefined. The body is still evaluated. Since the template uses the selectedAnswer, it is attempting to render an undefined object. You'll need to prevent the body of the second div from being evaluated when selectedAnswer is undefined.


There are a number of ways you can accomplish this but we'll stick to the easiest.

Change the visible binding on the second div to an if binding. Refer to the documentation for more information. Basically it is a lot like the visible binding except it doesn't evaluate the body if the condition is not truthy, exactly what we want.

Upvotes: 1

Related Questions