Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this knockoutjs observableArray not causing UI update?

I have a feeling I'm missing something simple here, but just can't quite grok this. Here is my script:

function FormDefinition()
{
    var self = this;
    self.Fields = ko.observableArray([new FieldDefinition()]);    
}

function FieldDefinition()
{
    var self = this;
    self.Name = "Test";
}
function ViewModel()
{
    var self = this;
    self.formDef = ko.observable(new FormDefinition());
    self.Name = "bob"
    self.addField = function(){
        this.formDef().Fields().push(new FieldDefinition());                    
    }            
}

ko.applyBindings(new ViewModel());

and here is my markup:

<a data-bind="click: addField">Add</a><br/>
<span data-bind="text: Name"></span>
<ul data-bind="foreach: formDef().Fields">
    <li data-bind="text: Name"></li>
</ul>​

and here is a jsFiddle: http://jsfiddle.net/5xSmr/

Expected behavior is that clicking 'Add' would cause the ui to update. debugging reveals that addfield is getting called.

like image 419
Daniel Avatar asked Apr 27 '12 20:04

Daniel


People also ask

How do you activate a Knockoutjs model?

Activating Knockout But since the browser doesn't know what it means, you need to activate Knockout to make it take effect. To activate Knockout, add the following line to a <script> block: ko. applyBindings(myViewModel);

What is ko ObservableArray?

An observableArray just tracks which objects it holds, and notifies listeners when objects are added or removed.

What is deferred in Knockout js?

Deferred – Notifications happen asynchronously, immediately after the current task and generally before any UI redraws. Rate-limited – Notifications happen after the specified period of time (a minimum of 2-10 ms depending on the browser).

What is observable array?

ObservableArray is an array that allows listeners to track changes when they occur.


2 Answers

Fixed your fiddle: http://jsfiddle.net/5xSmr/2/

<a data-bind="click: AddField">Add</a><br/>
<span data-bind="text: Name"></span>
<ul data-bind="foreach: formDef().Fields()">
    <li data-bind="text: Name"></li>
</ul>
function FormDefinition()
{
    var self = this;
    self.Fields = ko.observableArray();    
}

function FieldDefinition()
{
    var self = this;
    self.Name = "Test";
}
function ViewModel()
{
    var self = this;
    self.formDef = ko.observable(new FormDefinition());
    self.Name = "bob"
    self.AddField = function(){
        this.formDef().Fields.push({Name:"test"});
    }            
}

ko.applyBindings(new ViewModel());

The main problem was that you were calling Fields() and not just Fields. Fields() return the unwrapped array and by pushing directly to it, ko would never know about it.

like image 143
AlexG Avatar answered Sep 17 '22 14:09

AlexG


Here you go :-)

http://jsfiddle.net/JasonMore/Q6J6a/3/

View

<a href='#' data-bind="click: AddField">Add</a><br/>
<span data-bind="text: Name"></span>
<ul data-bind="foreach: formDef.Fields">
    <li data-bind="text: Name"></li>
</ul>​

Javascript

var FormDefinition = function ()
{
    var self = this;
    self.Fields = ko.observableArray();    
}

var ViewModel = function()
{
    var self = this;
    self.formDef = new FormDefinition();
    self.Name = ko.observable("bob");
    self.AddField = function(){
        self.formDef.Fields.push({Name:"test"});            
    }            
}

ko.applyBindings(new ViewModel());

like image 29
Jason More Avatar answered Sep 18 '22 14:09

Jason More