How to access property on object in viewmodel from

2019-03-04 12:52发布

问题:

I hava a viewmodel as follow :

define(
    ['jquery', 'knockout', 'knockout.mapping', 'data/data', 'models/models'],
    function ($, ko, mapping, data, models) {
        var post =  {},

            getPost = function (param) {
                $.when(data.deferredRequest('postDetail', param.id))
                 .done(function (result) {
                     mapping.fromJS(result, {}, post);

                     console.log(result.title === post.title()); // ---> this is true
                     console.log(ko.isObservable(post.title));   // ---> this is true
                 });
            };

        return {
            post   : post,
            getPost: getPost
        };
    });

I want to show title property in the html as follow :

<section id="section-post-detail" class="view" >
    <div class="page-header">
        <h3 data-bind="text: post.title"></h3>    <!-- show nothing -->
        <h3 data-bind="text: post().title"></h3>  <!-- error -->
        <h3 data-bind="text: post.title()"></h3>  <!-- error -->
    </div>
</section>

I tried three ways to show title property, however all those are failed. Did I miss anything?


Edited

I tweaked source code as follow. I added title property on viewmodel and updated it inside the getPost and then I succesfully accessed the title property of the viewmodel, not title property on post model.

define(
        ['jquery', 'knockout', 'knockout.mapping', 'data/data', 'models/models'],
        function ($, ko, mapping, data, models) {
            var post =  {},
                title = ko.observable(''),     
                getPost = function (param) {
                    $.when(data.deferredRequest('postDetail', param.id))
                     .done(function (result) {
                         mapping.fromJS(result, {}, post);

                         title(post.title());                
                         console.log(result.title === post.title()); // ---> this is true
                         console.log(ko.isObservable(post.title));   // ---> this is true
                     });
                };

            return {
                post   : post,
                title  : title,
                getPost: getPost
            };
        });

<section id="section-post-detail" class="view" >
        <div class="page-header">
            <h3 data-bind="text: title"></h3>    
        </div>
    </section>

However, as you see data-bind="text: title" is not the title propery on post, but the title property on viewmodel. This is not what I want. I would like to acces title property on post object.

Please correct my approacth.

回答1:

I think the problem is that you are initially creating your viewmodel as an empty object, like this:

var post = {};

And then you are trying to update the viewmodel, like this:

mapping.fromJS(result, {}, post);

However, the documentation for the mapping plugin at http://knockoutjs.com/documentation/plugins-mapping.html seems to indicate that you should create the viewmodel like this:

var viewModel = ko.mapping.fromJS(data);
// or, in your case
var post = ko.mapping.fromJS(result);

Then, when you need to call the server to get updated data, you can do this:

ko.mapping.fromJS(data, viewModel);
// or, in your case
ko.mapping.fromJS(result, post);

The important thing to consider, which I think RP was driving at, is that you can't create the viewmodel until after you have the data.



回答2:

Not sure when that you are applying bindings, but it appears that at the time of binding, you are just binding against the empty object. Then, when your AJAX request finishes, it adds the observables, but since post itself isn't observable, the UI does not update.

You could consider calling applyBindings after your request finishes like:

var vm = {
    post: ko.observable()
};    

//simulate AJAX
setTimeout(function() {
    vm.post(ko.mapping.fromJS({ title: "hello" }));    
}, 500);

ko.applyBindings(vm);

Then bind against it like:

<section id="section-post-detail" class="view" >
    <div data-bind="with: post" class="page-header">
        <h3 data-bind="text: $data.title"></h3> 
    </div>
</section>​​​​​​​​​



标签: knockout.js