开发者

Adding new value to nested observable array created with knockout.mapping plugin and knockoutjs

So close to getting this to work as expected. I am getting data from a JSON request and then using the mapping plugin to map it. I want to add new values to a nested array on a click binding.

Right now in my code I am getting an error that addPoint is not defined.

View:

<table>
    <tbody data-bind='template: {name: "statRowTemplate", foreach: stats }'></tbody>
</table>

<script id="statRowTemplate" type="text/html">
    {{if type() != "column"}}
    <tr>
            <td><label>Name: </label><input data-bind="value: name" /></td>
            <td>
                    <label>Plot Points: </label><ul class="list-plot-points" data-bind="template: {name: 'dataTemplate' , foreach: data}"></ul>
                    <button data-bind="click: addPoint">Add Point</button>
                </td>

    </tr>
    {{/if}}
</script>
<script type="text/html" id="dataTemplate">         
<li>
        <input data-bind="value: val" />
</li>
</script>

<button data-bind="click: saveChanges">Save Changes</button>

View Model

var viewModel = {};

$.getJSON('data-forecast-accuracy.json', function(result) {

    function mappedData(data) {
        this.val = data;
    }

    //override toJSON to turn it back into a single val
    mappedData.prototype.toJSON = function() {
       return parseInt(ko.utils.unwrapObservable(this.val), 10);  //parseInt if you want or not 
    };

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

    viewModel.stats = ko.mapping.fromJS(result, mapping);

    vi开发者_开发技巧ewModel.addPoint = function() {
    this.stats.data.push(new mappedData(0));
    }

    viewModel.saveChanges = function() {

        var unmapped = ko.mapping.toJSON(viewModel.stats);
        //console.log(unmapped);
        $.post('save-changes.php', {data: unmapped})
        .success(function(results) { console.log("success")})
        .error(function() {  console.log("error"); })
        .complete(function() {  console.log("complete"); });
    }

    ko.applyBindings(viewModel);
});

The JSON:

[{"type":"spline","marker":{"symbol":"diamond"},"name":"Cumulative","data":[10,17,18,18,16,17,18,19]},{"type":"spline","marker":{"symbol":"circle"},"name":"Monthly","data":[10,22,20,19,8,20,25,23]}]

I was able to adjust this jsfiddle from an earlier response to add points to the single array. I need to find a way to implement this across the generated mapping.

http://jsfiddle.net/vv2Wx/1/


Where you are binding against addPoint the context is an item in stats rather than your view model.

If viewModel has global scope, then you can do: click: viewModel.addPoint. You will want to make sure that this is set correctly in your addPoint method. Easiest way is to bind the method to your viewModel variable like:

viewModel.addPoint = function() {
    this.stats.data.push(new mappedData(0));
}.bind(viewModel);

If viewModel does not have global scope, then you can pass it in via templateOptions. This would be like:

<tbody data-bind='template: {name: "statRowTemplate", 
                             foreach: stats, templateOptions: { add: addPoints } }'></tbody>

Then, call it like: <button data-bind="click: $item.add">Add Point</button>

Finally, if you are using KO 1.3 beta, then you can do: <button data-bind="click: $root.addPoint">Add Point</button>


The reason you're getting "addPoint is not defined" error is because you're inside a template for a child property of the view model. Inside the template, the binding context is a stat object, not your view model.

Bottom line: Knockout is looking for a stat.addPoint function, which doesn't exist, so you get the error.

What you probably want to do is reference the parent binding context, your view model. In KO 1.3 beta, you can access parent binding contexts like this:

<button data-bind="click: $.parent.addPoint">Add Point</button>

If you're stuck on an old version of Knockout that doesn't provide access to the parent binding context, let me know, there are some additional options, such as making your view model globally accessible, then just binding to that fully qualified name.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