3

I am using John Papa's SPA source code to make my own app. I now have a problem where I want to add a new object to my observable array. I am finding this difficult because in my code there are loops for number of offices and contacts. So when I add an element to my KO observable array I want to add it to the right place.

 <div data-bind="foreach: agency">
        <div data-bind="foreach: offices">
            <button class="btn btn-info btn-force-refresh pull-right" data-bind="event: { click: $root.addOffice }">Add a new office</button>
            <table>
                <tr>
                    <td>
                        <h1>Offices</h1>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div>
                            <table>
                                <tr>
                                    <td>Address1</td>
                                    <td>Address2</td>
                                    <td>Address3</td>
                                    <td>Address4</td>
                                </tr>
                                <tr>
                                    <td>
                                        <input data-bind="value: address1, event: { change: $root.cacheForm }" />
                                    </td>

                                    <td>
                                        <input data-bind="value: address2, event: { change: $root.cacheForm }" />
                                    </td>

                                    <td>
                                        <input data-bind="value: address3, event: { change: $root.cacheForm }" />
                                    </td>

                                    <td>
                                        <input data-bind="value: address4, event: { change: $root.cacheForm }" />
                                    </td>
                                </tr>

                                <tr>
                                    <td>Address5</td>
                                    <td>faxNumber</td>
                                    <td>postCode</td>
                                    <td>telephoneNumber</td>
                                </tr>
                                <tr>
                                    <td>
                                        <input data-bind="value: address5, event: { change: $root.cacheForm }" />
                                    </td>
                                    <td>
                                        <input data-bind="value: faxNumber, event: { change: $root.cacheForm }" />
                                    </td>
                                    <td>
                                        <input data-bind="value: postCode, event: { change: $root.cacheForm }" />
                                    </td>
                                    <td>
                                        <input data-bind="value: telephoneNumber, event: { change: $root.cacheForm }" />
                                    </td>
                                </tr>
                            </table>
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div class="article-counter">
                            <address data-bind="text: contacts().length"></address>
                            <address>found</address>
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <button data-bind='click: $root.addContact'>Add Contact</button>
                        <div data-bind="foreach: contacts">
                            <table>
                                <tr>
                                    <td>Title</td>
                                    <td>First Name</td>
                                    <td>Surname</td>
                                </tr>
                                <tr>
                                    <td>
                                        <input data-bind="value: title, event: { change: $root.cacheForm }" readonly="true"  />
                                    </td>
                                    <td>
                                        <input data-bind="value: firstName, event: { change: $root.cacheForm }" readonly="true"  />
                                    </td>
                                    <td>
                                        <input data-bind="value: surName, event: { change: $root.cacheForm }" readonly="true" />
                                    </td>
                                    <td>
                                        <a href='#' data-bind='click: $root.removeContact' style="color:blue">Remove</a>

                                    </td>
                                </tr>
                            </table>
                        </div>
                    </td>
                </tr>
            </table>
        </div>
    </div>

When I click:

<button data-bind='click: $root.addContact'>Add Contact</button>

I want a new tr with empty textboxes for the user to input data.

define(['services/datacontext'], function (dataContext) {
    var initialized = false;
    var agency;

    var save = function (agency, myStoredValue) {
        // Clear Cache because user submitted the form. We don't have to hold onto data anymore.
        localStorage.setItem('Agency', null);
        localStorage.setItem('Offices', null);
        localStorage.setItem('Contacts', null);
        return dataContext.saveChanges(agency);
    };

    var vm = { // This is my view model, my functions are bound to it. 
        //These are wired up to my agency view
        activate: activate,
        agency: agency,
        brands: brands,
        title: 'agency',
        refresh: refresh, // call refresh function which calls get Agencies
        save: save,
        cacheForm: cacheForm,
        addOffice: addOffice,
        addBrand : addBrand,
        removeBrand: removeBrand,
        addContact: addContact,
        removeContact: removeContact
    };
    return vm;



     function addContact(office) { // Passing in object array of agency. We no it contains correct office and agency ID

    var agencyID = office.agencyID._latestValue;

    office.contacts._latestValue.push({
        agencyID: office.agencyID._latestValue,
        emailAddress: "",
        firstName: "",
        jobName: "",
        office: "",
        OfficeID: office.officeID._latestValue,
        personID: "",
        surName: "",
        title: ""
    });
}             
});    

So I am pushing a new element to

office.contacts._latestValue

In function

function addContact(office)

But I get this error:

Unhandled exception at line 9423, column 13 in http://localhost:13762/scripts/breeze.debug.js

0x800a01b6 - JavaScript runtime error: Object doesn't support property or method 'getProperty'

Does anyone know a good way of adding new arrays to a multidimensional ko observable array?

1 Answer 1

3

Never use _latestValue, that is what Knockout uses behind the scenes for data-binding purposes. It is a property you should never try to get or set.

To add an item to an observableArray, like the documentation states, simply use .push(); You also should consider creating a model of whatever your object being pushed is.

function contact(id, email, firstname, lastname, jobname, title) {
    var self = this;
    self.Id = ko.observable(id);
    self.Email = ko.observable(email);
    self.FirstName = ko.observable(firstname);
    self.LastName = ko.observable(lastname);
    self.JobName = ko.observable(jobname);
    self.Title = ko.observable(title);
}

function addContact(office) {

    var agencyID = office.agencyID;

    office.contacts.push(new contact(agencyID, "", "", "", "", "", ""));
}       
Sign up to request clarification or add additional context in comments.

1 Comment

this answer got me halfway. If you need to track the observables in the array check out this answer: link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.