add object to observable array using knockout
Asked Answered
N

3

8

For some reason i'm having trouble passing an object to observable array.

function CalendarViewModel() {
var self = this;

self.event = {
    name : ko.observable(""),
    adress : ko.observable(""),
    startTime : ko.observable(""),
    endTime : ko.observable("")
}

self.events = ko.observableArray([

])

self.addEvent = function (event) {

    self.events.push(event);

    alert(self.events.length)
    alert(self.events[0].name());
 }

my view:

 <fieldset class="add-event-fieldset">
            <div data-bind="with: event">
                <legend>Add Event</legend>
                <div style="text-align: center;">
                    <label class="title-label">What </label>
                </div>
                <div>
                    <label>Name: </label>
                    <input type="text" name="whatTxtBox" data-bind="value: name" />
                </div>
                <div>
                    <label>Where: </label>
                    <input type="text" name="whereTxtBox" data-bind="value: adress" />
                </div>
                <div style="text-align: center;">
                    <label class="title-label">When </label>
                </div>
                <div>
                    <label>start: </label>
                    <input type="text" id="startHourTxtBox" data-bind="value: startTime" />
                </div>
                <div>
                    <label>end: </label>
                    <input type="text" id="endHourTxtBox" data-bind="value: endTime" />
                </div>
            </div>

            <input type="hidden" name="" id="hiddenDay" />

            <button id="btnAddNewEvent" data-bind="click: $root.addEvent">+</button>
        </fieldset>

The alerts show that the array is always empty, please explain what i'm doing wrong thanks.

Notability answered 27/4, 2013 at 20:4 Comment(0)
D
13

Your observable array usage e.g self.events.push(event); is correct (because observable array implements push), only your alerts are wrong.

The correct calls would be

alert(self.events().length)
alert(self.events()[0].name());

Because you need to call the observable array as a function like the regular ko.observable to get its underlying value the array itself.

However you are currently adding to whole CalendarViewModel to the array because the btnAddNewEvent is outside of yourwith binding so the current context will be your main view model.

One way to solve it: just add the self.event to the array, so:

self.addEvent = function() 
{ 
    self.events.push(self.event); 
    alert(self.events().length)
    alert(self.events()[0].name());
}

But this can cause problems later when you want to add another element because you will end up referencing the same element, so the right solution is copy the properties somewhere:

So I would create a constructor function for your event class:

var Event = function(data) {
    var self = this;
    self.name = ko.observable(data.name()),
    self.adress = ko.observable(data.adress()),
    self.startTime = ko.observable(data.startTime()),
    self.endTime = ko.observable(data.endTime())
}

And push a new event in the addEvent

self.events.push(new Event(self.event));
Dipterocarpaceous answered 27/4, 2013 at 20:8 Comment(2)
now it is working but it seems that when I use alert(self.events()[0].name()); I get this error: Uncaught TypeError: Object #<CalendarViewModel> has no method 'name', When I type in alert(self.events()[0].event.name()) then its ok but doesnt it mean I store the whole view model in my array and not just the event property of the view model. I want the array to hold jsut the events objects, not the view model it self.Notability
Yes, you are currently adding to whole calendar viewmodel to the array because the btnAddNewEvent is outside of the with binding so the current context will be your main view model. One way to solve it to just and add the self.event so self.addEvent = function () { self.events.push(self.event); alert(self.events().length) alert(self.events()[0].name());Dipterocarpaceous
J
3

Try

self.events().length

and

self.events()[0].name() 

instead.

Jarman answered 27/4, 2013 at 20:9 Comment(0)
N
1

Just updating a little on nemesev answer. You really don't have to pass data as an argument

var Event = function() {
    var self = this;
    self.name = ko.observable();
    self.adress = ko.observable();
    self.startTime = ko.observable();
    self.endTime = ko.observable();
};

And call it like

self.events.push(new Event());
Nordrheinwestfalen answered 2/10, 2013 at 10:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.