Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.js - Using {{#if}} around {{bindAttr}} with shared condition?

I'm on Ember-1.0.0-pre2 and I seem to be having trouble using an {{#if}} statement around an element which has a {{bindAttr class="..."}} and the binding conditions are the same. I.E. the if statment and class binding are to the same controller attribute. See code:

<button {{action "toggleShow" target="controller"}}>Toggle Visibility</button>
{{#if show}}
   <div {{bindAttr class="show:red:green"}}>test</div>
{{/if}}

http://jsfiddle.net/y49ch/10/

If you click the "Toggle Visibility" button several times you'll notice you get a the common error that says: "Something you did caused a view to re-render after it rendered but before it was inserted into the DOM. Because this is avoidable and the cause of significant performance issues in applications, this behavior is deprecated ..."

At first look that seems stupid, but that's a very primitive example of my problem. In my case, there is a computed property on the end of both bindings (if and class attribute). In both cases the computed properties share a common dependent key. When that common dependent key changes it causes both helpers to be update and thus the error.

Is this a bug? I can guess what's happening here, but it seems like I should be able to do this safely.


EDIT: The above is a primitive example of the problem I'm having. It's meant to show it in a very simple way. Below is a more complex example.

Template:

<button {{action "toggleValue" target="controller"}}>Toggle Value</button><br>
{{#if greaterThanTen}}
  <div {{bindAttr class="isOdd:red:green"}}>test</div>
{{/if}}

Javascript:

App.myController = Ember.Controller.create({
  value: 10,

  greaterThanTen: function() {
    return this.get('value') > 10;
  }.property('value'),

  isOdd: function() {
    return this.get('value') % 2 === 1;
  }.property('value'),

  toggleValue: function() {
    this.set('value', (this.get('isOdd') ? 10 : 11));
  }
});

http://jsfiddle.net/y49ch/16/

like image 368
Wesley Workman Avatar asked Dec 01 '25 12:12

Wesley Workman


1 Answers

I see it now. Your original code had both points watching the same property which got me a little confused, but now it makes more sense. I can't really get what's going on, but I suspect it might have something to do with the runloop.

I've changed your code a little (see this jsfiddle) so that div is now a child view. Some of your properties were moved from the controller to the view (does your spec allow these guys to be at the view or does it have to be at the controller? unless I missed something only the view should be concerned about isOdd and toggleValue at this point) and the css is bound through classNameBindings watching for the value property that is bound to the parent view.

App.myController = Ember.Controller.create({
  value: 10,

  greaterThanTen: function() {
    return this.get('value') > 10;
  }.property('value') 

});

App.MyView = Ember.View.extend({
    templateName: 'my-view',
    valueBinding: 'controller.value', 
    toggleValue: function() {
        this.set('value', (this.get('isOdd') ? 10 : 11));
    },
    isOdd: function() {
         return this.get('value') % 2 === 1;
    }.property('value'),
    ChildView: Em.View.extend({
        classNameBindings: 'parentView.isOdd:red:green'        
    })
});

Now, the template looks like this:

<script type="text/x-handlebars" data-template-name="my-view">
  <button {{action "toggleValue"}}>Toggle Value</button><br>
  {{#if greaterThanTen}}
    {{#view view.ChildView}}
       test
    {{/view}}
  {{/if}}
</script>

Since the default tag for the View is div, it renders the same html, and it totally acts as a different view and prevents unecessary re-render.

Edit: Just as proof of concept, I've added a button to add to the value instead of just toggle so you can actually see the color changing after it gets visible. Here's the fiddle

Let me know if this is good for you

like image 79
MilkyWayJoe Avatar answered Dec 03 '25 02:12

MilkyWayJoe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!