Search code examples
knockout.jsknockout-mapping-plugin

Knockout mapping options not excluding additional properties from source object


In my view model I've declared an observable property called 'MappedItem':

var MyViewModel = function () {
    var $scope = this;

    ...

    $scope.MappedItem = ko.observable();

    ...

I need to map an object called 'item', which has several properties. I only need three of them in my mapped observable. So, here's what I'm trying:

var mapping = {'include': ["recid", "Program", "Station"]};
$scope.MappedItem = ko.mapping.fromJS(item, mapping);

This works but my mapping rules are ignored and I end up with 'MappedItem' having a lot of useless observable properties.

To get what I want I have to explicitly declare every property I don't want mapped in the 'ignore' attribute of the mapping options object:

var mapping = {
   'ignore': ["AdLength", "Affiliate", ... (MANY OTHER PROPERTIES MORE) ],
   'include': ["recid", "Program", "Station"]
};
$scope.MappedItem = ko.mapping.fromJS(item, mapping);

Another approach that I've tried:

ko.mapping.fromJS(item, mapping, $scope.MappedItem);

But this does not map any of 'item' properties to 'MappedItem' at all.

Shouldn't I be able to map the needed properties only using the 'include', without having to explicitly declare them in the 'ignore' option?


Solution

  • The 'include' array is only useful whenever you are mapping an item more than once. For instance, let's say you have mapped an item. Later on, you map the same item again, except this time, three additional properties have been added to the item. By default, Knockout would ignore those additional three properties because they weren't there the first time. By customizing the 'include' array, you can force Knockout to map those additional three properties.

    Unfortunately the 'include' array does not act as a whitelist like you were expecting.

    As a work around, you can customize the mapping object using the 'create' function, and only include the properties that you desire:

    Javascript

    var item = {
      'recid': '0',
      'Program': 'TestProgram',
      'Station': 'TestStation',
      'ignoredProperty': 'test'
    };
    
    var mapping = {
      create: function(options) {
        var orig = options.data;
        var filtered = {
          'recid': ko.observable(orig.recid),
          'Program': ko.observable(orig.Program),
          'Station': ko.observable(orig.Station)
        };
        return filtered;
      }
    };
    
    var myViewModel = function() {
      var $scope = this;
      $scope.MappedItem = ko.mapping.fromJS(item, mapping);
    };
    
    var vm = new myViewModel();
    ko.applyBindings(vm);
    

    Fiddle: https://jsfiddle.net/dw1284/g8ca78kc/