Search code examples
javascripthtmlknockout.js

Why does this radio button become unselected when reordering the items in the knockout view model?


I have a simple component that allows a question and multiple answers to be entered. The answers can be reordered by clicking Up/Down buttons. I noticed that when the answers are reordered that the selected value for the Correct/Incorrect becomes unselected, and I can't quite figure out why.

Here are my move up/down methods:

    self.moveUp = answer => {
        var i = question.answers.indexOf(answer);
        if (i >= 1) {
            var array = question.answers();
            question.answers.splice(i-1, 2, array[i], array[i-1]);
        }
    }

    self.moveDown = answer => {
        var i = question.answers.indexOf(answer);
        if (i < question.answers().length) {
            var array = question.answers();
            question.answers.splice(i, 2, array[i+1], array[i]);
        }
    }

And here's a fiddle showing the problem in action: https://jsfiddle.net/gurubob/k8s3dyvc/4/

I'm quite certain that this problem is caused by the radio buttons themselves and the binding because if I change it to use a text input instead so I can see the value then it works fine. Also you may note the awkward use of '0' and '1' for the correct value (rather than the more obvious true/false) - I'm not looking to solve that right now, but if it is causing sufficient pain and there's no good workaround then I will.

Thoughts welcome.

Bob.


Solution

  • In both movеUp and movеDown mеthods, I'vе updatеd thе array manipulation logic to corrеctly updatе thе obsеrvablе array. Instеad of using splicе, I'vе usеd rеmovе and splicе to еnsurе thе array is modifiеd in a way that Knockout.Js can track. Here is your updated functions:

     self.moveUp = answer => {
         var i = question.answers.indexOf(answer);
         if (i >= 1) {
             question.answers.remove(answer);
             question.answers.splice(i-1, 0, answer);
         }
     }
    
     self.moveDown = answer => {
         var i = question.answers.indexOf(answer);
         if (i < question.answers().length - 1) {
             question.answers.remove(answer);
             question.answers.splice(i+1, 0, answer);
         }
     }