Window width checking is not working


#1

Hello,

i have a problem with the didInsertElement and resize function… i want at a specific window width change a class of an element. but the change is only there if i load the site. if i change then the window size he do nothing…

here is my code:

        import Ember from "ember";
    var IndexView = Ember.View.extend({
      classNames: ['index'],
      //touchStart: Ember.alias('click'), 
      didInsertElement: function() {
          $('.mainmenu div').removeClass('open').addClass('close'); 
            var width = $(window).width();
            if (width >= 851) {
                $('.lobby-footer .send-gift li').removeClass('right').addClass('left');
                $('.lobby-footer .send-gift a').removeClass('btn-right').addClass('btn-left');
            }else {
                $('.lobby-footer .send-gift li').removeClass('left').addClass('right');
                $('.lobby-footer .send-gift a').removeClass('btn-left').addClass('btn-right');
            }
      },
      willDestroy: function() {
       },  
      resize: function() {
       }
    });

export default IndexView;

its all the same if i put the code in idInsertElement: function() or at resize: function() nothing works…

anyone any idea? What i do wrong?

Avi


#2

You need to add an event listener for resize on window itself. Resize is not fired on a per element basis.

You should add the listener on didInsertElement, and remove the listener on willDestroyElement.


#3

uff… i am a newbie on ember cli … can you show me an example or something?

i think i found here something similar, the menuOpenHandler: function() and menuCloseHandler: function() but i dont really understand this…

import Ember from "ember";
export default Ember.View.extend({
  classNames: ['application'], 
  classNameBindings: ['loading', 'error', 'splash', 'classForPath'], 
  loading: Ember.computed.alias('controller.loading'),
  error: Ember.computed.alias('controller.error'), 
  classForPath: (function() {
    var currentPath = this.get('controller.currentPath') || '';
    currentPath = Ember.String.decamelize(currentPath);
    currentPath = currentPath.split('.').join('-');
    return currentPath + "-view";
  }).property('controller.currentPath'), 
  didInsertElement: function() {
    var view = this;
    var resizeHandler = function() {
      //view.rerender();
      view.resize();
    };
    this.set('resizeHandler', resizeHandler);
    $(window).bind('resize', this.get('resizeHandler'));
    this.resize();
  },
  willDestroy: function() {
    $(window).unbind('resize', this.get('resizeHandler'));
  }, 
  splash: true, 
  splashDidChange: function() {
    this.set('splash', !this.get('controller.currentUser') || this.get('controller.error') || this.get('controller.loading'));
    Ember.run.scheduleOnce('afterRender', this, 'viewRendered');
    //Ember.run.next('afterRender', this, 'afterRender');
  }.observes('controller.currentUser', 'controller.error', 'controller.loading'), 
  menuOpenHandler: function() {
      var width = $(window).width();
      console.log("menu open handler: ", width);
      if (width <= 850) {
      if( $(this).hasClass("close")){
          $("#lobby-head").slideDown(1000);
          $(".mainmenu div").animate({
               height: "100px"
          }, 500, function() {
               $('.mainmenu div').removeClass('close').addClass('open'); 
          });
        return false;
      }
      return false;
      }
  },
  menuCloseHandler: function() {
    console.log("menu close handler: ", width);
      var width = $(window).width();
      if (width <= 850) {
          if( $(this).hasClass("open") ) { 
            $("#lobby-head").slideUp(500);
        $(".mainmenu div").animate({
             height: "32px"
        }, 1000, function() {
          $('.mainmenu div').removeClass('open').addClass('close'); 
        });return false;
        }
          return false;
      }
  },
  viewRendered: function() {
    var view = this;    
    Ember.run.next(function() {
      console.log("application view has been rendered");
      // render lobby
      if (!view.get('splash')) {
        // lobby has been rendered
        console.log("lobby has been rendered");
          view.$(".mainmenu div").on('click swipedown', view.menuOpenHandler);
          view.$(".mainmenu div").on('click swipeup', view.menuCloseHandler);
        
      } else {
        // application is still loading or in error state
        console.log("splash state");
          view.$(".mainmenu div").off('click swipedown', view.menuOpenHandler);
            view.$(".mainmenu div").off('click swipeup', view.menuCloseHandler);
      }
      
      $("a[href='#']").click(function(e) {
        e.preventDefault();
      });

      
      
    });
  }, 
  resize: function() {
    console.log("resize application");

  }

});

#4

This really isn’t an ember-cli thing, it’s just standard JS eventing put into an Ember context. Normally you might to something like so:

function myResizeFunction() {
   ... do what you want to do here ...
}

window.addEventListener('resize', myResizeFunction);

with jQuery in Ember that would look like this.

Ember.$(window).on('resize', myResizeFunction);

However, with single page apps, you want to remove any event listeners you have attached when they are no longer needed (when that view is torn down or the element is removed such as during a transition to another page).

If your one event listener is generic enough where it is reused by many views or by every page, you don’t need to worry about removing it. But in this case it seems very likely you do.

var IndexView = Ember.View.exend({
    
    _myResizeFunction : function () {
        ... do magic here ...
    },

    attachResizeListener : function () {
        Ember.$(window).on('resize', this.get('_myResizeFunction'));
    }.on('didInsertElement'),

    removeResizeListener : function () {
        Ember.$(window).off('resize', this.get('_myResizeFunction'));
    }.on('willDestroyElement')
});

However, if you need to preserve the context of your view within your function you will need to be a little more complicated, because otherwise the function will execute in the global scope. You could accomplish that using binding similar to so.

var IndexView = Ember.View.exend({
    
    _myResizeFunction : function () {
        ... do magic here ...
    },

    ___resizeFunction : null,

    attachResizeListener : function () {
        this.set('___resizeFunction', this.get(_myResizeFunction).bind(this));
        Ember.$(window).on('resize', this.get('___resizeFunction'));
    }.on('didInsertElement'),

    removeResizeListener : function () {
        Ember.$(window).off('resize', this.get('___resizeFunction'));
    }.on('willDestroyElement')

});

Before you run off and implement this though

You should really think about why you are using so much jQuery to manipulate the classes on elements within this view. This is a perfect use case for using attribute bindings, specifically the className binding, to let Ember worry about toggling the class names on the correct elements for you.

I know it is very tempting and easy to return to writing tangled jQuery statements when first starting out with Ember, but you will have cleaner code that breaks less often and likely comes with performance improvements (via render loop optimizations) by using bound attributes here instead of jQuery.


#5

wow :open_mouth: thank you!! you’ve explain that very good. i understand this now more :slight_smile: really really thank you!