Knockout JS mapping plugin without initial data / empty form

最后都变了- 提交于 2019-11-27 12:10:15

A couple of options for you besides just manually managing your view model. The mapping plugin supports a create callback that lets you customize how it gets created. This can be used to add default properties to an object, if they happen to be missing.

Something like this: http://jsfiddle.net/rniemeyer/WQGVC/

Another alternative is to use a binding that creates properties that are missing. It might look like:

//create an observable if it does not exist and populate it with the input's value
ko.bindingHandlers.valueWithInit = {
    init: function(element, valueAccessor, allBindingsAccessor, data) {
        var property = valueAccessor(),
            value = element.value;

        //create the observable, if it doesn't exist 
        if (!ko.isWriteableObservable(data[property])) {
            data[property] = ko.observable();
        }

        //populate the observable with the element's value (could be optional)
        data[property](value);

        ko.applyBindingsToNode(element, { value: data[property] });
    }
}

You would use it like this (need to pass the property as a string, otherwise it will error):

<input data-bind="valueWithInit: 'name'" />

Sample here: http://jsfiddle.net/rniemeyer/JPYLp/

I think the solution to you problem comes from thinking about the view model in the wrong way. A view model isn't only something that delivers data to the view, but also a place holder for submitting the data back.

The way i usually end up working with knockout, i never end up sending an empty view model to the view. The view model usually has all the fields i am binding on. While they might be empty strings, or initialized objects with no display values, the actual objects to still exits, with a proper representation of each object to the fields i am binding to.

You might want to look into simply sending empty objects instead of nothing to the view.

EDIT: The example is un ASP.NET MVC

So basiclaly, i on the server side, i create an view model object, which contains all the data that needs to be displayed as well as all the data that needs to be collected. For easier validation code i generally put the data to be collected into it's own subclass, but that all a matter of the needs of your code.

In anycase, the any object going to the view inherts from a vmBase class which basically provides a toJSON() method which generates the JSON serialization of the object. This gets called in my view by the view engine. As shown in the code below.

      <script type='text/javascript'>         
        var viewModel = ko.mapping.fromJS(<%= Model.ToJson() %>);                     

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

When i am ready to send the code back up, i simply remove pull a JS version of the view model.

<script type='text/javascript'>
     var dataToSendToServer = ko.toJS(viewModel);
</script>

In some sanarios, where only a part of the view model is changing (this is if you are doing AJAX updates), you can do some cool stuff like, switching templates so that different binding can be applyed. In this case we are using a #ID_of_Container as container of the original data/template and replacing the template (which can contain data-bind="" elements) a new template ID_of_Template

<script type='text/javascript'>
    ko.cleanNode($("#ID_of_Container"));
    delete (viewModel.Some_Element_To_Be_Updated);
    viewModel = ko.mapping.updateFromJS(viewModel, New_Data_For_That_Element);

    // Use ko.toJS(viewModel) because standard template plugin doesn't understand 
    // knockout observables
    $("#ID_of_Container").html($("#ID_of_Template").tmpl(ko.toJS(viewModel)))
    ko.applyBindings(viewModel, $("#ID_of_Container")[0]);

</script>

One approach I am exploring now is to create an additional web service method called ReturnEmptyObject() which does nothing other than create and return a newly instantiated object (whose properties would be default values) on the server side. The (in my case C#) object gets serialized to JSON, and finally arrives on the jQuery Ajax call.... and then passed into ko.mapping.updateFromJS()... which creates the needed observables on initial page load... before I call ko.applyBindings().

When ko.applyBindings() executes, it finds the observables it needs so it won't throw an error, even though they are mostly empty.

This way the page can initially be opened without any of the fields filled in. Yet, if I add some new properties to my class on the server side, they automatically show up on the client side still.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!