Built-in DOM listeners as observers?


#1

Has anyone implemented a DOM / state observer? To say it another way, can a View or a Controller directly observer DOM events or properties?

Let’s say, for example, I want to show / hide a nested view based on window dimensions. Ideally, the template would trip on a property of the controller. Out of the box, do controllers have something like the following?

windowResized: function () { console.log('resized'); }.observes('window.outerWidth')

Ignore, for now, the fact that the internals of this function don’t do anything constructive.

I assume the answer is “no, this is not available out-of-the-box”. The next question, then, would be: what’s the best way to do this? I would think that within the application view’s didInsertElement I would add an event listener that could update the application controller. In some other controller, I could “needs” the app controller, then reference that property from the related template?


#2

There’s nothing out of the box for this but what you’ve described is pretty much what I do. I setup a window resize event listener in my application controller and update a bunch of dimension properties on the application controller as they change.

This is fine for window events because you don’t have to worry about cleanup but if you were going to do anything on elements within the page that might be managed by Ember, you’d need to track them via view lifecycle hooks and unbind them when they’re removed from the DOM.


#3

Posted sample code here: http://stackoverflow.com/a/26795615/1173020

App.ApplicationController = Ember.Controller.extend({
  handleResize: function() {
    console.log('resized');
  },
  bindResizeEvent: function() {
    jQuery(window).on('resize', Ember.run.bind(this, this.handleResize));
  }.on('init')
});

#4

This is exactly what views are for- so much so that you actually get a lot of listeners for free just by using them.

For example, if your template has something like:

{{#view "clickyBox"}}
    <p>Lots of good content waiting to be clicked on</p>
{{/view}}

If you declare a “click” method on that view, you’ll get a free event listener, and can still handle custom events like Denis described:

// Clicky box view
export default Ember.View.extend({
    tagName: "div"
    classNames: ["some-display-class"],
    click: function(){
        console.log("This will fire automatically every time the div is clicked");
    },
    bindRarerEvent: function(){
       // Like Denis's solution
        this.$().on("rareEventName", Ember.run.bind(this, this.handleRarerEvent));
    },
    handleRarerEvent: function(){
        console.log("Respond to something that isn't baked into views");
        this.get("controller").send("sendToAControllerAction");
    }
});

#5

Sure, here is a mixin I threw together:

http://jsfiddle.net/NQKvy/1478/