dynamic column and rows with knockoutjs

孤人 提交于 2019-11-30 16:58:45
function ViewModel() {
    var self = this;

    self.invtype = "@ViewBag.invtype";
    self.columns = ko.observableArray();
    self.rows = ko.observableArray();

    self.load = function () {
        $.when(
            $.get("@Url.Content('~/api/inventories/')" + self.invtype),
            $.get("@Url.Content('~/api/')" + self.invtype)
        )
        .then(function (columnResponse, rowResponse) {
            var columnDefs = columnResponse[0],
                rowDefs = rowResponse[0],
                columnMapping = {
                    key: function (data) {
                        return ko.utils.unwrapObservable(data.ColumnName);
                    }
                },
                rowMapping = {
                    key: function (data) {
                        return ko.utils.unwrapObservable(data.Id);
                    }
                };

            ko.mapping.fromJS(columnDefs, columnMapping, self.columns);
            ko.mapping.fromJS(rowDefs, rowMapping, self.rows);
        });

        return self;
    };
}

Notes:

  • Using jQuery's .when() and .then() ensures that view model processing occurs only after both HTML requests have returned successfully. See jQuery's documentation on the topic.
  • The key function in the custom mapping ensures that when you call load() again then only the appropriate parts of your view model get an update. Otherwise ko.mapping.fromJS will replace the entire observable, resulting in a complete re-build of the affected part of your page. Specifying key allows partial page updates, so use a unique property of your data here. (If you don't plan on refreshing data from the server during page life time this step might not be necessary.)
  • The use of ko.utils.unwrapObservable() is mandatory because during a load operation key will be used on both the existing view model contents and the server response, so for example data.ColumnName could be an observable or a raw value.
  • Be sure to read through the advanced section of the mapping plugin documentation, you might find other helpful bits.

HTML

<table>
    <thead>
        <tr data-bind="foreach: $root.columns">
            <th data-bind="text: ColumnName"></th>
        </tr>
    </thead>
    <tbody data-bind="foreach: $root.rows">
        <tr data-bind="foreach: $root.columns">
            <td data-bind="text: $parent[ColumnName()]"></td>
        </tr>
    </tbody>
</table>

Notes:

  • The only place where $root is actually necessary is in the <tr data-bind="foreach: $root.columns"> binding. The others are just included for consistency.
  • $parent refers to the row from foreach: $root.rows.
  • The parentheses in $parent[ColumnName()] are necessary because ColumnName is an observable and in a complex binding they are not unwrapped automatically.

The whole thing can be seen here: http://jsfiddle.net/Tomalak/A6T8p/
and here (extended version): http://jsfiddle.net/Tomalak/A6T8p/1

rewrote my self.load

         self.Load = function () {
            $.ajax({
                url: "@Url.Content("~/api/")"+self.invtype, 
                type: 'GET',
                dataType: 'JSON',
                success: function (data) {
                    // Map the returned JSON to the View Model  
                    ko.mapping.fromJS(data,{}, self.items);   
                }
            });
            $.ajax({
                url: "@Url.Content("~/api/inventories/")"+self.invtype,
                type: 'GET',
                dataType: 'JSON',
                success: function (data) {
                    // Map the returned JSON to the View Model  
                    $.each(data,function(i,dt){ 
                        self.TBStruct.push(new ColName(dt));
                    }); 
                }
            });
            return self;
        };

output with iteration below

        <thead>
        <tr data-bind="foreach: TBStruct">
        <th data-bind="text: HeaderName,visible: SystemField == -1 || Visible" ></th>
        </tr>
        </thead>
        <tbody data-bind="foreach: items " >
        <tr data-bind="foreach: $root.TBStruct, click:function() { alert('me');}" id="rowData">
         <td data-bind="text: $parent[ColumnName],visible: SystemField == -1 || Visible" ">
         </td> 
         </tr> 
            </tbody>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!