質問

I'm playing around with Knockout JS, and in this code sample:

var data = 
    {
      allMakes: ko.observableArray([ 
        { name: "Toyota" }, 
        { name: "Fiat"} 
      ]),
      allModels: ko.observableArray([
        { name: "Corolla", make: "Toyota" },
        { name: "Celica", make: "Toyota" },
        { name: "Avensis", make: "Toyota" },
        { name: "Uno", make: "Fiat" },
        { name: "Bravo", make: "Fiat" }
      ])
    };

var myViewModel = 
    {
      makes : data.allMakes,
      models: ko.computed(function() {
        if (!myViewModel.selectedMake())
          return;

        // TODO: filter models by selected make
      }),
      selectedModel: ko.observable(""),
      selectedMake: ko.observable("")
    };

/* Uncomment it to work
myViewModel.models = ko.computed(function() {
if (!myViewModel.selectedMake())
          return;

        // TODO: filter models by selected make
      });
*/

ko.applyBindings(myViewModel);

http://jsbin.com/upaxum/8/edit

we can see that I try to access myViewModel variable inside models: ko.computed . However myViewModel is undefined when this computed observable runs. And I don't know why?

However if I create models computed observable in next statement, myViewModel variable is defined. Why is that?

EDIT: one of the answers suggests that I'm accessing the object before it is created. So how come that this code snippet works?

var myViewModel = 
    {
      myFnk : function()
      {
        console.log(myViewModel);
      }
    };

myViewModel.myFnk();

http://jsbin.com/eyutip/1/edit

役に立ちましたか?

解決

This is something that trips me up from time to time. ko.computed executes once as soon as it is defined. It does this so that it knows which variables it needs to subscribe to watch for changes.

So in this code

models: ko.computed(function() {
    if (!myViewModel.selectedMake())
        return;

    // TODO: filter models by selected make
})

myViewModel is accessed before it has been assigned to in the var myViewModel = line because the ko.computed is executing the function as soon as it is defined.

In your second example you are executing the function AFTER myViewModel has been defined so that is why it works. If you wanted to replicate this in your first example you might do something like:

var myViewModel = 
{
  makes : data.allMakes,
  selectedModel: ko.observable(""),
  selectedMake: ko.observable("")
};

myViewModel.models = ko.computed(function() {
    if (!myViewModel.selectedMake())
      return;

    // TODO: filter models by selected make
});

他のヒント

When you write

alert("This is " + myViewModel);

myViewModel hasn't yet been defined--you're still in the process of defining it! What exactly are you trying to do? What's the original reason that you want to be able to access the view model from within itself? If you tell us this, I'm pretty sure we can find a more idiomatic way of doing what you need to do.


Edit (after OP's edit)

In order to be able to refer to parts of your view model from other parts of the view model, use the self pattern (as recommended in the Knockout documentation):

function myViewModel() {
    var self = this;
    self.makes = data.allMakes;
    self.models = ko.computed(function() {
        if (!self.selectedMake())
            return;
        // TODO: do something with self.selectedMake()
        });
    self.selectedModel = ko.observable("");
    self.selectedMake = ko.observable("")
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top