剔除:不寻常的映射模式

Knockout : Unusual Mapping Pattern

本文关键字:映射 模式 不寻常 剔除      更新时间:2023-09-26

场景:我向服务器请求一个零件。它还给了我这个(它是伪的,但代表了我所看到的):

{
PartNumber : "XYZ", 
Description: "ABCFOO", 
ProductClass: "Widget",
FieldList:[
    {Name: "PROGRAM TYPE", Value: "Program3"},
    {Name: "SHIP", Value: false},
    {Name: "NOTES", Value: "SomeValue1"}
],
MoreStuff : [{
    ...
}]
}

注意元素的FieldList列表,这是这里的重点。

服务器还给了我一个特定字段的列表,它们的类型和默认值。它看起来像这样:

[
{FieldName : "PROGRAM TYPE", FieldType: "List", Defaults: [{Name:"Program 1", Value: "Program1"},{Name:"Program 2", Value: "Program2"},{Name:"Program 3", Value: "Program3"}]},
{FieldName : "SHIP", FieldType : "Boolean", Defaults: []},
{FieldName : "NOTES", FieldType: "TextArea", Defaults: []}
]

这是一个单独的REST调用,在加载我的Part之前。我使用它来为部件创建HTML页面的一部分。您可以看到,当我请求Part时,它们与FieldList部分有类似的关系。

根据"字段列表"和默认值,我在页面上生成了适当的HTML元素。如果是布尔字段类型,我会创建一个复选框——如果是列表,我会生成一个SELECT(默认值中有选项),TextArea是一个文本区域,等等。这些都很好。它最终看起来像:

<input data-bind="textInput: PartNumber"/>
<textarea data-bind="textInput: Description"></textarea>
<!-- generating fieldlist - i create a pseudo attr because the field name can have spaces-->
<select field_label="PROGRAM TYPE">   <!-- how the heck do i bind to this??-->
   <option value="Program1">Program 1</option>
   <option value="Program2">Program 2</option>
   <option value="Program3">Program 3</option>
</select >
<input type="checkbox" field_label="SHIP" value="true"/> <!-- or this, how to bind to it?!-->
<!-- end of field list generation -->

现在我把这个对象(我得到的部分)放进我的ViewModel中——这一切都很顺利。我让它变得简单,只需使用ko.mapping.fromJS(rest_data);就可以了。

数据绑定是ducky的——因为我能够将它绑定到什么。我的问题来自于——我该如何将我的FieldList映射到我为服务器提供的字段生成的HTML。我的数据/视图模型对象中有FieldList,其中有一个buncha内容,我想映射到生成的内容。我拥有的唯一真正的"密钥"是我自己创建的field_label,因为服务器的FieldName可以有空间。

所以我想我要问的是,我有一个FieldList的数组。我的视图模型中有整个Part对象,一切都很好。如何获取FieldList并将其映射到另一个对象(即,获取FieldList名称并将其绑定到具有相同值的field_label的元素?

拼写如下:如何将名称为"PROGRAM TYPE"的FieldList映射到field_label为"PROGRAM TYPE"的HTML元素。

我开始认为这样的事情可能是我应该走的方向:http://jsfiddle.net/MhdZp/128/但它超出了我的想象。

解决这一问题的一种方法:

function Option(definition) {
    this.definition = definition;
    this.value = ko.observable();
    this.templateName = 'input-template-' + definition.FieldType;
}
function ViewModel() {
    var self = this;
    // from REST call
    var fieldDefinition = [{
        FieldName: "PROGRAM TYPE",
        FieldType: "List",
        Defaults: [
            { Name: "Program 1", Value: "Program1" }, 
            { Name: "Program 2", Value: "Program2" }, 
            { Name: "Program 3", Value: "Program3" }
        ]
    }];
    self.options = ko.observableArray();
    // for the sake of the example
    self.options.push(new Option(fieldDefinition[0]));
    // methods    
    self.optionByName = function (name) {
        return ko.utils.arrayFirst(self.options(), function (option) {
            return option.Name = name;
        });
    };
    // poor man's init, imagine 2nd rest call instead
    self.optionByName("PROGRAM TYPE").value("Program3");
}

<script type="text/html" id="input-template-List">
    <label data-bind="text: definition.FieldName"></label>
    <select data-bind="
        value: value,
        options: definition.Defaults,
        optionsText: 'Name',
        optionsValue: 'Value',
        optionsCaption: 'Please select...'
    "></select>
</script>

<div data-bind="foreach: options">
  <div data-bind="template: templateName"></div>
</div>

根据需要添加更多的模板,这应该很容易扩展。

jsFiddle:http://jsfiddle.net/0nxt2zte/