3
votes

I'm following John Papa's jumpstart course about SPA's and trying to display a list of customers loaded via ASP.NET Web API the knockout foreach binding is not working. The Web API is working fine, I've tested it on it's own and it is returning the correct JSON, because of that I won't post the code for it. The get method simply returns one array of objects, each with properties Name and Email. Although not a good practice, knockout is exposed globaly as ko by loading it before durandal.

I've coded the customers.js view model as follows

define(['services/dataservice'], function(ds) {
     var initialized = false;

     var customers = ko.observableArray();

     var refresh = function() {
         return dataservice.getCustomers(customers);
     };

     var activate = function() {
          if (initialized) return;
          initialized = true;
          return refresh();
     };

     var customersVM = {
          customers: customers,
          activate: activate,
          refresh: refresh
     };

     return customersVM;
});

The dataservice module I've coded as follows (I've not wrote bellow the function queryFailed because I know it's not being used)

 define(['../model'], function (model) {
     var getCustomers = function (customersObservable) {
          customersObservable([]);

          var options = {url: '/api/customers', type: 'GET', dataType: 'json'};

          return $.ajax(options).then(querySucceeded).fail(queryFailed);

          function querySucceeded(data) {
               var customers = [];

               data.forEach(function (item) {
                   var c = new model.Customer(item);
                   customers.push(c);
               });

               customersObservable(customers);
          }
     };

     return {
          getCustomers: getCustomers
     };
 });

Finaly the model module was built as follows:

define(function () {

    var Customer = function (dto) {
        return mapToObservable(dto);
    };

    var model = {
        Customer: Customer
    };

    return model;

    function mapToObservable(dto) {
        var mapped = {};
        for (prop in dto)
        {
            if (dto.hasOwnProperty(prop))
            {
                mapped[prop] = ko.observable(dto[prop]);
            }
        }

        return mapped;
    }
});

The view is then simply a list, it is simply:

<ul data-bind="foreach: customers">
    <li data-bind="text: Name"></li>
</ul>

But this doesn't work. Any other binding works, and I've looked on the console window, and it seems the observable array is being filled correctly. The only problem is that this piece of code doesn't show anything on screen. I've reviewed many times the files but I can't seem to find the problem. What's wrong with this?

5
case sensitivity? You stated above that the properties were Name and Email, but your binding says text: name. - Brad
@Brad, I've written wrong here. I've had written with the wrong case on my code also, but even correcting this, it still doesn't work. Do you have any other idea? Thanks for the help. - user3115001
Did you remember to call applyBindings? - Hallvar Helleseth
Any thing in the console for errors? - Kelly J Andrews
You picked a solution, but you didn't mention what had gone wrong - Thanasis Ioannidis

5 Answers

3
votes
1
votes

I know this question is a little old but I thought I'd add my response in case someone else runs into the same issue I did.

I was using Knockout JS version 2.1.0 and it seems the only way I can get the data to display in a foreach loop was to use:

$data.property 

so in the case of your example it would be

$data.Name

Hope this helps

1
votes

Well, I just spent a lot of time on an local issue to realize that the ko HTML comment format, if used, should be like this:

<!-- ko foreach: arrecadacoes -->

and NOT like this:

<!-- ko: foreach: arrecadacoes -->

: is NOT used after ko...

0
votes

I don't see anywhere in your code that you've called ko.applyBindings on your ViewModel.

0
votes

KO has a known issue while using foreach in a non-container element like the one above <ul> so you have to use containerless control flow syntax.

e.g.

<ul>
 <!-- ko foreach: customers-->
    <li data-bind="text: Name"></li>
 <!-- /ko -->
</ul>

Ref: http://knockoutjs.com/documentation/foreach-binding.html