AndyMcG
AndyMcG

Reputation: 3

Knockout.js adding new items to array

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.

The HTML looks like this:

<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/

Thanks

Andy

Upvotes: 0

Views: 6031

Answers (1)

Mark Robinson
Mark Robinson

Reputation: 13278

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.

So instead of:

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

You would have:

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

See 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).

Upvotes: 3

Related Questions