2012-05-04 3 views
2

* UPDATE * (смотри ниже)KnockoutJS - ViewModel Abstracion

Я понимаю основы KnockoutJS. При создании таблицы viewmodel, можно было бы использовать <tr data-bind="foreach: rows">

Теперь я пытаюсь абстрагировать таблицу viewmodel, чтобы я мог создавать несколько таблиц с одинаковым поведением (сортировка, редактирование, разбиение на страницы и т. Д.). Так что я стремлюсь к что-то вроде этого:

HTML

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

Главная ViewModel

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

Моя первая попытка была имитируя пример [simpleGrid] плагин (@http://knockoutjs.com/examples/resources/knockout.simpleGrid.1.3.js), которые используют файлы KnockoutJS для примера [Paged grid].

Я не уверен, но я думаю, что базовая концепция абстракции в этом плагине не представлена ​​хорошо. Когда я попытался включить класс css в элементы <th>: <th class="col col-id">, <th class="col col-name"> и т. Д., Я выяснил, что это было непросто (невозможно?) С использованием атрибутов data-bind.

Атрибуты data-bind, вероятно, не должны использоваться для этого материала, поскольку эти классы не изменятся - они являются частью более высокого уровня абстракции: мы должны фактически вставлять эти классы с помощью системы шаблонов jQuery.tmpl или Underscore , Но потом я получил сообщение об ошибке [Эта система шаблонов не поддерживает использование привязки foreach] (или что-то в этом роде). Поэтому

Моя вторая попытка была реализовать абстракцию, как это должно быть реализовано: со свойствами таблицы (колонны и т.д.) на другой «уровень абстракции», чем данные таблицы:

  1. Создание основной <tr data-bind="foreach: rows"> HTML при создании новой конкретной модели табличного представления с использованием «абстрактного» шаблона - это я просто сделал с помощью _.template Underscore.
  2. Пусть эта конкретная модель просмотра использует вышеуказанный 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 сообщает мне, что привязки перепутаны в html для моей конкретной модели (которая вставлена ​​в <div>.Если я вставляю строки [A] и [B], то она работает для начальных данных ([D]), но после этого не отвечает.

Все в порядке: я довольно смущен про что-то простое, как абстрагирование вида. Разве нет стандартного решения для этого в KnockoutJS? (Я искал googled, но не мог найти ничего ...) Или я просто испортил это сам (вполне возможно)? ;)

* UPDATE *

Я решил проблему (но, возможно, это не самый лучший/хорошо на всех - каково ваше мнение), для полноты ради:? (Сокращенный вариант - конечно, вы, вероятно, также хотите наблюдать строки по отдельности и т.д ..)

HTML (да, это целенаправленно строка передается связывания обработчика)

<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 [...] 
+0

Что вы имеете в виду под "после того, что не отвечает"? Вы делаете 'var vm = new ViewModel()' и 'vm.groupTable.data (newData);'? – freakish

+0

На самом деле (!) Я делал 'vm.groupTable.data(). Push' ... Но теперь я понимаю, насколько глупым это было;) –

+0

Да, но вы действительно можете сделать' vm.groupTable.data.push'. Без '()' должно работать как ожидалось. :) – freakish

ответ

Смежные вопросы