Tui Popenoe
Tui Popenoe

Reputation: 2114

ApplyBindings to an array using Knockout JS

I have an AJAX request that returns an array of objects (Results). In the success callback function, the binding is applied using:

success: function(data) {
                ko.applyBindings(new ResultsViewModel(data), target);
         }

Where target is the target DOM element, and ResultsViewModel is created similar to:

function ResultsViewModel(model) {
    var self = this;
    self.text = ko.observable(model.text);
    self.id = model.id;
    self.Descriptions = ko.observableArray(model.descriptions);
}

In my HTML, the data is bound to the elements using:

<div data-bind="template: {name: 'results-template', foreach: $data}">

Then a template class that binds the individual properties of the view model.

My question is: how can I bind the array of data that is returned by my AJAX call (multiple result objects) using the viewmodel with a mixture of observable and static properties to the DOM?

The foreach loop I am using should create a template and bind each object in the returned array to a separate div, but it looks as though it is attempting to bind the root object in the returned array, which is null (unnamed array).

Upvotes: 3

Views: 1373

Answers (2)

Jeroen
Jeroen

Reputation: 63709

We can (somewhat) see where you're going with this. Your question is not 100% clear, so it's impossible to give a definitive answer (I suggest going through the KnockoutJS tutorials because you seem to have a few basic KO concepts mixed up). Nonetheless, here's one direction you could take.

As mentioned in the other answer, you use the template binding, but you don't indicate why you'd need that, as the foreach binding should suffice. The data for that template would be the Descriptions observable array, not $data. You're entire View (when keeping the use of the template binding) should look like something like this:

Option 1

<script type="text/html" id="results-template">
    <span data-bind="text: desc"></span><br />
</script>

<h4 data-bind="text: text"></h4>
<div data-bind="template: {name: 'results-template', foreach: Descriptions}">
</div>

This is assuming your Descriptions are complex objects that look like this:

[{ id: 12, desc: "Feels good" }, ... ]

See this fiddle for a demo.

Option 2

If your descriptions are just flat strings then your View's template needs to change and it does use the $data variable:

<script type="text/html" id="results-template">
    <span data-bind="text: $data"></span><br />
</script>

This is assuming your data looks like this:

["Feels good", ... ]

See this fiddle for a demo.


As a footnote, I noticed:

  • self.id is no observable, is that intentional?
  • you use a specific target when applying bindings, but from your question I see no reason why you'd need that?

In my example fiddle I've changed those two things.

Upvotes: 1

Patrick M
Patrick M

Reputation: 10989

It looks like you're misusing the $data "special context property" (as the knockout.js docs calls it). Quoting:

But what if you want to refer to the array entry itself (not just one of its properties)? In that case, you can use the special context property $data. Within a foreach block, it means “the current item”.

You're not really using a foreach binding, though: it's a template binding. In the docs for the template binding, they never use the foreach: $data syntax, it's always foreach: somePropOnTheViewModel.

Have you tried doing that instead? I can't be certain if this will do what you want without seeing the rest of the HTML for the binding you're applying it to, but I think this would work for your template code:

<div data-bind="template: {name: 'results-template', foreach: Descriptions}">

Upvotes: 2

Related Questions