Knockout JS映射插件没有初始数据/空表单

时间:2011-07-18 15:19:22

标签: javascript knockout.js jqtouch knockout-mapping-plugin

我们正在使用knockout和knockout映射插件来促进我们的jQTouch Web应用程序中的数据绑定。我们使用映射插件的原因是能够使用knockout而无需在javascript中手动定义/更改viewmodels。当您从服务器/客户端数据库初始加载数据时,映射插件非常有用。

我们遇到的问题是我们有一些屏幕/视图,其中有一种形式可能没有任何初始数据。如果没有这个初始数据,映射插件就无法“生成”viewmodel(ko.mapping.fromJS)。这意味着我们仍然需要手动定义视图模型的大部分视图。

我认为这是映射插件(应该)支持的场景我错了吗?我的意思是,这意味着映射插件仅在您始终具有初始数据负载的情况下可用。

3 个答案:

答案 0 :(得分:19)

除了手动管理视图模型之外,还有几个选项。映射插件支持create回调,允许您自定义如何创建它。这可用于向对象添加默认属性(如果它们恰好丢失)。

像这样:http://jsfiddle.net/rniemeyer/WQGVC/

另一种方法是使用创建缺失属性的绑定。它可能看起来像:

//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] });
    }
}

你会像这样使用它(需要将属性作为字符串传递,否则会出错):

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

此处示例:http://jsfiddle.net/rniemeyer/JPYLp/

答案 1 :(得分:4)

我认为解决问题的方法来自于以错误的方式思考视图模型。视图模型不仅可以将数据传递给视图,还可以用于提交数据的占位符。

我通常最终使用淘汰赛的方式,我从未最终向视图发送空视图模型。视图模型通常包含我绑定的所有字段。虽然它们可能是空字符串,或者没有显示值的初始化对象,但实际的对象仍然会退出,并且每个对象都适当地表示我绑定的字段。

您可能希望仅查看向视图发送空对象而不是任何内容。

编辑:该示例是非ASP.NET MVC

基本上,我在服务器端,创建了一个视图模型对象,其中包含需要显示的所有数据以及需要收集的所有数据。为了更容易验证代码,我通常会将要收集的数据放入其自己的子类中,但这完全取决于代码的需求。

在任何情况下,从vmBase类进入视图内部的任何对象基本上都提供了一个toJSON()方法,该方法生成对象的JSON序列化。这在视图引擎的视图中被调用。如下面的代码所示。

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

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

当我准备好重新发送代码时,我只需删除一个JS版本的视图模型。

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

在某些视图中,只有部分视图模型正在发生变化(这就是你正在进行AJAX更新),你可以做一些很酷的事情,比如切换模板,以便可以应用不同的绑定。在这种情况下,我们使用 #ID_of_Container 作为原始数据/模板的容器,并将模板(可以包含data-bind =“”元素)替换为新模板 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>

答案 2 :(得分:0)

我现在正在探索的一种方法是创建一个名为ReturnEmptyObject()的附加Web服务方法,除了在服务器端创建并返回一个新实例化的对象(其属性将是默认值)之外,它什么都不做。 (在我的情况下是C#)对象被序列化为JSON,最后到达jQuery Ajax调用....然后传递到ko.mapping.updateFromJS()...这将在初始页面加载时创建所需的observable。在我调用ko.applyBindings()之前。

当ko.applyBindings()执行时,它会找到它需要的observable,因此它不会抛出错误,即使它们大部分都是空的。

这样一来,页面最初可以在没有填写任何字段的情况下打开。但是,如果我在服务器端向我的类添加一些新属性,它们会自动显示在客户端。