Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifier called on each class property update #223

Open
olaf-k opened this issue Jul 3, 2014 · 9 comments
Open

Modifier called on each class property update #223

olaf-k opened this issue Jul 3, 2014 · 9 comments

Comments

@olaf-k
Copy link

olaf-k commented Jul 3, 2014

Consider the following:

var exampleController = klass({
    $constructor : function() {
        this.itemlist = ['one', 'two', 'three', 'four', 'five'];
        this.someval = '';
    },
    filter : function(e) {
        console.log('in filter');
        return e;
    }
});

{template example using c:exampleController}
    <ul>
    {foreach item in c.itemlist | c.filter}
        <li>{item}</li>
    {/foreach}
    </ul>
    <input type="text" value="{c.someval}"/>
{/template}

The filter is called each time c.someval is udpated. (This doesn't happen if the filter is defined outside the class.)

@benouat
Copy link
Member

benouat commented Jul 3, 2014

From what I understood about our expression engine, as soon as you use a reference to a property or a method on an object, the expression watch the object for any change.

This is what is happening here.
{foreach item in c.itemlist | c.filter} the expression part is in c.itemlist | c.filter. Anytime c changes (which means any time to change the value of any of its member properties) the expression get refreshed.

Thus I agree, it sounds like an aggressive refresh politic, but I would tend say that it is working as designed...

@olaf-k
Copy link
Author

olaf-k commented Jul 3, 2014

I had a hunch this would be the reason considering the same code with the filter defined outside the class but given the controller as an argument behaves the same way.
This impacts the way we can write controllers.

Is there a particular reason why in foreach item in object.collection we don't just stick to watching collection only?

@benouat
Copy link
Member

benouat commented Jul 3, 2014

My answer is not going to be simple and clear... 😞
@b-laporte @PK1A could you help me on that one ?

@PK1A
Copy link
Contributor

PK1A commented Jul 3, 2014

@olaf-k filters can have dynamic arguments that might change the filtering result, hence the watch. At least this is my mental model of those things...

@olaf-k
Copy link
Author

olaf-k commented Jul 3, 2014

@PK1A makes sense to watch arguments indeed. However in
{foreach item in c.itemlist | c.filter}
c is the container of the filter, not its argument.
Actually
{foreach item in c.itemlist | filter:c.propertytowatch}
works well but forces me to put the filter outside the controller.
So maybe we could watch only arguments (itemlist only in the first case)?
@b-laporte ?

@PK1A
Copy link
Contributor

PK1A commented Jul 3, 2014

@olaf-k OK, sorry for not being precise. Arguments are one part of the story and I think we all agree for the need of watching explicit arguments. But recently @b-laporte introduced possibility of specifying objects with the apply method as filters. In this case all the property of such object might be taken into account when executing the apply method.

Disclaimer: I don't know all the internals / details so might be as well making up things here...

@b-laporte
Copy link
Member

@olaf-k the behaviour you see on filter is the same as for functions/methods - as the filter is a function (or references an implicit function such as apply). So in case of a function used in a template expression hashspace will observe the function argument and the function context (i.e. the this object) as methods frequently use other members of their associated object.
With this said, the filter will not be called that often as when a change occurs, the expression is set as dirty, and will be re-evaluated only once when the DOM is refreshed (so in practice the filter will not be called everytime a change occurs on the its context object..)

@benouat
Copy link
Member

benouat commented Jul 4, 2014

@b-laporte from what I understood on @olaf-k sample, each time you type something in the input the filter gets called....

@olaf-k
Copy link
Author

olaf-k commented Jul 4, 2014

OK, so - I discussed this with @b-laporte and learned that methods can actually be bound and that when they are, both their arguments and their context are watched. From what I understood this was introduced when solving #50 but I wasn't aware of this new behavior -- that basically answers #75 by the way (just not how I expected it to.)

I'm a bit partial about this and still believe it would be great for developers to have a way to explicitly state a method's dependencies, overriding the framework's "I'll watch everything" functionality. We could discuss in a meeting, but feel free to comment here as well.

Edit:
For the sake of completeness, there are various ways to work around the issue:

  • move the filter outside the controller
  • move the property (someval in the sample) one level down (since the framework only watches the first level)
  • trick the parser with {let f = c.filter.bind(c)}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants