【问题标题】:Knockout - readonly model binding from selected item in dropdown淘汰赛 - 下拉列表中选定项目的只读模型绑定
【发布时间】:2012-04-03 22:12:58
【问题描述】:

我遇到了 Knockout 中 ViewModel 结构的问题。

更新

JS Fiddle

结束更新

概述

  • 我想从 MVC 操作返回一个模型并使用映射 淘汰赛扩展以创建从 JSON 到 ViewModel 的 observable。
  • 表中的显示项目只有一个字段是可编辑的,而这 字段是下拉列表,但它导致项目的所有属性都更新 价值观。
  • 将模型发布回 MVC 操作。

说明

我正在使用映射扩展将从 MVC 操作返回的 JSON 模型映射到淘汰模型,我的模型如下所示:

public class SomeClassInput
{
    public string Help { get; set; }
    public IEnumerable<SomeClassItem> Items { get; set; }

    public class SomeClassItem
    {
        public string Code { get; set; }
        public string Location { get; set; }
        public string Easting { get; set; }
        public string Northing { get; set; }
        public string WaterName { get; set; }
        public string WfdCode { get; set; }
    }

    public SomeClassInput()
    {
        Items = new List<SomeClassItem>();
    }
}

从 Action 返回的模型,可以包含默认数据 - 少量项目。

我正在使用 JSON 的自定义序列化设置,因此所有 PascalCase 属性名称都转换为 camelCase。

绑定非常简单(包装某种控制器以管理少量屏幕和动态加载视图):

this.model = ko.mapping.fromJS(modelJson);
ko.applyBindings(this.model, this.view.content[0]);

现在在视图中我有一张桌子:

<table class="table table-striped table-bordered" id="some-table"
       data-swo-codes="@Url.Action("Codes", "Controller")"
    >
    <thead>
        <tr>
            <th>
                [Actions]
            </th>
            <th>
                Code
            </th>
            <th>
                Location
            </th>
            <th>
                Name of Water
            </th>
            <th>
                WFD Code
            </th>
        </tr>
    </thead>
    <tbody data-bind="template: {name: 'rowTemplate', foreach: items}">
    </tbody>
    <tfoot>
        <tr>
            <td colspan="6">
                <button class="btn" data-bind="click: table.addRow">Add new Storm Water Overflow</button>
            </td>
        </tr>
    </tfoot>
</table>           

<script type="text/html" id="rowTemplate">
    <tr>
        <td>
            <button class="btn" data-bind="click: $parent.table.removeRow "><i class="icon-remove"></i></button>
            <button class="btn" data-bind="click: $parent.table.moveUp, disable: ko.computed(function() { return $parent.table.moveUpEnabled.call($parent, $data); }, $parent) "><i class="icon-arrow-up"></i></button>
            <button class="btn" data-bind="click: $parent.table.moveDown, disable: ko.computed(function() { return $parent.table.moveDownEnabled.call($parent, $data); }, $parent) "><i class="icon-arrow-down"></i></button>
        </td>
        <td>
            <select data-bind="options: $parent.codes, optionsText: 'name', value: code, optionsCaption: 'Select Code...'"></select>
        </td>
        <td>
            <label data-bind="visible: code, text: location" />
        </td>
        <td>
            <label>E</label><label data-bind="visible: code, text: easting" />
            <label>N</label><label data-bind="visible: code, text: northing" />
        </td>
        <td>
            <label data-bind="visible: code, text: waterName" />
        </td>
        <td>
            <label data-bind="visible: code, text: wfdCode" />
        </td>
    </tr>    
</script>

这不是工作示例 - 所以标签可以是跨度或任何需要的。

$parent.table | table - 围绕表格包装所有操作,例如添加一行、删除、上下移动。这行得通。

