【问题标题】:How to add stuff to Knockout mapping view model?如何向 Knockout 映射视图模型添加内容?
【发布时间】:2017-06-25 04:33:17
【问题描述】:

我是 Knockout 的新手,在使用 Knockout 映射插件时无法理解如何“编辑”视图模型。希望有人可以帮助我。我有一个列表。下面是一个类似的例子。基本上有多个文件的多个组。

[
    {
        "group": "Alice",
        "files": [
            {"filename": "red.mp3", "length": 5},
            {"filename": "blue.mp3","length": 6},
            {"filename": "yellow.mp3","length": 5}
        ]
    },
    {
        "group": "Bob",
        "files": [
            {"filename": "green.mp3","length": 2},
            {"filename": "purple.mp3","length": 10}
        ]
    }
]

我可以从中得到基本模型:

$.getJSON('api/get-list', function(data)
    {
        view = ko.mapping.fromJS(data);
        ko.applyBindings(view);
    });

它可以工作,我已经设法将它绑定到 HTML 中,所以它是可见的,并且在那个区域一切都很好。但是,我需要添加一些东西,我不知道该怎么做。更重要的是,如何干净利落地做好。

我正在输出带有复选框的文件,并且我想要一个绑定到它的“选择”属性。我已经能够通过在后端添加字段来做到这一点,但不希望这样做,因为它真的不应该存在。还需要显示当前选择的数量、数量、每组数量和总数。

所以,基本上我想要这样的东西:

{
    "formSubmit": ?,
    "totalNumberOfFiles": ?,
    "totalNumberOfSelectedFiles": ?,
    "groups": 
    [
        {
            "group": "Alice",
            "numberOfFiles": ?,
            "selectedFiles": ?,
            "files": [
                {
                    "filename": "red.mp3",
                    "length": 5,
                    "selected": boolean
                },
                ...
            ]
        },
        ...
    ]
}
  • 虽然,例如,numberOfFiles 可能甚至不需要?可以从files.length 或其他地方得到吗?
  • selectedFiles 应该是一个计算所选文件数量的函数/可观察对象(看起来如何?),还是应该是一个以某种方式添加/删除的列表(以及如何做到这一点? )
  • 我如何在提交功能中获取当前选定文件的列表,以便将它们发送回服务器?
  • 无论哪种方式,我如何以一种不太混乱的方式“增强/丰富/包装”我从服务器获得的基本数组?

基本上,我知道(可以弄清楚)在模型工作时如何进行绑定,但不明白在使用映射插件时如何以好的方式构建它(我真的 不想手动操作)。

希望有人能帮帮我,因为我就是想不通????

【问题讨论】:

    标签: javascript knockout.js viewmodel


    【解决方案1】:

    当你使用 ko.mapping.fromJS 时,每个属性都被转换为 observable,每个数组都被转换为 observableArray。

    主视图模型 MyViewModel 有一个 FileGroups 列表,该列表由使用自定义映射对象的映射初始化。该对象有一个“创建”回调(如 http://knockoutjs.com/documentation/plugins-mapping.html 中所述),它实例化一个新的 FileGroup。

    FileGroup 构造函数中,就在创建新的子视图模型之前,添加了一个属性 'selected',其中 false 是其默认值。

    另外,主视图模型有两个计算的 observable:

    1. numberOfFiles:返回每个 FileGroup 中的文件总数
    2. selectedFiles:返回一个数组,其中包含每个 FileGroup 中的所有选定文件

    submit 方法中,有一个简单的警报来演示如何访问所选文件的数组。

    // data obtained from the server
    var data = [
      {
        "group": "Alice",
        "files": [
          { "filename": "red.mp3", "length": 5 },
          { "filename": "blue.mp3", "length": 6 },
          { "filename": "yellow.mp3", "length": 5 }
        ]
      },
      {
        "group": "Bob",
        "files": [
          { "filename": "green.mp3", "length": 2 },
          { "filename": "purple.mp3", "length": 10 }
        ]
      }
    ];
    
    // sub view model representing a single file grouping
    var FileGroup = function (data) {
      data.files.map(f => f.selected = false);
      ko.mapping.fromJS(data, {}, this);
    }
    
    // main view model
    var MyViewModel = function (data) {
      this.fileGroups = ko.mapping.fromJS(data, { create: options => new FileGroup(options.data) });
    
      this.numberOfFiles = ko.computed(() => {
        return this.fileGroups().reduce((total, fg) => {
          total += fg.files().length;
          return total;
        }, 0);
      }, this);
    
      this.selectedFiles = ko.computed(function() {
        return this.fileGroups().reduce((selectedFiles, fg) => {
          selectedFiles.push.apply(selectedFiles, fg.files().filter(f => f.selected()));
          return selectedFiles;
        }, [])
      }, this);
    
      this.submit = function() {
        alert("FILES POSTED TO SERVER: " + this.selectedFiles().length);
      }
    }
    
    var viewModel = new MyViewModel(data);
    ko.applyBindings(viewModel);
    .fileGroup {
      border: 1px solid lightgray;
      margin-bottom: 15px;
      padding: 10px;
    }
    
    .selected {
      border: 1px solid lightgreen;
      margin-bottom: 15px;
      padding: 10px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js" type="text/javascript"></script>
    
    <div data-bind="foreach: fileGroups">
      <h3 data-bind="text: group"></h3>
    
      <div data-bind="foreach: files" class="fileGroup">
        <input type="checkbox" data-bind="checked: selected">
        <span data-bind="text: filename" />
      </div>
    </div>
    
    <h4>Number of Files: <span data-bind="text: numberOfFiles"></span></h4> 
    
    <div data-bind="foreach: selectedFiles, visible: selectedFiles().length > 0" class=selected>
      <span data-bind="text: filename" />
    </div>
    
    <button data-bind="click: submit">Submit</button>

    【讨论】:

    • 这使得它更加更清晰?我想我现在真的可以靠自己在这条淘汰赛道路上走得更远了。太感谢了! ?
    猜你喜欢
    • 2012-01-30
    • 2013-03-21
    • 2012-06-24
    • 2015-04-22
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    相关资源
    最近更新 更多