Mr Grok
Mr Grok

Reputation: 3956

knockout.js binding update issue

Simple example below that re-orders fields on a form. Everytime you hit the "Top" button next to a row it should move it to the top of the list. The buttons seem to act in a few odd ways but I'll describe one for the sake of argument. Starting at the bottom click each button. You'll find that the console.log indicates that the field.order is always one but the UI doesn't quite match by the time you get to the last two; they remain as "10" and "20" in the textbox which is wrong but their order is still switched correctly.

Is this a ko bug or have I missed something?

Note:You should be able to copy and paste the code direct into an html file and run it.

<html>
<head>
<script src="http://knockoutjs.com/js/knockout-2.0.0.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
    function Field(name, order)
    {
        this.name = name;
        this.order = order;
    }

    function Form() {
        this.name = ko.observable("Test");
        this.fields = ko.observableArray();

        this.fields.push(new Field("field a", 10));
        this.fields.push(new Field("field b", 20));
        this.fields.push(new Field("field c", 30));
        this.fields.push(new Field("field d", 40));
        this.fields.push(new Field("field e", 50));
        this.fields.push(new Field("field f", 60));
    }

    function AppViewModel() {
        var self = this;
        self.selectedForm = ko.observable(new Form());

        reorderItems = function () {
            self.selectedForm().fields.sort(
            function (left, right) {
                return (left.order == right.order)
                    ? 0 : ((left.order < right.order) ? -1 : 1)
            });
        }

        fieldMove = function (field) {
            // find field in parent
            var fldIdx = self.selectedForm().fields().indexOf(field);

            field.order = 1;
            console.log(field.order);
            field.name = field.name + field.order;

            // re-order the items
            reorderItems();
        }
    }

    $(document).ready(function () {
        // Activates knockout.js
        ko.applyBindings(new AppViewModel());
    });
</script>
</head>
<body>
    <div class="form" data-bind="with: selectedForm">
    <!-- ko foreach: fields -->
    <div class="field">
        <span data-bind="html: name"></span>
        <input data-bind="value: order"></input>
        <button data-bind="click: fieldMove">Top</button>
    </div>
    <!-- /ko -->
</div>
</body>

Upvotes: 0

Views: 1426

Answers (1)

Steve Greatrex
Steve Greatrex

Reputation: 15999

I'm not sure exactly why you were having problems, but I managed to get this working by replacing the standard properties of name and order with observable properties.

This working fiddle demonstrates the solution

Upvotes: 2

Related Questions