CaptnKebec
CaptnKebec

Reputation: 31

Knockoutjs computed not updated from observableArray

I want a computed to be updated when an observable array is updated. The array is populated with questions and answer (Yes or No). When the user change the answer of a question, I want some region to be visible or not.

So the computed is5B should be true if one of the question is answered "oui" and this should make the sections visible.

The is5B computed is only calculated at initialization and is not fired when the array is updated (it is updated, I checked with a breakpoint)

Here's the view model:

var section5Model = ko.validatedObservable({
    Questions5A: ko.observableArray(GetQuestions('5A')),
    Questions5B: ko.observableArray(),
    Questions5C: ko.observableArray(),
    ContactAQ: ko.observable(),
    Date: ko.observable(''),
    Heure: ko.observable(''),
    CategorisePar: ko.observable(''),
    DateCategorise: ko.observable(''),
    RepOuiNon: [{ label: 'Oui', value: 0 }, { label: 'Non', value: 1 }]
});

section5Model().is5B = ko.computed(function () {
    this.Questions5A().forEach(function (item) {
        if (item.reponse == 'Oui') {
            return true;
        }
    });
}, section5Model());

Here's the markup:

<div id="sectionContainer">
    <div id='S5FormBlock1' class="formSection5">
        <div id="QSection5A" data-bind="foreach: Questions5A">
            <div class='mockTable'>
                <div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
                <div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
                    <input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
                </div>
            </div>
            <p />
        </div>
        <div data-bind="visible: is5B">Il s'agit d'une plainte qualité</div>
        <div id="QSection5B" data-bind="visible: is5B,foreach: Questions5B">
            <div class='mockTable'>
                <div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
                <div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
                    <input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
                </div>
            </div>
            <p />
        </div>
        <div data-bind="visible: is5C">Il s'agit d'une plainte d'insatisfaction</div>
        <div id="QSection5C" data-bind="visible: is5C,foreach: Questions5C">
            <div class='mockTable'>
                <div class="column200 centerLabel"><span data-bind="text: Texte"></span></div>
                <div class="grayRoundBorder padR10" data-bind="foreach: $parent.RepOuiNon">
                    <input type="radio" data-bind="value: label, attr : {name: $parent.ID}, checked: $parent.reponse" /><span data-bind="text: label"></span>
                </div>
            </div>
            <p />
        </div>
    </div>
</div>

Upvotes: 1

Views: 291

Answers (2)

Well Wisher
Well Wisher

Reputation: 1875

Computed are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change. so in your case no observable inside your computed function. so make at-least one variable in side computed as observable. in your case please make the item.response as observable. for that you need to return observable variable on GetQuestions('5A')

Please do Questions5A observableArray as like

 var section5Model = ko.validatedObservable({
        Questions5A: ko.observableArray([
                {reponse : ko.observable('reponse 1 ') },
                {reponse : ko.observable('reponse 2') },
                /* other objects */
        ]),      
        /* other code  */

Upvotes: 0

Sławomir Rosiek
Sławomir Rosiek

Reputation: 4073

The problem that you have is that item.response is not observable. So if it change KnockoutJS doesn't know about that. To fix this you have to change that to observable

section5Model().is5B = ko.computed(function () {
    this.Questions5A().forEach(function (item) {
        if (item.reponse() == 'Oui') {
            return true;
        }
    });
}, section5Model());

Upvotes: 2

Related Questions