1

i have a model like this

function ViewModel(){
    var self = this

    self.Choices            =   ko.observableArray([])
    self.AcceptedChoices    =   ko.observableArray([])

    self.LoadData   =   function(){
        self.ViewAnswered()
    }   

    self.ViewAnswered = function(){
        var url =   'QuestionsApi/ViewAnswered'
        var type    =   'GET'
        ajax(url , null , self.OnViewAnsweredComplete, type )                   
    }
    self.OnViewAnsweredComplete = function(data){
        var currentAnswer = data.Answer

        self.Choices(currentAnswer.Choices)
        self.AcceptedChoices(currentAnswer.AcceptedChoices)
    }       

    self.LoadData()         
}

Here is my object. I have removed extra things

{
    "AcceptedChoices": [94, 95],
    "Choices": [{
        "ChoiceId": 93,
        "ChoiceText": "Never"
    }, {
        "ChoiceId": 94,
        "ChoiceText": "Sometimes"
    }, {
        "ChoiceId": 95,
        "ChoiceText": "Always"
    }]
}

And here is binding

<u data-bind="foreach:Choices">
    <li>
        <input type="checkbox" name="choice[]" data-bind="value:ChoiceId,checked:$root.AcceptedChoices">
        <span data-bind="text:ChoiceText">Never</span>
    </li>
</u>

Now the problem is that checkboxes are not being checked due to the choices being array of objects. How can i resolve this issue? Although the same thing works for radio where there is only one selection.

2 Answers 2

2

Never mind i have found a solution here

checked binding does not properly compare primatives

Also it tells two ways for this. The Solution provided in fiddle is creepy so i will use the one using knockout version 3.0.0.

All i need to do is attach knockout-3.0.0.js instead of any other and then use checkedValue instead of value.

<input type="checkbox" name="choice[]" 
    data-bind="
            checkedValue:ChoiceId,
            checked:$root.AcceptedChoices"
>

And that's done. Hope it helps someone.

EDITS :

I noticed it is not working on the Chrome. So i found an alternative. I created these two functions.

self.ConvertToString = function(accepted){
    var AcceptedChoices =   []
    ko.utils.arrayForEach(accepted, function(item) {
        AcceptedChoices.push(item.toString())
    })  
    return  AcceptedChoices
}
self.ConvertToInteger = function(accepted){
    var AcceptedChoices =   []
    ko.utils.arrayForEach(accepted, function(item) {
        AcceptedChoices.push(parseInt(item))
    })  
    return  AcceptedChoices         
}

And use them

self.AcceptedChoices(self.ConvertToString(currentAnswer.AcceptedChoices))

To get the value

AcceptedChoices: self.ConvertToInteger(self.AcceptedChoices()),
Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, that's why I ended up doing it the way I put in my answer. Good to know it's finally fixed in 3.0!
0

You need to be checking to see if the Id of a choice is in the AcceptedChoices array. Use the ko.utils array function to help do that:

checked: function() { return ko.utils.arrayFirst($root.acceptedChoices(), function(item){
    return item == ChoiceId();
} !== null }

You could put this into a function on your root object:

self.isChoiceAccepted = function(choiceId){
    return ko.utils.arrayFirst($root.acceptedChoices(), function(item){
        return item == choiceId;
    } !== null
};

then call it in your data-bind as:

checked: function() { return $root.isChoiceAccepted(ChoiceId()); }

This isn't tested, I'm not 100% sure that the arrayFirst method returns null if it doesn't find a matching item in the array, so chack that.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.