~ read.
Ember, jQuery, and UI libraries

Ember, jQuery, and UI libraries

When developing with Ember, we often need to perform some jQuery manipulation that would be a lot simpler in a traditional development environment. Because Ember inserts content into the DOM after page load, any jQuery loaded along with index.html may go to waste as the elements to be acted on do not exist at time of execution.

Specifically, I've been using a lot of popular UI libraries, many of which are meant to be used alongside Bootstrap. Things like Bootstrap Datepicker (the eternicode fork), Bootstrap Switch, and Chosen.js from Harvest. A lot of these libraries (as well as Bootstrap itself) don't function correctly with Ember due to the peculiarities mentioned above.

The Ember guides provide a solution to this asynchrony issue, but they don't cover it entirely. Berlin developer Marcus Böhm provides a really great way to DRY up this lifecycle callback solution. I've included his tweaks below.

Ember.View.reopen({
  didInsertElement : function(){
    this._super();
    Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
  },
  afterRenderEvent : function(){
    // implement this hook in your own subclasses and run your jQuery logic there
  }
});

I am more of a Coffeescript guy, myself, so this is exactly what I use in my code. (It's really just a straight transpile from the previous code block.)

Ember.View.reopen
  didInsertElement: ->
    @_super()
    Ember.run.scheduleOnce "afterRender", this, @afterRenderEvent
    return

  afterRenderEvent: ->

This means that any Ember View in your project will now be able to run its necessary Javascript at the appropriate time if you simply override afterRenderEvent in that View! Here is an example of a Google Map I put in an app to test this process.

App.GoogleMapView = Ember.View.extend(
  afterRenderEvent: ->
    initialize = ->
      mapDiv = document.getElementById "map"
      map = new google.maps.Map(mapDiv,
        center: new google.maps.LatLng(42.9, 6.1)
        zoom: 3
        styles: [
          #various map features here
        ]
        mapTypeId: google.maps.MapTypeId.ROADMAP
      )
      return

    initialize()
)

The more I read about this process, the more I see that the proper way to handle this kind of thing is with Ember Components. Again and again they are heralded as the better solution for reusable chunks of an app that mix View and Controller code. I still need to learn more about Ember Components, though, before I feel comfortable making the switch.

Like I said at the beginning, Bootstrap itself runs into some issues with Ember. Luckily, we've got the bootstrap-for-ember project that helps us out! Not everything is implemented, but the things I have needed (alerts, modals, tabs) are all there, and the project is modular, allowing you to add only what you need to your app. bootstrap-for-ember actually uses Ember Components to achieve its functionality, and I plan on digging into how it works to maybe port over my UI elements.

If you're interested in seeing how I've gotten some of these tools functioning in Ember or are just looking for resources, don't hesitate to reach out. I'm on Twitter @MattAHorton.

comments powered by Disqus