2012-10-30 90 views
5

我需要从数据库中构建一个动态表单。我有以下实体来快速定义表单字段:动态表单构建与knockoutjs

public class FormField { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public string Type { get; set; } // Possible values are: 'Radio','Combo','Text'. A dropdown will be created for a Combo type of element, a radio set for Radio type of element and a text input for Text type of element. 
     public string Options { get; set; } // Only relevant in case of Radio/Combo type 
     public string Default { get; set; } // Default value in case of Type 'Text' and selected value in case of Type 'Radio/Combo' 
     public string Blankout { get; set; }// An expression to define when this field should be hidden 
    } 

    /* A sample JSON array (from the DB) to build the form would be: 
     [ 
     { Name:"Gender", Type:"radio", Options:["Male","Female","Unknown"], Default:"Male", Blankout:"Never" }, 
     { Name:"Age", Type:"text", Options:"None", Default:15, Blankout:"Never" }, 
     { Name:"Neighbourhood", Type:"Combo", Options:["Eastern","Western","Northern","Southern","Central"], Default:"Central", Blankout:"if (Age < 40 or Voted='Obama')" }, 
     { Name:"Voted", Type:"Combo", Options:["Obama","Romney","Harry Potter"], Default:"Harry Potter", Blankout:"if ((Gender='Female' and Age < 15) or Neighbourhood='Eastern'" } 
     ] 
    */ 

我可以建立从“FormField”在数据库记录的动态表单,但问题是我需要跟踪的任何表单字段的值的变化,当价值发生变化时,我需要将所有表单数据发送到服务器(异步),以便评估服务器上的“Blankout”公式。如果我在没有KnockoutJS的情况下执行这个更改跟踪事件,那么它没有响应并且变得非常复杂。 我已经通过KnockoutJS的几个教程,但无法弄清楚如何组织我的ViewModel这个特定的问题。

任何帮助,将不胜感激。

更新1

我曾尝试使用下面的代码来发布此表单数据控制器:

$.ajax({ 
      type: "POST", 
      url: "/MyController/GetBlankoutElements", 
      contentType: 'application/json', 
      dataType: 'json', 
      data: JSON.stringify(ko.toJSON(self)), 
      success: function(result) { 
       alert(result); 
       //self.HiddenElements(result.split(',')); 
      } 
    }); 

在我的控制器中我曾尝试下面的代码:

[HttpPost] 
    public ActionResult GetBlankoutElements(List<MyFieldViewModel> Fields) 
    { 
     return Json(Fields); // List, Fields is null here 
    } 

她是MyFieldViewModel类的外观:

public class MyFieldViewModel 
    { 
     public string Title { get; set; } 
     public string Name { get; set; } 
     public string Type { get; set; } 
     public string Default { get; set; } 
     public string[] Options { get; set; } 
    } 

我试图在提示Post an Array of Objects via JSON to ASP.Net MVC3

描述以下是打印出当我执行警报(ko.toJSON(个体经营))

{"Fields": 
     [{"Title":"CCType","Name":"CCType","Type":"Radio","Default":"Enterprise","Options":["Enterprise","Express","CVP","PCCE"]},{"Title":"Industry","Name":"Industry","Type":"Combo","Default":"Banks","Options":["Banks","ServiceProvider","Outsourcer","Airlines","Utilities","Government","Retail"]},{"Title":"Customer Lab","Name":"CustomerLab","Type":"Combo","Default":"0","Options":["0","1"]},{"Title":"No of Agents","Name":"Agents","Type":"Text","Default":"if(c.CCType==\"CVP\") then 10 else 25","Options":[]},{"Title":"ExpLicType","Name":"ExpLicType","Type":"Radio","Default":"if(c.CCType==\"Express\") then \"Enhanced\" else \"None\"","Options":["None","Premium","Standard","Enhanced"]},{"Title":"Multimedia","Name":"Multimedia","Type":"Combo","Default":"WIM","Options":["None","EIM","WIM","EIM&WIM","BSMediaRouting","MCAL"]}], 
    "HiddenElements":[] 
    } 

