在Knockout中绑定多个部分视图

时间:2014-11-19 17:55:07

标签: asp.net-mvc knockout.js asp.net-mvc-5

enter image description here

我有一个jQuery手风琴,每个小组都包含一个表格。所有表单都相同,输入共享相同的ID,名称和data-bind属性。

假设每个表单具有不同的绑定上下文(使用ko with:),this is how I would set up the Knockout.js ViewModel如果有两个表单。

但是,我事先并不知道会有多少表格。我正在为MVC ViewModel的表单集合中的每个表单对象呈现一个PartialView(包含表单)。

@model ViewModel

<div class="container-fluid">
    <div id="jQueryAccordion">

        @foreach (var form in Model.AllForms.ToList())
        {
           <!-- ko with: items[@form.Key] -->
           Html.RenderPartial("_Form", form);
           <!-- /ko --> 
        }

        // etc.

如果我不知道将会有多少种形式,我将如何设置Knockout.js ViewModel?

2 个答案:

答案 0 :(得分:3)

我建议你可以通过ajax call&amp; amp;相应地绑定数据敲除绑定如下:

//C# XxxController: return partial view:
public ActionResult MyView()
{
    return PartialView("_MyView");
}

//Ajax call to load partial view at client side:
$.get('Xxx/MyView', function(view){
    _contentHolder.html(view);
    ko.applyBinding(self, _contentHolder[0]);
})

您可以循环遍历模型集合并动态应用挖空绑定。

答案 1 :(得分:2)

正如Anh Bui建议的那样,我会在浏览器中动态创建它们。在服务器端使用ASP.net创建的标记使用applyBindings有点像黑客攻击,这意味着你要对抗Knockout,而不是使用它。

最好让Knockout负责实际创建表单。这意味着

  1. 仅向其提供创建每个表单所需的数据为JSON
  2. 为表单标记创建Knockout模板
  3. 使用forEach绑定
  4. 循环数据

    模板:

    <script type="text/html" id="form-template">
      <form action="/target-url">
        <label for="user_name">What's your name?</label>
        <input type="text" data-bind="value: user_name" name="user_name" />
        <label for="user_location">Where are you from?</label>
        <input type="text" data-bind="value: user_location" name="user_location" />
      </form>
    </script>
    

    接下来,您将相关的表单数据作为JSON数组输出到服务器端。我还没有使用ASP.net,所以我只能在这里提供伪代码:

    <script type="application/javascript">
      window.form_json_from_server = "
    
       @foreach (var form in Model.AllForms.ToList())
       {
         // .. ASP.net JSON output magic goes here
       }
    
      ";
    </script>
    

    这样你的标记的最终结果就像

    <script type="application/javascript">
      window.form_json_from_server = "[
    
       { user_name: "Foo1", user_location: "Bar1" },
       { user_name: "Foo2", user_location: "Bar2" },
       { user_name: "Foo3", user_location: "Bar3" }
    
      ]";
    </script>
    

    (请注意,JS字符串不能包含换行符。我在这里使用换行符对其进行格式化以便于阅读)

    现在我们将表单数据格式化为JSON,保存在Javascript字符串中。接下来:您的Knockout视图模型:

    var ViewModel = function ViewModel() {
      var that = this,
          raw_forms_object;
    
      // we reconstitute our JSON string into a Javascript object
      raw_forms_object = JSON.parse(window.form_json_from_server);
    
      // this is where the objects made from our JSON will end up in
      this.forms = ko.observableArray([]);
    
      ko.utils.arrayForEach(raw_forms_object, function(f) {
        // f contains one of our form objects, such as { user_name: "Foo1", user_location: "Bar1" }
    
        // instead of adding f directly to the array, we make a new object in which the
        // properties are observables
        var form = {
          user_name: ko.observable(f.user_name),
          user_location: ko.observable(f.user_location),
        };
    
        // add our new form object to our observableArray
        // make sure to use 'that', because 'this' is the scope of the arrayForEach callback we're in
        that.forms.push(form);
      });
    }
    

    现在我们有一个名为&#39;形式的observableArray&#39;在我们的视图模型中使用我们的表单对象。我们使用forEach绑定来创建与表单对象一样多的表单:

    <div data-bind="template: { name: 'form-template', foreach: forms }"></div>
    

    剩下的就是将我们的视图模型实例应用于页面:

    ko.applyBindings( new ViewModel() );
    

    如果您愿意,可以在此可运行的代码段中试用:

    &#13;
    &#13;
    var ViewModel = function ViewModel() {
      var that = this,
          raw_forms_object;
        
      // we reconstitute our JSON string into a Javascript object
      raw_forms_object = JSON.parse(window.form_json_from_server);
        
      // this is where the objects made from our JSON will end up in
      this.forms = ko.observableArray([]);
        
      ko.utils.arrayForEach(raw_forms_object, function(f) {
        // f contains one of our form objects, such as
        // { user_name: "Foo1", user_location: "Bar1" }
        
        // instead of adding f directly to the array, we make a new object in which the
        // properties are observables
        var form = {
          user_name: ko.observable(f.user_name),
          user_location: ko.observable(f.user_location),
        };
        
        // add our new form object to our observableArray
        // make sure to use 'that', because 'this' is the scope 
        // of the arrayForEach callback we're in
        that.forms.push(form);
      });
    }
    
    
    ko.applyBindings( new ViewModel() );
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <script type="text/html" id="form-template">
      <form action="/target-url">
        <label for="user_name">What's your name?</label>
        <input type="text" data-bind="value: user_name" name="user_name" />
        <label for="user_location">Where are you from?</label>
        <input type="text" data-bind="value: user_location" name="user_location" />
      </form>
    </script>
    
    <div data-bind="template: { name: 'form-template', foreach: forms }"></div>
    
    <script type="application/javascript">
       window.form_json_from_server = '[{"user_name": "Foo1","user_location": "Bar1"},{"user_name": "Foo2","user_location": "Bar2"},{"user_name": "Foo3","user_location": "Bar3"}]';
    </script>
    &#13;
    &#13;
    &#13;