只有一个单元格是可编辑的——代码。代码将是一个下拉菜单,由后台的一些 ajax 代码初始化,返回所有可能的代码和连接到项目的元数据 - 此调用在模型 ko.applyBindings 之前执行。 ajax 调用的结果看起来几乎像模型:

[ {
  name: 'some_name_of_code',
  code: 'GUID',
  location: 'some_place',
  easting: '435',
  northing: '345',
  waterName: 'some_name',
  wfdCode: 'some_code'

}, {
//..
}]

当用户从代码下拉列表中选择一个项目时,所有属性都应该显示并映射到模型。 this.model.items[0].easting 将并且应该返回一个值。

所以当用户点击保存时,我可以打开模型并将其作为 JSON 发布到 MVC 操作。

更新

以防万一,因为我所有的淘汰赛视图模型都由 controller 管理,所以有一个标准。将模型发布回服务器的方式,负责它的片段:

save: function () {
    var that = this,
        model = ko.mapping.toJS(this.model);

    delete model.help;

    logger.log(this.id + ' SAVE event executing');

    return $.ajax({
        type: 'POST',
        url: this.saveUri,
        data: JSON.stringify(model),
        contentType: 'application/json; charset=utf-8',
        success: function() {
            logger.log(that.id + ' SAVE event executed and finished with success, cleaning up dirty flag');

            that.model.tracker().markCurrentStateAsClean();
        }
    });
}

结束更新

问题

如果不编写大量自定义函数来设置数据,我不确定如何实现我想要的——从动作返回的模型到视图模型,以及从视图上的内容到将被回发的模型到服务器。

任何帮助将不胜感激。

更新

JS Fiddle

结束更新

【问题讨论】:

  • 你想达到什么目的?我迷路了...... Jsfiddle 展示问题所在会很有帮助。
  • jsfiddle 添加。我想将我在下拉列表中选择的内容映射到模型中的项目,以便我的通用保存方法可以处理保存。此外,我应该能够显示加载时从服务器传递的数据

标签: knockout.js


【解决方案1】:

这是工作小提琴。

http://jsfiddle.net/madcapnmckay/wgRdj/

发现了一些东西。首先,您的初始视图模型创建没有使用任何映射 配置所以这一行。

var viewModel = ko.mapping.fromJS(jsonModel);

创建匿名对象而不是 Item 类型的对象。我把它改成了。

var viewModel = ko.mapping.fromJS(jsonModel, { 
    items: {
       create: function (options) {
           return new Item(options.data);
       }
    } 
});

其次,您传入的 json 包含来自代码对象的每条数据的副本。为了使选项绑定正确选择值,您必须引用相同的确切对象实例,因为即使具有相同的值,js 也无法区分两个对象。有很多方法可以做到这一点,但为了保持现有的 json 结构,我只是将绑定更改为仅引用 codeid 而不是整个对象,并使其他项目值从中派生。

function Item(config) {
   var self = this;
   this.code = ko.observable(config.code);

   var value = ko.computed(function() {
        if (this.code()) {
            // find the code in the list
            return ko.utils.arrayFirst(viewModel.codes(), 
                 function (c) { 
                     return c.code == self.code(); 
                 });
        }
        return null;
   }, this);        

   var getValue = function(name) {
       if (value()) {
           return value()[name];
       }
       return "";
   }        

   this.location = ko.computed(function() {
       return getValue("location");
   }, this);

   this.easting = ko.computed(function() {
       return getValue("easting");
   }, this);

   this.northing = ko.computed(function() {
       return getValue("northing");
   }, this);

   this.waterName = ko.computed(function() {
       return getValue("waterName");
   }, this);

   this.wfdCode = ko.computed(function() {
       return getValue("wfdCode");
   }, this);
}

这样做的好处是最初只需要在 json 中传递 id。

希望这会有所帮助。

【讨论】:

  • 太好了,谢谢,ps。检查配置是否定义为req,否则添加行不起作用。
猜你喜欢
  • 2017-10-15
  • 2013-02-14
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多