knockout throws Message: TypeError: <xxx> is not a function. What does it mean?

javascript, knockout.js

Solution

It's not that CommentList is undefined, it's just that it's not an observable (hence not a function). The reason being that in your ajax callback, you are just pushing the 'chat' objects received from your server "as is". You're not creating for example a new observableArray called CommentList, but you're just putting a bare array CommentList - hence the thrown error by KO.

You would need to make the same transformation as you did when constructing self.chats in the viewmodel constructor, e.g.:

$.each(chats, function(index, chat) {
    self.chats.push(
        {
            CourseItemDescription: chat.CourseItemDescription,
            CommentList: ko.observableArray(chat.CommentList),
            CourseItemID: chat.CourseItemID,
            UserName: chat.UserName,
            ChatGroupNumber: chat.ChatGroupNumber,
            ChatCount: chat.ChatCount,
            NewCommentText: ko.observable("")
        }
    );
});

By the way, you should also take a look at the ko.mapping plugin, it can do this transformation for you.

Edit: Also, for better performance you shouldn't push each individual item into the observable array, but add them in one bulk operation, something like:

self.chats( self.chats().concat( ko.utils.arrayMap(chats, function(chat) {
    return { /* ... same as before ... */ };
} ) );

Problem

I have this code: ``` <ul id="chats" data-bind="foreach: chats"> <li> <div class="chat_response" data-bind="visible: CommentList().length == 0"> <form data-bind="submit: $root.addComment"> <input class="comment_field" placeholder="Comment…" data-bind="value: NewCommentText" /> </form> </div> <a class="read_more_messages" data-bind="visible: moreChats, click: showMoreChats">Read More Messages...</a> </li> </ul> function ChatListViewModel(chats) { // Data var self = this; self.chats = ko.observableArray(ko.utils.arrayMap(chats, function (chat) { return { CourseItemDescription: chat.CourseItemDescription, CommentList: ko.observableArray(chat.CommentList), CourseItemID: chat.CourseItemID, UserName: chat.UserName, ChatGroupNumber: chat.ChatGroupNumber, ChatCount: chat.ChatCount, NewCommentText: ko.observable("") }; })); self.moreChats = ko.observable(true); self.showMoreChats = function () { var LastChatGroupNumber = self.chats()[self.chats().length - 1].ChatGroupNumber; $.ajax({ url: $.CourseLogic.dataitem.GetMoreChatsUrl, data: "{chatGroupNumber: " + ko.toJSON(LastChatGroupNumber + 1) + "}", type: "post", contentType: "application/json", success: function (chats) { var chatList = self.chats(); $.each(chats, function (index, chat) { self.chats.push(chat); }); } }); } } ko.applyBindings(new ChatListViewModel(initialData)); ``` But I get this error when the showMoreChats function is called: `Unable to parse bindings. Message: TypeError: CommentList is not a function; Bindings value: visible: CommentList().length == 0` What does it mean?

Original source