Knockout.js agregando nuevos elementos a la matriz

I am having trouble being able to programatically add elements to an observable array contained within a table of data.

Each row of the table has a different array that I wish to affect.

El HTML tiene este aspecto:

<div class='liveExample'>     
<h2>Cases</h2>
<div id='contactsList'>
    <table class='contactsEditor'>
        <tr>
            <th>Case Number</th>
            <th>Stage</th>
            <th>Users</th>
            <th>Ids</th>
        </tr>
        <tbody data-bind="foreach: appearances ">
            <tr>
                <td>
                    <input data-bind='value: caseNumber' />
                </td>
                <td><input data-bind='value: caseStage' /></td>
                <td> 
                    <ul  data-bind="foreach: subjects">
                        <li style="list-style-type:none;"><label data-bind="text: Name"/></li>    
                    </ul>   
                </td>
                <td>
                    <table>
                        <tbody data-bind="foreach: ids">
                            <tr>
                                <td><input data-bind='value: $data' /></td>
                                <td><a href='#' data-bind='click: $root.removeId'>Delete</a></td>
                            </tr>
                        </tbody>
                    </table>
                    <a href='#' data-bind='click: $root.addId'>Add number</a>
                </td>
            </tr>
        </tbody>
    </table>
</div>     
<p>
    <button data-bind='click: save, enable:appearances().length > 0'>Save to JSON</button>
</p>     
<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>    

The data and JavaScript looks like this:

enter code here
var initialData = [{
"Number": "12000009",
"Stage": "Inital",
"Subjects": [{
    "Name": "Andrew McAdam"},
{
    "Name": "Patrick Brown"}],
"Ids": [1]},
{
"Number": "12000010",
"Stage": "Inital",
"Subjects": [{
    "Name": "John Smith"}],
"Ids": [2, 3]},
{
"Number": "12000011",
"Stage": "Inital",
"Subjects": [{
    "Name": "James Bonner"}],
"Ids": [4]},
{
"Number": "12000012",
"Stage": "Processed",
"Subjects": [{
    "Name": "Henrik Dalgleish"}],
"Ids": [5]}]

var AppearancesModel = function(appearances) {
var self = this;
self.appearances = ko.observableArray(ko.utils.arrayMap(appearances, function(appearance) {
    return {
        caseNumber: appearance.Number,
        caseStage: appearance.Stage,
        subjects: ko.observableArray(appearance.Subjects),
        ids: ko.observableArray(appearance.Ids)
    };
}));

self.addId = function(appearance) {
    appearance.ids.push("");
};

self.removeId = function(id) {
    $.each(self.appearances(), function() {
        this.ids.remove(id)
    })
};

self.save = function() {
    self.lastSavedJson(JSON.stringify(ko.toJS(self.appearances), null, 2));
};

self.lastSavedJson = ko.observable("")
}

ko.applyBindings(new AppearancesModel(initialData));​

The problem I have is that after the clicking the Add button and entering a value the value in the array is empty string (the value I added when creating the new array element).

I think the issue is that I am adding the new item to the array before I have a value, but I thought that it would be bound to the new inpute so when I executed the Save function the new value would be reflected.

The JsFiddle of the above is at http://jsfiddle.net/amcgoldrick/3h9GZ/

Muchas Gracias

Andy

preguntado el 31 de julio de 12 a las 11:07

Following the advice from @Mark-Robinson, I added the following to map the original ids ids: ko.observableArray(ko.utils.arrayMap(appearance.Ids, function(id) { return ko.observable(id)})) and my original ids are displayed. The issue I have now is that 'appearance.ids.push({id: ko.observable("")});' adds an object with an id property to an array of integers. -

1 Respuestas

The values that you add to your ids observableArray are not observable therefore the binding is only one way. If you want to update the value inside the observableArray then you need to make the elements inside the observableArray observable.

Así que en lugar de:

self.addId = function(appearance) {
    appearance.ids.push("");
};

Tendrías:

self.addId = function(appearance) {
    appearance.ids.push({id: ko.observable("")});
};

Ver http://jsfiddle.net/5wKjk/3/ for a working example. (I've not added code to map your existing ids as I just wanted to demonstrate the principles involved and didn't have time).

Respondido 31 Jul 12, 11:07

Excellent, that helps me get a bit closer. - AndyMcG

El uso de appearance.ids.push({id: ko.observable("")}); cause an object with a property id y un valor de "" to be added. I can't workout how to add a simple integer. - AndyMcG

Have you looked at the fiddle? In the markup I have changed the bindings so they deal with the 'id' property. Also, if you want to bind your value to a input box then when you enter something into the textbox knockout will always write a string back into your model. Therefore, I wouldn't be concerned with whether your value is an integer or a string. After all, 1 == "1" in JavaScript. - Mark Robinson

Sorry Mark, I got a bit mixed up with my JSFiddle windows. What you supplied was perfect. The code required to map the existing ids is ids: ko.observableArray(ko.utils.arrayMap(appearance.Ids, function(x) { return { id: x }; })) - AndyMcG

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.