wrufesh
wrufesh

Reputation: 1406

Cannot map function in view model with json data knockout mapping

My viewmodel is like this:

var viewModel = function(){
var self = this;
self.title = ko.observable('Hello World');
self.rows = ko.observableArray();

self.on_click = function(){
    alert('Hello World');
    var data = [
        {
            id : 1,
            x : 1,
            y : 2,
            z : 3,
        },
        {
            id : 2,
            x : 4,
            y : 5,
            z : 6,
        },
        {
            id : 3,
            x : 7,
            y : 8,
            z : 9,
        }
    ];
    self.rows(ko.unwrap(ko.mapping.fromJS(data, viewModelRow)));
    alert(self.rows());

};
};

var viewModelRow = function(){
    var self = this;
    self.id = ko.observable();
    self.x = ko.observable();
    self.y = ko.observable();
    self.z = ko.observable();
    self.mthd = function(){
        alert('Just Clicked');
    };
};
vm = new viewModel();
ko.applyBindings(vm);

My html is like this:

<body>
<h1 data-bind="text:title"></h1>
<div data-bind="foreach: rows">
    <table>
        <tr>
        <td data-bind="text : id"></td>
        <td data-bind="text: x"></td>
        <td data-bind="text: y"></td>
        <td data-bind="text: z"></td>
            <td><button type="button" data-bind="click: mthd">btn</button></td>
        </tr>
    </table>
</div>
<button type="button" data-bind="click: on_click">button</button>
</body>

When mapping is performed with data on viewModelRow view model then it throws the error saying

ReferenceError: mthd is not defined

I want all json data mapping with viewModelRow along with method named mthd define in viewModelRow. Please help. JSFIDDLE LINK: http://jsfiddle.net/enabqm3d/5/

Upvotes: 0

Views: 501

Answers (2)

super cool
super cool

Reputation: 6045

As scenario looks simple you can achieve it using .arrayMap mapping to the function which having observables

viewModel:

var viewModelRow = function (param) {
    var self = this;
    self.id = ko.observable(param.id);
    self.x = ko.observable(param.x);
    self.y = ko.observable(param.y);
    self.z = ko.observable(param.z);
    self.mthd = function () {
        alert('im clicked')
    };
};

var viewModel = function () {
    var self = this;
    self.title = ko.observable('Hello World');
    self.rows = ko.observableArray();
    self.on_click = function () {
        var converted = ko.utils.arrayMap(data, function (item) {
            return new viewModelRow(item); // key part here
        })
        self.rows(converted); // assigning after converting everything into observables
    };
};
ko.applyBindings(new viewModel());

working fiddle up here

Upvotes: 1

Tomalak
Tomalak

Reputation: 338158

You are using the mapping plugin in the wrong way. The fromJS function takes three arguments:

fromJS(data, mappingDefinition, mappingTarget);

The mappingDefinition defines the rules that should be executed during the mapping, for example, to create certain objects from the data, as shown here:

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

    self.title = ko.observable('Hello World');
    self.rows = ko.observableArray();
    self.init = function(){
        var data = {
            rows: [
                {id : 1, x : 1, y : 2, z : 3,},
                {id : 2, x : 4, y : 5, z : 6,},
                {id : 3, x : 7, y : 8, z : 9,}
            ]
        };

        ko.mapping.fromJS(data, {
            rows: {
                create: function (options) {
                    return new ViewModelRow(options.data);
                }
            }
        }, self);
    };
};

var ViewModelRow = function(data){
    var self = this;

    // think whether these properties really need to be observable
    self.id = ko.observable(data.id);
    self.x = ko.observable(data.x);
    self.y = ko.observable(data.y);
    self.z = ko.observable(data.z);
    self.mthd = function(){
        alert('Just clicked ' + self.id() );
    };
};

var vm = new ViewModel();
ko.applyBindings(vm);
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<h1 data-bind="text:title"></h1>

<div data-bind="foreach: rows">
  <table>
    <tr>
      <td data-bind="text: id"></td>
      <td data-bind="text: x"></td>
      <td data-bind="text: y"></td>
      <td data-bind="text: z"></td>
      <td><button type="button" data-bind="click: mthd">btn</button></td>
    </tr>
  </table>
</div>

<button type="button" data-bind="click: init">init viewmodel</button>

Read through the documentation, it's not even a lot to read.

Upvotes: 0

Related Questions