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

Posted

技术标签:

【中文标题】Knockout JS映射插件没有初始数据/空表单【英文标题】:Knockout JS mapping plugin without initial data / empty form 【发布时间】:2011-10-07 19:00:55 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

除了手动管理视图模型之外,还有几个选项可供您选择。映射插件支持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/

【讨论】:

感谢 RP Niemeyer,我将在接下来的几天内尝试一下。听起来很有希望! cust init 绑定对我来说非常有用,但我不喜欢绑定中数据绑定属性的动态更新,所以我建议使用virual elements。类似于: @ChrisDaMour - 这个版本有点过时了。我使用自定义绑定更新了答案,该绑定将 value 绑定应用于元素,但不会覆盖任何其他绑定。另一种选择是在任何其他绑定之前使用单独的 init 绑定。 @RPNiemeyer,这仍然是解决此问题的最佳方法吗? @GONeale - 如果你想“即时”创建 observables,那么这仍然是一个不错的选择。【参考方案3】:

我认为解决您问题的方法来自以错误的方式思考视图模型。视图模型不仅是向视图传递数据的东西,而且还是用于提交数据的占位符。

我通常最终使用淘汰赛的方式,我永远不会最终将空视图模型发送到视图。视图模型通常具有我绑定的所有字段。虽然它们可能是空字符串,或者没有显示值的初始化对象,但实际对象仍然存在,每个对象都正确表示为我绑定到的字段。

您可能想研究简单地向视图发送空对象而不是什么。

编辑:示例是非 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>

在某些 sanarios 中,只有一部分视图模型在发生变化(如果您正在进行 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>

【讨论】:

你也在使用 KO 映射插件吗?这使您能够生成视图模型,而不必“手动”定义它。这是我们遇到问题的部分。 希望编辑有所帮助。我花了一点时间才意识到我可以通过淘汰赛来做这种事情。但是它最终得到了一些非常好的结果。它确实给网站一个厚客户端和非常流畅的 AJAX 流。

以上是关于Knockout JS映射插件没有初始数据/空表单的主要内容,如果未能解决你的问题,请参考以下文章

带有 require.js 的 Knockout.js 映射插件

Knockout.js 数据验证之插件版和无插件版

使用 Knockout.js 在表单输入上切换按钮状态

Select2 与 Knockout.js 初始值

Knockout JS 如何将数据绑定到静态表单元素

我是不是总是使用 Knockout 映射插件来执行我的视图模型,从而过度使用它?