Markus Walden
Markus Walden

Reputation: 53

How to extend a mapped knockout viewmodel "on the fly" with additional property?

I'm getting a json object array from my ASP.NET Web API and map it to my knockout viewmodel (ko.observablearray). While binding the model to the document I get an "Unable to process binding" error.

This is because the json dto I get from the API doesen't have the Editable property defined. How can I add it on the fly while mapping? It should be false by default.

Here's the code:

var Accessory = function (id, leftOnPatient, reject, amount, patchNumber, additionalInfo, editable) {
  var self = this;

  self.Id = ko.observable(id);
  self.LeftOnPatient = ko.observable(leftOnPatient);
  self.Reject = ko.observable(reject);
  self.Amount = ko.observable(amount);
  self.PatchNumber = ko.observable(patchNumber);
  self.AdditionalInfo = ko.observable(additionalInfo);
  self.Editable = ko.observable(editable); 
}

function MedicinesAndAccessoriesViewModel() {
  var self = this;

  self.Accessories = ko.observableArray([]);
  self.error = ko.observable();

  function getAllAccessories() {
    ajaxHelper(accessoriesUri, 'GET').done(function (data) {
      ko.mapping.fromJS(data, {}, self.Accessories);     
    });
  };

  getAllAccessories(); 
};

var vm = new MedicinesAndAccessoriesViewModel();
ko.applyBindings(vm, document.getElementById("medicinesAndAccessoriesTab"));

HTML:

<ol class="list-group list_of_items padding-top-15" data-bind="foreach: Accessories">
        <li class="list-group-item">
            <div class="container-fluid">
                <div class="col-md-4">
                    <span data-bind="text: Id, visible: !Editable()"></span> //Here I get the error
....
...
..
.

So, how can I define the Editable(false) property client side for each Accessory loaded from the API? Every other property I get from the dto loaded from the API. Can it be done somehow while mapping?

Upvotes: 1

Views: 455

Answers (1)

Jeroen
Jeroen

Reputation: 63719

You're currently not using the Accessory constructor function anywhere at all, the word occurs only once at its definition in your snippet...

You need to utilize your mapping definition and tell it to map that part of your json correctly, e.g.:

function getAllAccessories() {
    ajaxHelper(accessoriesUri, 'GET').done(function (data) {
        var mappingRules = {
            'accessories': {
                create: function(options) {
                    return new Accessory(
                        options.data.id, 
                        options.data.leftOnPatient, 
                        options.data.reject, 
                        options.data.amount, 
                        options.data.patchNumber, 
                        options.data.additionalInfo, 
                        options.data.editable);
                }
            }
        };

        ko.mapping.fromJS(data, mappingRules, self.Accessories);     
    });
};

This should already make sure the Editable observable is there. You could try to force it into a boolean with !! just in case:

self.Editable = ko.observable(!!editable); 

PS. I recommend making the constructor function slightly less complicated by reducing the number of arguments to one (e.g. data or dto), so that return new Accessory(options.data) will do in the above snippet.

Upvotes: 1

Related Questions