mvvm - knockout JS - ViewModel 抽象

标签 mvvm knockout.js viewmodel abstraction

*更新* (见下文)

我了解 KnockoutJS 的基础知识。创建 TableView 模型时,可以使用 <tr data-bind="foreach: rows">
现在我正在尝试抽象 TableView 模型,以便我可以创建具有相同行为(排序、编辑、分页等)的多个表。所以我的目标是这样的:

HTML

<div class="table a" data-bind="myTableBinding: aTableViewModel"></div>
<div class="table b" data-bind="myTableBinding: anotherTableViewmodel"></div>

主视图模型
var MainViewModel = function () {
  this.aTableViewModel = new AbstractTableViewModel({
      columns: [...]
      initialSort: [...]
  });
  this.anotherTableViewModel = new AbstractTableViewModel({
      columns: [...]
      initialSort: [...]
  });
};

我的第一次尝试是模仿 KnockoutJS 文档用于 [Paged grid] 示例的示例 [simpleGrid] 插件 (@ http://knockoutjs.com/examples/resources/knockout.simpleGrid.1.3.js )。

我不太确定,但我认为抽象的基本概念在这个插件中没有得到很好的体现。当我试图将 css 类包含到 <th> 中时像这样的元素:<th class="col col-id"> , <th class="col col-name">等,我发现使用 data-bind 这并不容易(不可能?)属性。
data-bind属性可能不应该用于这些东西,因为这些类不会改变——它们是更高抽象级别的一部分:我们实际上应该使用 jQuery.tmpl 或 Underscore 的模板系统插入这些类。但后来我收到一条错误消息,说 [此模板系统不支持使用 foreach绑定(bind)](或类似的东西)。

因此,我的第二次尝试是实现抽象,因为它应该被实现:表属性(列等)在另一个“抽象级别”而不是表数据:
  • 创建基础<tr data-bind="foreach: rows"> html 在新的特定 TableView 模型的实例化中,使用“抽象”模板——我只是用 Underscore 的 _.template 做的。
  • 让这个特定的 View 模型像往常一样使用上面的 html。

  • 在 CoffeeScript 中:
    do ->
      ko.dataTable =
        ViewModel: (config) ->
          @id = config.id
          @columns = config.columns
          @pageSize = config.pageSize ? 9999
          @sortColumn = ko.observable (config.sortColumn ? @columns[0].col)
          @sortOrder = ko.observable (config.sortOrder ? "asc")
          @data = ko.observableArray (config.data ? [])
          null
    
      ko.bindingHandlers.dataTable =
        init: (el, acc) ->
          viewModel = acc()
          $(el).find("div:first").html dataTableTemplateMaker viewModel
          # ??? [A] ko.applyBindings viewModel, $(el).find("table")[0]
          # ??? [B] controlsDescendantBindings: yes
          null
        update: (el, acc) ->
          viewModel = acc()
          # ??? [C]
          null
    

    进而:
    <div data-bind="dataTable: groupTable">
    

    和:
    class ViewModel
      constructor: ->
        @groupTable = new ko.dataTable.ViewModel
          id: "grouptable"
          columns: [
            { col: "num",     title: "Groep", editable: yes }
            { col: "subject", title: "Vak" }
            { col: "year",    title: "Jaar" }
            { col: "level",   title: "Niveau" }
            { col: "day",     title: "Dag" }
            { col: "hour",    title: "Uur" }
            { col: "place",   title: "Lokaal", editable: yes }
          ]
          pageSize: 10
          sortColumn: "num"
          sortOrder: "asc"
          data: [] # [D]
    

    ...其中???标记我的困惑所在的位置。

    假设我不插入行 [A][B] .然后当然 KnockoutJS 告诉我绑定(bind)在我的特定 View 模型的 html 中都搞砸了(插入到 <div> 中。如果我插入行 [A][B] ,那么它确实适用于初始数据(在 [D] ),但之后没有响应。

    总而言之:我对抽象 View 模型这样简单的事情感到很困惑。在 KnockoutJS 中没有标准的解决方案吗? (我用谷歌搜索但找不到任何东西......)还是我自己搞砸了(很可能)? ;)

    *更新*

    我解决了这个问题(但也许它根本不是最好的/很好 - 你的意见是什么?),为了完整起见:(一个浓缩版本 - 当然你可能还想单独观察行等。 .)

    HTML(是的,这是故意传递给绑定(bind)处理程序的字符串)
    <div data-bind="myTableBinding: 'viewModelPropertyHoldingTableViewModel'"></div>
    

    CoffeeScript
    class MainViewModel
      constructor: ->
        @viewModelPropertyHoldingTableViewModel = new TableViewModel <options>
        null
    
    class TableViewModel
      constructor: (options) ->
        @columns = options.columns
        @rows = ko.observableArray (options.rows ? [])
        [...]
        null
    
    tableTemplateMaker = _.template '
      <table>
        <thead>
          <tr>
            [% _.map(tableViewModel.columns, function (column) { %]
            <th>[%= column.title %]</th>
            [% } %]
          </tr>
        </thead>
        <tbody data-bind="foreach: rows">
          <tr>
            [% _.map(tableViewModel.columns, function (column) { %]
            <td data-bind="text: [%= column.id %]"></td>
            [% } %]
          </tr>
        </tbody>
      </table>
    '
    
    ko.bindingHandlers.myTableBinding =
      init: (element, viewModelPropertyNameAccessor, _, mainViewModel) ->
        tableViewModelProperty = viewModelPropertyNameAccessor()
        tableViewModel = mainViewModel[tableViewModelProperty]
        $(element).html tableTemplateMaker
          tableViewModelProperty: tableViewModelProperty
          tableViewModel: tableViewModel
        null
    
    m = new MainViewModel
    ko.applyBindings m
    
    m.viewModelPropertyHoldingTableViewModel.data.push [...]
    

    最佳答案

    为什么要重新发明轮子? :P

    https://github.com/CogShift/Knockout.Extensions

    关于mvvm - knockout JS - ViewModel 抽象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10448807/

    相关文章:

    javascript - 更新 knockout 可观察数组无法更新剑道多选控件

    asp.net-mvc-2 - 派生对象列表的 MVC2 Modelbinder

    android - ViewModel没有零参数构造函数

    javascript - 为什么一个函数表现得像一个计算函数?

    javascript - knockout bindingHandler 导致 pureComputed 评估延迟

    java - ViewModelProvider Fragment实例化模型

    c# - 将我的 DTO 暴露给认为不正确的 View 吗?

    C# MVVM : Adding new ViewModel (strict non-exposed Model design)

    c# - 使用服务依赖注入(inject)实例化 MyViewModel 时出现 NullReferenceException

    silverlight - 为类/结构的所有成员提高 INotifyPropertyChanged?