1

I have a observable defined inside a object literal of a knockout viewmodel . Now when I ran the application .Its unable to access the observable .

$(function () {
  var viewModel =    {
    Folders: ['Inbox', 'Archive', 'Sent', 'Spam'],
    Title: ko.observable("My View Model Test"),
    SelectedFolder: ko.observable(),
    Mails: ko.observableArray(),
    SelectedMail: ko.observable(),
    SelectedChoices: ko.observable(false),


    navigate: function (folder) {           
        SelectedFolder(folder);
        $.ajax({
            url: "/Api/MailBox",
            data: { folder: folder },
            success: function (data) {
                self.Mails(data);
            },
            statusCode: {
                404: function () {
                    console.log("No Mails");
                }
            }

        });
    }
};
}

when I have bind the click event to navigate function . It says SelectedFolder is undefined . Can someone tell me why is it unable to access the SelectedFolder observable inside the navigate function ?

Joy
  • 6,438
  • 8
  • 44
  • 75

2 Answers2

2

When the navigate method is running and it looks for the SelectedFolder observable, it first looks for it in the context of the navigate method. Failing that, it jumps up to the parent context, which is the anonymous function being run when the page is ready. Failing that, it jumps to the global context - it can't find SelectedFolder there, so it then gives up.

To fix this, change your navigate method to reference the viewModel variable that is available in the context of the anonymous function being run when the page is ready:

navigate: function (folder) {           
  viewModel.SelectedFolder(folder);
  $.ajax({
    url: "/Api/MailBox",
    data: { folder: folder },
    success: function (data) {
      viewModel.Mails(data);
    },
    ...

Note that I also added a reference to the viewModel in the success callback so that it could find the Mails observable.

This should work, however, I would recommend considering changing your structure so that your navigate method isn't dependent on specific global variables. Here is one way:

var myViewModel = function() {
    var self = this;
    self.Folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
    self.Title = ko.observable("My View Model Test");
    self.SelectedFolder = ko.observable();
    self.Mails = ko.observableArray();
    self.SelectedMail = ko.observable();
    self.SelectedChoices = ko.observable(false);

    self.navigate = function (folder) {           
        self.SelectedFolder(folder);
        $.ajax({
            url: "/Api/MailBox",
            data: { folder: folder },
            success: function (data) {
                self.Mails(data);
            },
            statusCode: {
                404: function () {
                    console.log("No Mails");
                }
            }

        });
    };
};

$(function () {
  var ViewModel = new myViewModel();
  ko.applyBindings(viewModel);
});
CodeThug
  • 3,054
  • 1
  • 21
  • 17
1

The issue is probably what the current context is when the method is called. If the method is being called by a click event then this is probably the object which the click event was bound to, and so it tries to find a SelectedFolder method on that element.

Not sure if this is the best way, but here is one possible solution:

var viewModel =    {
  Folders: ['Inbox', 'Archive', 'Sent', 'Spam'],
  Title: ko.observable("My View Model Test"),
  SelectedFolder: ko.observable(),
  Mails: ko.observableArray(),
  SelectedMail: ko.observable(),
  SelectedChoices: ko.observable(false)
};

viewModel.navigate = function (folder) {           
  viewModel.SelectedFolder(folder);
  $.ajax({
    url: "/Api/MailBox",
    data: { folder: folder },
    success: function (data) {
      viewModel.Mails(data);
    },
    statusCode: {
      404: function () {
        console.log("No Mails");
      }
    }
});
samjudson
  • 56,243
  • 7
  • 59
  • 69
  • Your Idea is correct but the thing is I wanted to move the method inside the object literal. What you have done is outside the scope of object literal . So isn't it possible to define the function inside the object literal ? – Joy Dec 21 '12 at 16:52