【问题标题】:dynamic form building with knockoutjs使用 knockoutjs 构建动态表单
【发布时间】:2012-10-19 18:42:56
【问题描述】:

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

    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'" }
       ]
    */

我可以从 DB 中的“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中描述的技巧

以下是我执行 alert(ko.toJSON(self))

时打印出来的 Json 数据
    {"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 数据映射到我的 MyFieldViewModel 类,我仍然感到困惑,但我仍然如何获得选择价值观?

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

当我改变时

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

与 数据:ko.toJSON(self)

映射在我的控制器上运行良好,您可以在以下屏幕截图中看到:

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

【问题讨论】:

    标签: ajax asp.net-mvc-3 knockout.js json.net form-post


    【解决方案1】:

    要跟踪更改,您可以使用本文中的dirty flaghttp://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/

    【讨论】:

    • 非常感谢@Artem 的快速回复。这回答了动态表单部分的构建。我还需要在运行时隐藏一些字段,为此,当我无法在 AJAX 请求的数据属性中静态键入元素名称时,我会将“所有表单数据”发布到服务器。其次,假设服务器返回一个 JSON 列表,其中包含需要隐藏的那些元素的名称。我将消失表单上的所有此类元素(同时取消隐藏之前隐藏的任何其他元素)。我希望你能理解我的问题。非常感谢您的努力。
    • @Akeel - 听起来你很接近。您可以使Blankout 成为可观察对象,然后对每个它使用visibleif 绑定,或者创建一个表示非隐藏字段的计算(返回一个数组),然后通过它创建一个foreach。您可以在脏标志触发时执行 AJAX 请求,并且当您的响应返回时更新每个字段上的 Blankout 可观察值。我是否正确理解了您的情况?
    • @ArtemVyshniakov 感谢您的帮助。我已尝试按照您的建议将数据发布到我的控制器,但没有成功。我已经用更多细节更新了这个问题。
    • 更新了稍加修改的jsfiddle jsfiddle.net/akeelrehman/fpXPK/2,也就是跟踪元素的值,最终这些元素被传递到服务器。
    猜你喜欢
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    相关资源
    最近更新 更多