Problem with computed properties and setters


#1

I have a bare-bones example of what looks like a bug, but I’m not sure:

http://jsfiddle.net/Steve_OH/VE62u/

I have a simple application controller with two properties, one computed (outValue) and one not (inValue), with outValue dependent on inValue. Both are displayed on screen in edit boxes. If I modify inValue, the display of outValue updates as expected. However, if I so much as touch the outValue edit box (I just have to set focus to it), the link is broken, and changes to inValue no longer trigger the code that updates outValue.

I can make it work by changing the function declaration for the computed property from

outValue: function()

to

outValue: function(key, value)

With that change, it works fine. Unfortunately, unless I actually reference key or value from within the function, the minifier in ember-app-kit strips out the arguments, and I’m back where I started.

Bug? The problem occurs in the latest beta as well as 1.3.1.

Thanks,

-Steve


#2

Definitely not a bug…this works:

App.ApplicationController = Ember.ObjectController.extend({
        inValue: 0,
        outValue: function(key,value) {
            if( arguments.length == 2 ) {
                this.set('inValue', value / 2);
            } else {
                return this.get('inValue') * 2;
           }
        }.property('inValue')    
    });

The key thing to remember with setting calculated properties is that the second argument that is passed is the new value for that property; you have to perform the inverse calculation and set that to the dependent keys.


#3

I think you’re missing my point…

These are NOT supposed to be reciprocal properties. One of them is an input, the other is an output. The only reason that the output value is displayed in an edit box is to simplify copy/paste. Hand-modifying the output value should not have any effect on the input value, and in any case, the problematic behavior occurs merely when the output edit box is clicked, without any modifications having been made at all.

Yes, it works fine when you include the arguments in the parameter list–that’s what I said in my original message. It doesn’t work fine when the arguments are omitted. And in my case, the arguments are superfluous, so they get stripped out by the minifier, so even if I do include them, the minified version exhibits the same incorrect behavior.


#4

Ahh…I did miss the point, my bad…wouldn’t you maybe want an observer instead? Try this:

App.ApplicationController = Em.ObjectController.extend({
  inValue: 0,
  outValue: 0,
  inValueObserver: function() {
    this.set('outValue', this.get('inValue') * 2);
  }.observes('inValue')
});

That being said, I see now why you are led to believe there might be a bug…a two-way binding is being set up on a calculated property that can’t handle being set. That (somehow) breaks the binding between the properties…

It’s as if you’re setting that calculated property to .readOnly() but you’re allow the user to edit it…(when you do this, it’ll actually throw an error rather than fail silently).

The solution above should work. As an alternative, don’t create a two way binding to the view. In your template, if you just do:

<p>{{view Ember.TextField valueBinding="inValue"}}</p>
<p><input type="text" {{bind-attr value=outValue}} /></p>

The, the second input will not try to set the property no matter what you do, but it will continue to update based on the calculated property.

Hope this helps!


#5

Thanks. I had actually come up with some workarounds already. I was more concerned about finding out whether or not I should report it as an issue. I think I will, because any time the behavior of some code changes simply as the result of a simple minifier optimization, it’s probably a Bad Thing.

-Steve