Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

KnockoutJS, updating ViewModel after ajax call

I am using Knockout and the Knockout Mapping plugin.

  • My MVC3 Action returns a View and not JSON directly as such I convert my Model into JSON.
  • This is a data entry form and due to the nature of the system validation is all done in the Service Layer, with warnings returned in a Response object within the ViewModel.
  • The initial bindings and updates work correctly its the "post-update" behavior that is causing me a problem.

My problem is after calling the AJAX POST and and receiving my JSON response knockout is not updating all of my bindings... as if the observable/mappings have dropped off

If I include an additional ko.applyBindings(viewModel); in the success things do work... however issues then arise with multiple bindings and am certain this is not the correct solution.

This is the HTML/Template/Bindings

<!-- Start Form -->
<form action="@Url.Action("Edit")" data-bind="submit: save">
<div id="editListing" data-bind="template: 'editListingTemplate'"></div>
<div id="saveListing" class="end-actions">
    <button type="submit">Save Listings</button>
</div>
</form>
<!-- End Form -->

<!-- Templates -->
<script type="text/html" id="editListingTemplate">
        <div class="warning message error" data-bind="visible: Response.HasWarning">
            <span>Correct the Following to Save</span>
            <ul>
                {{each(i, warning) Response.BusinessWarnings}}
                    <li data-bind="text: Message"></li>
                {{/each}}
            </ul>
        </div>

        <fieldset>
            <legend>Key Information</legend>
            <div class="editor-label">
                <label>Project Name</label>
            </div>
            <div class="editor-field">
                <input data-bind="value: Project_Name" class="title" />
            </div>            
        </fieldset>        
</script>
<!-- End templates -->

And this is the Knockout/Script

<script type="text/javascript">
        @{ var jsonData = new HtmlString(new JavaScriptSerializer().Serialize(Model)); }

        var initialData = @jsonData;
        var viewModel = ko.mapping.fromJS(initialData);


        viewModel.save = function () 
        {
            this.Response = null;
            var data = ko.toJSON(this);
            $.ajax({
                url: '@Url.Action("Edit")',
                contentType: 'application/json',
                type: "POST",
                data: data,
                dataType: 'json',
                success: function (result) {
                ko.mapping.updateFromJS(viewModel, result);
            }
        });
    }

    $(function() {                        
        ko.applyBindings(viewModel);            
    });
</script>

And this is the response JSON returned from the successful request including validation messages.

{
    "Id": 440,
    "Project_Name": "", 
    "Response": {
        "HasWarning": true,
        "BusinessWarnings": [
            {
                "ExceptionType": 2,
                "Message": "Project is invalid."
            }, {
                "ExceptionType": 1,
                "Message": "Project_Name may not be null"
            }
        ]
    }   
}

UPDATE

Fiddler Demo Is a trimmed live example of what I am experiencing. I have the Project_Name updating with the returned JSON but the viewModel.Response object and properties are not being updated through their data bindings. Specifically Response.HasWarning().

I've changed back to ko.mapping.updateFromJS because in my controller I am specifically returning Json(viewModel).

Cleaned up my initial code/question to match the demo.

like image 391
Galen Avatar asked Dec 25 '10 02:12

Galen


2 Answers

I guess Response is reserved, when I change "Response" to "resp", everything went fine. See http://jsfiddle.net/BBzVm/

like image 158
Gelin Luo Avatar answered Oct 21 '22 23:10

Gelin Luo


Should't you use ko.mapping.updateFromJSON on your success event? Chapter Working with JSON strings on Knockout Mapping site says:

If your Ajax call returns a JSON string (and does not deserialize it into a JavaScript object), then you can use the functions ko.mapping.fromJSON and ko.mapping.updateFromJSON to create and update your view model instead.

like image 42
Bcelik Avatar answered Oct 21 '22 23:10

Bcelik