ManuelDeLeon / viewmodel

MVVM for Meteor
https://viewmodel.org
MIT License
205 stars 23 forks source link

Inherit properties stopped working on 3.4.2 #187

Closed dnish closed 8 years ago

dnish commented 8 years ago

Hey, just upgraded to the latest version and now all parts of my application stopped working. I'm getting the following error:

this.status is not a function

Status is a property of a collection item, normally VM takes it automatically when I do something like this:

{{#each item}}
   {{>single_item}}
{{/each}}

An example item object:

{name: 'A song', id:356, status:'waiting'}

A ViewModel:

Template.single_item.viewmodel({
getStatus() { if(this.status() == 'new') { return "It's a new one"; }}
});

On 3.4.2 this stopped working. When I downgrade to 3.3.3 everything is working fine again.

ManuelDeLeon commented 8 years ago

Make a repro.

dnish commented 8 years ago

Having some trouble of reproduce this in a new project, but this is what I get when I cut my VM to the smallest peace:

Template.item.viewmodel({
 formatTitle() {

  console.log(this.title());
  return this.title();

  }
}); 

This will give me the following console output:

null
null
null
null
A new entry
Another entry
Just a test entry
A very nice posting

I only have 4 collection items, but the console logs 8 function calls of formatTitle(), where all are null at the beginning. The correct output should be

A new entry
Another entry
Just a test entry
A very nice posting

If I downgrade to ViewModel 3.3.3 this behavior doesn't happen.

dnish commented 8 years ago

Okay, this should reproduce the problem: https://github.com/dnish/viewmodel-repro2

Console output:

Exception in template helper: TypeError: this.person is not a function
    at ViewModel.itemVM.sayHello (http://localhost:3000/app/client/item.js?d9165453dc3734c95a4b11a49466fd6d1d96fe90:18:26)
    at Object.helpers.(anonymous function) (http://localhost:3000/packages/manuel_viewmodel.js?f31121e3f28d80af44ebd9dab257b6d1d3170597:212:67)
    at http://localhost:3000/packages/blaze.js?695c7798b7f4eebed3f8ce0cbb17c21748ff8ba8:2994:16
    at http://localhost:3000/packages/blaze.js?695c7798b7f4eebed3f8ce0cbb17c21748ff8ba8:1658:16
    at http://localhost:3000/packages/blaze.js?695c7798b7f4eebed3f8ce0cbb17c21748ff8ba8:3046:66
    at Function.Template._withTemplateInstanceFunc (http://localhost:3000/packages/blaze.js?695c7798b7f4eebed3f8ce0cbb17c21748ff8ba8:3679:12)
    at http://localhost:3000/packages/blaze.js?695c7798b7f4eebed3f8ce0cbb17c21748ff8ba8:3045:27
    at Spacebars.call (http://localhost:3000/packages/spacebars.js?3eafdd2d5d5d8f08431aa842df4b5e8142600b17:175:18)
    at Spacebars.mustacheImpl (http://localhost:3000/packages/spacebars.js?3eafdd2d5d5d8f08431aa842df4b5e8142600b17:112:25)
    at Object.Spacebars.mustache (http://localhost:3000/packages/spacebars.js?3eafdd2d5d5d8f08431aa842df4b5e8142600b17:116:39)

If I change my function to this:

sayHello() { console.log(this); console.log(this.person());}

I get the following output:

ViewModel {vmId: 38, vmOnCreated: Array[0], vmOnRendered: Array[1], vmOnDestroyed: Array[0], vmAutorun: Array[0]…}
children: (search)
info: (value)
person: (value)
sayHello: ()
status: (value)
templateInstance: Blaze.TemplateInstance
text: (value)
vmAutorun: Array[0]
vmId: 38
vmOnCreated: Array[0]
vmOnDestroyed: Array[0]
vmOnRendered: Array[1]
vmPathToParent: ()
__proto__: ViewModel

but also this exception

Exception in template helper: TypeError: this.person is not a function
    at ViewModel.itemVM.sayHello (http://localhost:3000/app/client/item.js?7572f2538df20189c5c79e650f4fba1c93a94824:20:26)
    at Object.helpers.(anonymous function) (http://localhost:3000/packages/manuel_viewmodel.js?f31121e3f28d80af44ebd9dab257b6d1d3170597:212:67)

I'm calling the VM function in my template:

<template name="item">
   Name: {{sayHello}} <br>
</template>
fvpDev commented 8 years ago

Try using .load()... Check this out: https://github.com/fvpDev/_vmTestRepros/tree/Issue_187

@ManuelDeLeon: (but now I don't understand why the template isn't updating "sayHello"...console log shows the update though)

dnish commented 8 years ago

@fvpDev Did you try version 3.3.3 for the code above? Is it there updating?

fvpDev commented 8 years ago

My repro is at 3.4.3 I believe...didn't test other versions.

ManuelDeLeon commented 8 years ago

It works with 3.4.1 but not after.

dnish commented 8 years ago

@ManuelDeLeon Yep, my version also works with 3.4.1

ManuelDeLeon commented 8 years ago

Fixed on v3.4.4

Here's what happened. On v3.4.2 I delayed the loading of properties from the context. That meant the blaze helper triggered before the view model had the property. Now it's working as expected.

@all At risk of sounding rude I'll say this: Please, for the love of $DEITY, let's work on our repro making skills. I spend most of the time cleaning up the repros from all the stuff that is just noise. In this case all that's needed to reproduce the problem is:

Client:

<body>
  {{#each getItems}}
    {{> item }}
  {{/each}}
</body>

<template name="item">
  Name: {{ sayHello }} <br>
</template>
Template.body.viewmodel({
  getItems: null,
  onCreated: function () {
    Meteor.call("test", (err, res) => {
      this.getItems(res);
  });
  }
});

Template.item.viewmodel({
  sayHello: function() {
    return this.person ? this.person().name : 'asdf';
  }
});

Server:

Meteor.methods({
  test() {
    return [
      {
        text: 'Hello',
        status: 'new',
        person: {
          name: 'Dennis'
        }
      }
    ];
  }
})

No packages, routes, i18n, console logs, etc.

fvpDev commented 8 years ago

+1 @ManuelDeLeon about the repro-making skills Lol I tried to do what I could but wanted to get the issue taken care of as soon as possible and left the console logs in there for sake of dnish's benefit