Updating view model from object not working

2019-05-31 09:48发布

问题:

I want to be able to observe an object inside the view model. I have a simple example that doesn't work as expected, can anyone see the problem?

Using knockout 1.1.1, have 2 inputs as such:

<form data-bind="submit: save">
    <input type="text" data-bind="value: deckName" />
    <input type="text" data-bind="value: deck().Name" />
    <button type="submit">Go</button>
</form>

When the page loads, the inputs get the default values, but on submitting the form viewModel.deck().Name is not updated but viewModel.deckName is.

<script type="text/javascript">
    var initialData = {"Name":"test"};

    var viewModel = {
        deck: ko.observable(initialData),
        deckName: initialData.Name,
        save: function() {
            ko.utils.postJson(location.href, { deck: this.deck, deckName: this.deckName });
        }
    };
    ko.applyBindings(viewModel);
</script>

On the form POST, deck will still send "test" no matter the input whilst deckName will be the corresponding input value.

What I really want is to be able to observe an object viewModel.deck and then bind its properties to inputs, but the properties don't get updated.

回答1:

There are several problems with what you have provided.

  1. You've only set up a one time value setter for your second input since deck().Name is a static value (as opposed to a ko.observable or a ko.observableArray). (To prove this add viewModel.deck({"Name":"updated test"}); to the end of your script after ko.applyBindings(viewModel);)
  2. deckName is a one way binding - it's written during the initial applyBindings and viewModel will be updated by changes made by the user or scripts to the <input>. However, if you make programmatic changes to the viewModel your input field will not be updated to match. You'll want to take a look at the last part of Knockout.js' value binding documentation.

A slightly improved version:

<form data-bind="submit: save">
    <input type="text" data-bind="value: deckName" />
    <input type="text" data-bind="value: deck().Name" />
    <button type="submit">Go</button>
</form>
<script type="text/javascript">
    var initialData = {"Name":"test"};

    var viewModel = {
        deck: ko.observable(initialData),
        // Set up a two way binding
        deckName: ko.observable(initialData.Name),
        // Set up a one time value setter
        save: function() {
            ko.utils.postJson(location.href, ko.toJSON(this));
            // When we save the model we post *it* back, rather than
            // serializing it by hand.
        }
    };
    ko.applyBindings(viewModel);
    viewModel.deck({"Name":"updated test"});
</script>

An alternate version using fromJS:

<form data-bind="submit: save">
    <input type="text" data-bind="value: Name" />
    <button type="submit">Go</button>
</form>
<script type="text/javascript">
    var initialData = {"Name":"test"};

    var viewModel = ko.mapping.fromJS(initialData);
    viewModel.save = function() {
        ko.utils.postJson(location.href, ko.toJSON(this));
        // When we save the model we post *it* back, rather than
        // serializing it by hand.
    }
    ko.applyBindings(viewModel);
</script>

You'll want to look at Knockout's fromJSON and fromJS funcitons (implemented in its mapping plugin).



标签: knockout.js