coderenaissance / knockout.viewmodel

The knockout viewmodel plugin is the fastest, smallest, cleanest, most flexible way to create a knockout viewmodel.
http://coderenaissance.github.com/knockout.viewmodel
105 stars 27 forks source link

Question on using json array rather than json object with array as a property #34

Closed kevinmcphail closed 11 years ago

kevinmcphail commented 11 years ago

Hi, sorry to post this in issues but I was not sure where to post questions. I am just getting started with knockout and saw that ko.viewmodel is probably replacing ko.mapping. I read through you examples page and decided to give it a try. I ran into an issue trying to work with a json array i get back from the server. Unlike in the examples I am getting an array and not an object with an array as one of its properties. I tried to follow your example and I can get the page to load without any binding errors but I am not seeing the expected behavior. In the html I am not sure how to bind to the delete button. I have tried $parent.Delete and Delete. With just Delete the page bindings fail on page load and with $parent.Delete they complete successfully but clicking the button has no effect on the observable isdeleted. So what is the appropriate way to bind a button to deleted?

Second question, can you show an example of a more complex mapping? For example in the model below I need to add an observable through extend and I also need to intercept and create a javascript date object for the releasedate.

var initialData=[{"Id":5,"Name":"Central","Current":0.58,"ReleaseDate":"2013-05-13T00:00:00"},
{"Id":6,"Name":"Southwest","Current":1.45,"ReleaseDate":"2013-05-10T00:00:00"}];

ko.viewmodel.options.logging = true;

        var options = {
            extend: {
                "{root}[i]": function(zone){
                    zone.isDeleted= ko.observable(false);
                    return zone;
                },
                "{root}": function(root) {
                    root.Delete = function(zone) {
                        zone.isDeleted(true);
                    };
                }
            }
        };

        var viewmodel = ko.viewmodel.fromModel(initialData, options);

```HTML
<table class="table table-striped">
        <tbody data-bind="foreach: viewmodel">
            <tr>
                <td data-bind="text:Id"></td>
                <td data-bind="text:Name"></td>
                <td><input class="input-small" type="number" step="any" data-bind='value: Current'></td>
                <td><input class="input-medium" type="date" placeholder="mm/dd/yyyy" data-bind='datevalue:ReleaseDate'></td>
                <td data-bind="text:ReleaseDate"></td>

                <td data-bind="text:isDeleted"></td>
                <td><button class="btn btn-primary noprint" data-bind='click:$parent.Delete' >Delete</button></td>
            </tr>
        </tbody>
    </table>
coderenaissance commented 11 years ago

For issue 1 you can try this:

tbody data-bind="foreach: $root"

Which is a reference to the root object which is your array. A better alternative is:

var model = { Zones: initialData}; //code removed for brevity var viewmodel = ko.viewmodel.fromModel(model, options);

and then:

tbody data-bind="foreach: Zones"

I would normally say that having your root as an object was personal preference but I had trouble getting your example running otherwise, and I didn't have time to fight with it, though you're welcome to try. Here is a jsFiddle that has everything working:

http://jsfiddle.net/RhnVG/

Make sure you remember to call ko.applyBindings. I didn't see this in your code but it was probably removed for brevity.

coderenaissance commented 11 years ago

This should work: http://jsfiddle.net/8yjaE/ but it can't find Delete on $root even though I tested in the console to make sure it was there. This is a problem with knockout and is shown clearer by this example: http://jsfiddle.net/5EZQC/. I have reported this as a knockout issue: https://github.com/knockout/knockout/issues/999