1

This question build up on KnockoutJS: Tracking menu clicks and KnockoutJS: Event object. I have re-factored the code a bit to seperate the viewModel and the UI logic. What I'm trying to do now is convert the "Children" object array of each "Menu" object into an observableArray so I can add/remove a menu's children to change my UI.

Here is my simplified code:

var viewModel = {};
var viewContext = {
    initialize: function (data) {
        viewModel = data;

        //for (var i = 0; i < viewModel.Panels.length; i++) {
            viewContext.observe(viewModel.Panels[0].Menu);
        //}
        viewModel.menuActive = ko.observable(false);
        viewModel.currentMenu = ko.observable(0);
        viewModel.currentNode = ko.observable({});
        viewModel.currentList = ko.observableArray([])
    },
    observe: function (data) {
        for (var i = 0; i < data.Children.length; i++) {
            viewContext.observe(data.Children[i]);
        }
        data.Children = ko.observableArray(data.Children);
    },
    nodeClicked: function (event) {
        var target = $(event.target)
        var data = target.tmplItem().data

        viewContext.getData(data, function (response) {
            viewModel.currentList(response.d);
            data.Children(response.d);
        });
        viewModel.currentNode(data);
    },
    getData: function (data, onSuccess) {
        $.ajax({
            url: 'console.asmx/' + data.Method,
            type: "POST",
            cache: false,
            contentType: "application/json; charset=utf-8",
            data: ko.utils.stringifyJson(data),
            dataType: "json",
            success: onSuccess,
            error: function () {
                viewModel.currentList([]);
            }
        });
    }
};
$(function () {
    $.ajax({
        url: 'console.asmx/Initialize',
        type: "POST",
        cache: false,
        contentType: "application/json; charset=utf-8",
        data: "{}",
        dataType: "json",
        success: function (data) {
            viewContext.initialize(data.d);
            ko.applyBindings(viewModel);
        }
    });
});

When the page is initially rendered (using the templates in the referenced questions), everything is fine. However, when I click on a menu which is fires the "nodeClicked" event, I get an error on the line data.Children(response.d); that says "Uncaught ReferenceError: Children is not defined".

My guess is that the line data.Children = ko.observableArray(data.Children); is not converting my array properly into an observableArray.

Any ideas will be greatly appreciated.

5
  • Is data.Children defined when ko.observableArray(data.Children) is called? Commented Mar 18, 2011 at 14:45
  • yes it is. The data comes from the server after an ajax call, and every menu object has a property "Children" which is an array (empty if it is a leaf object). I can confirm this because my UI is rendered correctly for elements bound to data.Children. Commented Mar 18, 2011 at 14:50
  • 1
    It is fine to create an observableArray from an array with the syntax that you are using. It should not cause a problem. I would try logging data and response.d in your callback from your AJAX request to make sure that they are what you expect. Some console.log calls if you are using Firefox with Firebug or Chrome would probably help. Otherwise, even some alert(ko.toJSON(data)) in the callback would hopefully show something. Maybe add it to the question. Your application is a bit too involved for someone else to easily work up a jsFiddle to simulate it. Maybe you could try. Thanks. Commented Mar 18, 2011 at 16:05
  • Thanks RP! I think you just pointed me in the right direction. Commented Mar 18, 2011 at 16:13
  • @RP Niemeyer, you were right! My ajax response was returning an object which did not have a "Children" property at some point. How can I give you credit for this suggestion? Can your comment into an answer? Commented Mar 18, 2011 at 18:07

1 Answer 1

3

It is fine to create an observableArray from an array with the syntax that you are using. It should not cause a problem. I would try logging data and response.d in your callback from your AJAX request to make sure that they are what you expect. Some console.log calls if you are using Firefox with Firebug or Chrome would probably help. Otherwise, even some alert(ko.toJSON(data)) in the callback would hopefully show something. If it is saying Children is not defined, then it is more than a problem with moving it from a normal array to an observableArray as Chidren is not there at all.

Here's a snippet of what will and will not work:

$.getJSON("http://localhost/getMoreData", function (allData) {
  if (allData) {
    var mappedData = $.map(allData.rows, function (row) {
      return new Object();
    });

    // DOES NOT WORK:
    //self.koArray().unshift(mappedData);

    // DOES WORK!
    for (var i = 0; i < mappedData.length; i++) {
      self.koArray().unshift(mappedData[i]);
    }
  }
});
Sign up to request clarification or add additional context in comments.

1 Comment

Just a quick comment - I needed to dynamically grab more data using our REST interface and then append that data to our knockout table. I had to loop through the array and add the items individually rather than adding the entire array in order for Knockout to not complain. Thanks RP.

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.