Ember observer not working when observes property of other controller


#1

I want to access the IsOpen property that is set in my ApplicationController in my EventsController , but more than that , I want to listen for changes in it , so I’m using the following code :

isOpen: Ember.observer('application.isOpen', function () {
  console.log('test');
}),

But is not firing at all.

In my ApplicationController i have the following:

export default Ember.Controller.extend({
  isOpen: true,

  actions: {
      toggleSidebar () {
       this.toggleProperty('isOpen');
      }
   }
});

Am i missing some configuration?


UPDATE:

What i’m trying to do:

In my application template, i’m calling two components, the sidebar and the navbar component. In the navbar component, i have a button, each will send a action to ApplicationController, in order to make the sidebar toggle.

Like this:

ApplicationTemplate:

{{#if session.isAuthenticated}}
	{{pc-sidebar
		isVisible=showWrappers
		isOpen=isOpen
	}}
	{{pc-navbar
		isVisible=showWrappers
		isOpen=isOpen
		action='toggleSidebar'
	}}
{{/if}}
{{outlet}}

So, when i click in the button in my navbav, i send a action to ApplicationController:

actions: {
  toggleSidebar () {
     this.sendAction('action');
  }
}

And in my application controller, i just update the isOpen property:

  isOpen: true,
  actions: {
     toggleSidebar () {
       this.toggleProperty('isOpen');
     }
  }

Now the problem:

I need toggle the main too, each is wrapping all the content, BUT… the MAIN is not in the application template, because only a few templates need it , that would be the case of EventTemplate:

<main class="main">
  <!-- content of event template here -->
</main>

So… my solution was make the main a component, and call like this:

{{#main-main isOpen=isOpen}}
  <!-- content of event template here -->
{{/main-main}}

Now… i need listen to isOpen that was define in ApplicationController, and i’m struggling with this…

Thanks.


#2

The Ember.observer('application.isOpen', … part won’t work.

Well it does, but does not do what you think: it simply watches this.application.isOpen on your EventsController.

It is possible to get a reference to the other controller using this.container.lookup, then attach your observer using Ember.addObserver.

However, I suspect you’re embarked on a XY question, so it would probably be better if you explained what you are trying to accomplish. I have a strong feeling it would be doable more naturally in another way.


#3

I updated the question!!!


#4

Generally, when you need to share state between different layers of an Ember application, the tool for the job is to create a service. Here for instance, you could imagine having a panel service, maybe something like this:

// app/services/panels.js
export default Ember.Service.extend({
    mainPanelShown: false,

    setPanel: function (name, visible) {
        set(this, name + 'PanelShown', visible);
    }
});

You can then use it from anywhere:

// If you need to know whether to show the panel/the panel is shown
export default Ember.Controller.exend({
    panels: Ember.inject.service(),
    isPanelShown: Ember.computed.readOnly('panels.mainPanelShown')
});

If you need to trigger it:

export default Ember.Controller.extend({
    panels: Ember.inject.service(),
    actions: {
        showTheMainPanel: function () {
            get(this, 'panels').setPanel('main', true);
        }
    }
});

Granted, this is definitely not polished, but you get the idea. The point is to have the service be the central interface for triggering panels and getting their state.

This can even be extended so that setPanel accepts additional parameters to configure the panel.


#5

That works pretty well!!! Thank you very much Spectras… i’m really trying to learn Ember, but i’m having some difficult.

Thank you again man!!


#6

Spectras… what is the difference between use Ember.computed.readOnly and Ember.computed.alias?


#7

You’re welcome.

For readOnly and alias, they’re the same, except you cannot use set() on the readOnly version (it will throw an error). It’s a good idea to use it instead of alias when you should not change the value from that component/controller.