2011-12-29 51 views
33

我正在通過Knockoutjs網站上的映射插件示例工作。將屬性添加到通過使用Knockout JS映射插件創建的視圖模型

這是示例數據。

Knockout JS Mapping Plugin

var data = { 
    name: 'Scott', 
    children: [ 
     { id : 1, name : 'Alice' } 
    ] 
} 

的例子顯示瞭如何覆蓋一個孩子的映射,但我怎麼改變爲基本對象的映射。

例如,如果我想爲Scott添加一個「FavouriteChild」屬性,我該如何去解決它?

我假設我需要在基礎映射上使用create函數,但是我找不到任何地方的語法示例。

var myChildModel = function(data) { 
    ko.mapping.fromJS(data, {}, this); 

    this.nameLength = ko.computed(function() { 
     return this.name().length; 
    }, this); 
} 

var mapping = { 
    'children': { 
     create: function(options) { 
      return new myChildModel(options.data); 
     } 
    } 
} 

var viewModel = ko.mapping.fromJS(data, mapping); 

編輯:從接受的答案下面,我發現這個工作

<span data-bind='text: AdditionalProperty'> 

淘汰賽代碼

var mapping = { 
    create: function (options) { 
     //customize at the root level. 
     var innerModel = ko.mapping.fromJS(options.data); 

     innerModel.AdditionalProperty = 'Hello World'; 

     return innerModel; 
    } 
} 

var viewModel = ko.mapping.fromJS(data, mapping); 

//use this as our model bindings 
ko.applyBindings(viewModel); 

回答

23

您需要使用create方法映射對象本身如:

var mapping = { 
    //customize at the root level. 
    create: function(options) { 
    //first map the vm like normal 
    var vm = ko.mapping.fromJS(options.data); 

    //now manipulate the returned vm in any way that you like 
    vm.someProperty = "test"; 

    vm.someComputed = ko.computed(function() { 
      return vm.first() + " " + vm.last(); 
    }); 

    //return our vm that has been mapped and tweaked 
    return vm; 
    } 
}; 
+6

如何解釋如何,與一個空函數創建演示有關訪問根什麼級別並添加到它。 – 2013-06-10 20:23:48

+0

已更新該函數以顯示在返回結果之前如何映射和處理結果。 – 2014-05-08 20:31:48

+0

我知道這是一個非常古老的問題,但剛剛遇到它我想提出一個建議。映射時使用create回調的代碼示例(在KnockoutJs站點上)不能解釋create方法在映射對象上。瑞恩,如果可以的話,我會要求網站的所有者用上面的代碼替換他們的代碼示例。 – 2017-01-05 14:22:44

13

這是一個延續,基於RP尼邁耶的解決方案

這個回答這個答案在這裏是基於上述,並從他的博客解決方案 - 感謝您的!我想我應該添加一些細節,因爲它解決了何時該數組不是第一級對象。

var data = { 
person: { 
     children: [{ id: 1, firstName: 'Scot', lastName: 'Weise'}] 
    } 
}; 

var mapping = { 
    'children': { 
     create: function(options) { 
      return (new (function() { 
       // setup the computed binding for some reason I had 
       // to use ko.dependentObservable instead of ko.computed 
       // or errors showed up. 
       this.fullName = ko.dependentObservable(function() { 
        return this.firstName() + ' ' + this.lastName(); 
        }, this); 
        ko.mapping.fromJS(options.data, { }, this); 
       })(/* call the ctor here */)); 
      } 
     } 
    }; 

    // Create view model and map the data object to the model. 
    var viewModel = ko.mapping.fromJS(data, {}); 

    // update the viewModel with the mapping object that contains 
    // some a computed property(s) 
    viewModel.person = ko.mapping.fromJS(viewModel.person, mapping); 
    ko.applyBindings(viewModel); 

請注意,該人是第一級對象,子女是該人的子財產。起初,line viewModel.person = ko.mapping.fromJS(viewModel.person,mapping)對我來說並不直觀。

這裏是一個輕微的變化

person對象是可觀察到的是添加或更新後,它最初來自服務器的JSON數據創建的。

var viewModel = {}; 
$(document).ready(function() { 
    var person = getPerson(); 

    // selected person is added to the viewModel 
    viewModel.selectedPerson = ko.observable(person); 
    ko.applyBindings(viewModel); 
}); 

function getPerson() { 
// you would probably pass this into the function as a parameter. 
var person = 
    { 
     name: 'jim', 
     children: [{ id: 1, firstName: 'jane', lastName: 'bob'}] 
    }; 

    var mapping = { 
     'children': { 
      create: function (options) { 
       return (new (function() { 
        // setup the computed binding 
        this.fullName = ko.dependentObservable(function() { 
        return this.firstName() + ' ' + this.lastName(); 
        }, this); 
        ko.mapping.fromJS(options.data, {}, this); 
       })(/* call the ctor here */)); 
      } 
     } 
    }; 

    var result = ko.mapping.fromJS(person, mapping); 
    return result; 
} 

在HTML

最終一些有約束力的代碼,你需要把它放到一些使用在某些時候是這樣的:

<div data-bind="foreach:viewModel.selectedPerson().children"> 
    <span data-bind="text:fullName"></span> 
</div> 

感謝您的幫助!沒有你的博客文章,我無法做到這一點。

3

注意,要對孩子定義其他計算觀測則需要通過另外一套映射選項

var mapping = { 
    create: function(options) { 
    //customize at the root level. 

    var mapping2 = { 
     'children': { 
     create: function(options) { 
      //customize children also 

     } 
     } 
    } 

    //call ko.mapping.fromJS on the options.data as well with further customization 
    ko.mapping.fromJS(options.data, mapping2, this); 
    } 
}; 
+1

我在這裏尋找如何映射嵌套屬性和恕我直言,這是最明顯的例子。如果它包含viewModel的樣本,它對我來說將是一個完整的解決方案。 – 2014-02-13 07:32:09

0

基於由Jason和RP尼邁耶提供的例子另一個例子。

data是我們一個Ajax查詢後得到的,在我們添加兩個嵌套的觀測值(viewModel.weekly.selectedWeekviewModel.monthly.selectedMonth):

var data = { 
     "date": "2017-03-28", 
     "weekly": { 
      "weeks": [ 
       { 
        "id": "201701", 
        "label": "Week 1" 
       }, 
       { 
        "id": "201702", 
        "label": "Week 2" 
       } 
      ] 
     }, 
     "monthly": { 
      "months": [ 
       { 
        "id": "201701", 
        "label": "01/2017" 
       }, 
       { 
        "id": "201702", 
        "label": "02/2017" 
       } 
      ] 
     } 
    } 

    var viewModelMapping = { 
     create: function (options) { 
      return (new (function() { 
       // viewModel root level 
       var mapping2 = { 
        'weekly': { 
         create: function (options) { 
          // viewModel.weekly 
          return new function() { 
           var model = ko.mapping.fromJS(options.data, {}, this); 
           model.selectedWeek = ko.observable(); 
           return model; 
          }; 
         } 
        }, 
        'monthly': { 
         create: function (options) { 
          // viewModel.monthly 
          return new function() { 
           var model = ko.mapping.fromJS(options.data, {}, this); 
           model.selectedMonth = ko.observable(); 
           return model; 
          }; 
         } 
        } 
       }; 

       ko.mapping.fromJS(options.data, mapping2, this); 
      })()); 
     } 
    }; 


    var viewModel = ko.mapping.fromJS(data, viewModelMapping); 
    ko.applyBindings(viewModel);