我需要的仅仅是JSON数据该字段的名称和它的用户选定的值,我很困惑,即使我得到这个JSON数据映射到我的MyFieldViewModel类,仍然会如何得到选定的值?

更新2(JSON数据映射工作)

当我改变

data: JSON.stringify(ko.toJSON(self)) 

与 数据:ko.toJSON(个体)

映射我的控制器上完美地工作,如下图所示: Debug screenshot of Mapped list object from post json data

现在,问题仍然存在,发布表单的要点是用表单上的用户输入更新服务器,即针对每个表单字段元素的值。 我如何发布表单字段的当前选定/类型值? 例如,在上面的屏幕截图中,我可以看到Default但不是当前选定的值。

回答

8

对于跟踪更改,您可以使用dirty flag从这篇文章:http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html

创建以下视图模型:

function FormField(data) { 
    var self = this; 

    self.Name = ko.observable(data.Name); 
    self.Type = ko.observable(data.Type); 
    self.Options = ko.observableArray(data.Type != 'text' ? data.Options : []); 
    self.Default = ko.observable(data.Default); 
} 

function ViewModel(data) { 
    var self = this; 

    self.Fields = ko.observableArray(ko.utils.arrayMap(data, function(item) { 
     return new FormField(item); 
    })); 

    self.dirtyFlag = new ko.dirtyFlag(this); 

    self.isDirty = ko.computed(function(){ 
     if (self.dirtyFlag.isDirty()) 
     { 
      alert("Value changed!"); 
      // Do async update. 
     } 
    }); 
} 

HTML标记:

<div data-bind="foreach: Fields"> 
    <b data-bind="text: Name"></b> 
    <!--ko if: Type() == "combo"--> 
     <select data-bind="options: Options, value: Default"></select>     <!--/ko--> 
    <!--ko if: Type() == "radio"--> 
     <div data-bind="foreach: Options"> 
      <input type="radio" value="cherry" data-bind="value: $data, checked: $parent.Default" /> 
      <span data-bind="text: $data"></span> 
     </div> 
    <!--/ko-->  
    <!--ko if: Type() == "text"--> 
     <input type="text" data-bind="value: Default"></input>     
    <!--/ko--> 
    <br/>  
</div> 

这里是工作提琴:http://jsfiddle.net/vyshniakov/CWTTR/

编辑:

这里是你的问题,如果回答我理解他们是正确的:

要将所有字段发布到服务器,您可以使用ko.toJSON(self)函数。你的Ajax调用看起来如下:

$.ajax({ 
     type: "POST", 
     url: "controller/action", 
     contentType: 'application/json', 
     data: JSON.stringify(ko.toJSON(self)), 
     success: function(result) { 
      self.HiddenElements(result); 
     } 
    }); 

看更新的小提琴,看看如何隐藏某些字段依赖于从服务器响应:http://jsfiddle.net/vyshniakov/CWTTR/1/

+0

非常感谢你对@Artem的这种快速回应。这回答了动态表单部分的构建。我还需要在运行时隐藏一些字段,这样做时,我不会在AJAX请求的数据属性中静态键入元素名称,因此我会将“所有表单数据”发布到服务器。其次,让服务器返回一个JSON列表,其中包含那些需要隐藏的元素的名称。我会消失在窗体上的所有这些元素(同时取消隐藏之前隐藏的任何其他元素)。我希望你能理解我的问题。真的很感谢你的努力。 –

+0

@Akeel - 听起来你很接近。你可以使'Blankout'成为一个可观察对象,然后对每个对象使用'visible'或'if'绑定,或者创建一个代表非隐藏字段(返回一个数组)然后通过它的'foreach'的计算。当脏标志触发并且您的响应返回时,您可以在AJAX请求中更新每个字段上的'Blankout'可观察值。我是否正确理解你的方案? –

+0

@Akeel查看更新后的帖子。 –