Quantcast
Channel: Ember.JS - Latest topics
Viewing all articles
Browse latest Browse all 4830

Communication between cousin components - two-way binding vs. unidirectional?

$
0
0

@jameslaneconkling wrote:

Trying to find best practices for a component relationship I see a lot in my apps: cousin components that are backed by the same models, where there is a one-to-many relationship between the shared ancestor component and each cousin. E.g.

                 ancestor-component
                         |
             +-----------+------------+
             v                        v
          parent1                  parent2
             +                        +
    +----------------+       +----------------+
    v        v       v       v        v       v
cousinA   cousinB  cousinC cousinA  cousinB  cousinC

Each set of siblings represent a different visualization of the data. Cousins A are backed by the same data, cousins B likewise, etc. I'm looking for best practices in ways to sync the visual state of cousins. E.g. hover on one cousin, and the effect is registered on it's corresponding cousin.

I've found two general patterns: two-way binding using the model, and unidirectional using the data-down, actions-up pattern. E.g., to have corresponding cousin components enter a hover state when either is hovered on:

  1. two-way binding Ember Twiddle

// register an isHoverState on the model
export default Ember.Component.extend({
  classNames: ['child-one'],
  classNameBindings: ['model.isHoverState:hover'],
  
  announceHoverState: Ember.observer('model.isHoverState', function() {
      console.log('cousins hovered:', this.get('model.id'));
  }),
  
  mouseEnter() {
    this.set('model.isHoverState', true);
  },
  
  mouseLeave() {
    this.set('model.isHoverState', false);
  }
});
  1. data down/actions up Ember Twiddle

// send mouseEnter/Leave actions up to the shared ancestor component, 
// and a childOne/TwoHover property down to the other parent component
  // (see the twiddle for all the code)
export default Ember.Component.extend({
  classNames: ['child-two'],
  classNameBindings: ['cousinIsHover:hover', 'selfIsHover:hover'],
  
  cousinIsHover: Ember.computed('childOneHover', function() {
    return this.get('childOneHover') === this.get('model');
  }),
  
  announceCousinHover: Ember.observer('childOneHover', function() {
    if (this.get('childOneHover') === this.get('model')) {
      console.log('cousins hovered:', this.get('model.id'));
    }
  }),
  
  mouseEnter() {
    this.sendAction('mouseEntered', this.get('model'));
    this.set('selfIsHover', true);
  },
  
  mouseLeave() {
    this.sendAction('mouseLeft', this.get('model'));
    this.set('selfIsHover', false);
  }
});

I have some early observations about the pros and cons of each approach, but I wanted to know if anyone who has spent more time in the Ember space (I'm going on two months here), has any input on best practices, antipatterns, or other approaches I didn't consider here.

Initial thoughts:

two-way binding via model

  • takes ~1/2 the lines of code, and is simpler in some ways to reason about
  • requires you to store view state on the model (bad?)
  • it's not possible to tell which cousin component set the state (bad?)

unidirectional flow

  • requires a lot more code, particularly with a deep component hierarchy from ancestor to cousin
  • the component signatures become a lot longer as the number of possible states increases (b/c you are passing down more data, and up more actions)
  • I don't like having to pass the childOneHover model down to all child-two components (and childTwoHover model to all child-one components), and compare it against it's own model to make sure it's a match.
  • it is possible to tell which cousin initiated the state change, and thus manage reactions to state change in a much more detailed way. (very good)

Any thoughts/feedback? Hope this isn't too general (it's very specific to a number of cases I'm working on, but maybe not for others?)

Posts: 2

Participants: 2

Read full topic


Viewing all articles
Browse latest Browse all 4830

Trending Articles