动态项目 ViewModel 淘汰赛

Dynamic Item ViewModel Knockout

我有很多 (KnockOut) 视图模型,它们从休息服务获取数据,然后填充 "item" 非常简单的视图模型,只包含来自 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();
            }
        });
    }
}

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

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

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

有。如果你的对象比较简单,没有嵌套,可以自己写代码映射:

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>