【问题标题】:Dynamic Item ViewModel Knockout动态项目 ViewModel 淘汰赛
【发布时间】:2017-09-22 08:10:19
【问题描述】:

我有很多 (KnockOut) 视图模型,它们从 REST 服务获取数据,然后填充非常简单且仅包含来自 REST 接口的字段的“项目”视图模型。

我只是想知道是否有一种方法可以不必定义项目视图模型,而是以某种方式将它们动态创建为对象(其中每个属性都是可观察的)。

所以在下面的示例中,我希望没有“ItemViewModel”,而只是在 AddItems 函数中说明它应该基于数据创建一个对象并使每个条目都成为 ko.observable。传递的“itemName”然后包含“ItemViewModel1”(或在其他调用“ItemViewModel2”...等)。

例如如果 Json Rest 输入有一个字段“LAST_NAME”,它将添加 self.LAST_NAME = ko.observable()" 填充该值等(所以我仍然可以在视图中引用它)。

var ItemViewModel1 = function (data) {
    var self = this;
    self.PAR1 = ko.observable(data.PAR1) 
    self.PAR2 = ko.observable(data.PAR2) 
    self.PAR3 = ko.observable(data.PAR3) 
    self.PAR4 = ko.observable(data.PAR4) 
    // … etc
}
var MasterViewModel1 = function (data) {
    var self = this;
    ReportBaseViewModel.call(self)
}

var ReportBaseViewModel = function () {
    var self = this;

    /* commonly used vars */
    self.report = ko.observable();
    self.searchedCallBackFunction = ko.observable();
    self.items = ko.observableArray();
    self.selecteditem = ko.observable();
    self.selectedPerson = ko.observable();

    /* method: print */
    self.PrintEventHandler = function (data) { window.print(); };

    /* method: add items to array */
    self.AddItems = function (data) {
        var newitems = ko.utils.arrayMap(data, function (item) {
            c = new window[self.itemname](item);
            return c;
        });
        self.items(newitems);
    };

    /* eventhandler: select one item */
    self.SelectEventHandler = function (item) {
        selecteditem(item);
    };

    self.GetReport = function (selectedPerson, viewContainer, url, itemName) {
        self.selectedPerson(selectedPerson);
        self.itemname = itemName;
        var jqxhr = $.ajax({
            url: url,
            type: "GET"
        }).done(function (data, textStatus, jqXHR) {
            if (data != null) {
                self.AddItems(data);
                $('#' + viewContainer).show();
                document.getElementById(viewContainer).scrollIntoView();
            }
        }).fail(function (jqXHR, textStatus, errorThrown) {
            console.log('fail' + JSON.stringify(jqXHR));
            toastr.options = {
                "closeButton": true,
                "debug": false,
                "newestOnTop": false,
                "progressBar": false,
                "positionClass": "toast-top-right",
                "preventDuplicates": false,
                "onclick": null,
                "showDuration": "0",
                "hideDuration": "1000",
                "timeOut": "0",
                "extendedTimeOut": "0",
                "showEasing": "swing",
                "hideEasing": "linear",
                "showMethod": "fadeIn",
                "hideMethod": "fadeOut"
            };
            toastr["error"]("ERROR");
        }).always(function (jqXHR, textStatus, errorString) {
            if (typeof self.searchedCallBackFunction() === 'function') {
                self.searchedCallBackFunction();
            }
        });
    }
}

【问题讨论】:

    标签: javascript knockout.js viewmodel


    【解决方案1】:

    有。如果你的对象很简单并且没有嵌套,你可以自己编写代码来映射它们:

    var someJSON = '{ "firstName": "John", "lastName": "Doe" }';
    
    var makeSimpleVM = function(obj) {
      // Return a new object with all property
      // values wrapped in an observable
      return Object
        .keys(obj)
        .reduce(function(vm, key) {
          vm[key] = ko.observable(obj[key]);
          return vm;
        }, {});
    };
    
    var myVM = makeSimpleVM(JSON.parse(someJSON));
    
    console.log(ko.isObservable(myVM.firstName)); // true
    console.log(myVM.firstName()); // John
    
    myVM.firstName("Jane");
    console.log(myVM.firstName()); // Jane
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

    我认为通读这个幼稚的实现很重要:它让你明白为什么使用现成的插件可能是一个更好的主意

    一旦您的服务器端代码包含数组、嵌套视图模型或您不想映射的任何属性,您就会遇到问题。 ko.mapping 插件已经为你解决了这些问题。它将数组映射到ko.observableArrays 并让您指定映射策略。

    var someJSON = '{ "firstName": "John", "lastName": "Doe" }';
    
    // Let's use the library this time
    var myVM = ko.mapping.fromJS(JSON.parse(someJSON));
    
    console.log(ko.isObservable(myVM.firstName)); // true
    console.log(myVM.firstName()); // John
    
    myVM.firstName("Jane");
    console.log(myVM.firstName()); // Jane
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

    【讨论】:

      【解决方案2】:

      您可以尝试使用映射插件或 Json 函数,具体取决于您要查找的内容。我认为您正在寻找的是映射插件:

      http://knockoutjs.com/documentation/plugins-mapping.html

      http://knockoutjs.com/documentation/json-data.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-16
        • 2013-01-09
        • 1970-01-01
        相关资源
        最近更新 更多