Javascript

  1. Adding properties to a model within an EmberJS router
  2. Sorting controller model results in EmberJS with sortProperties
  3. Having a bidirectional computed property on an EmberJS text field
  4. EmberJS debugging tips
  5. Adding a Select2 View in EmberJS
  6. Using Radio Buttons in EmberJS
  7. Capturing EmberJS errors with Raygun.io
  8. Integration Testing with EmberJS and JQuery
  9. Adding an Index to an each iteration over a computed property in EmberJS
  10. EmberJS Handlebars sanity tests with Grunt
  11. Waiting for EmberJS to update its views manually
  12. Testing Mocha applications with Grunt using Jenkins
  13. Extending App.reset() in EmberJS
  14. Understanding Ember.Object
  15. Transient DS.Model Attributes in EmberJS
  16. Listing the Attributes of an EmberJS DS.Model at Runtime
  17. The Problems with Chai
  18. Adding an ‘application loading’ screen to an EmberJS application
  19. Multiple JQuery versions with EmberJS
  20. npm, bower, Handlebars, Grunt, JQuery

How I learnt EmberJS and Coffeescript and Git

I’ll be using the tutorial at http://emberjs.com/guides/getting-started.

  1. Install Sublime Text 2 as an IDE.
  2. Install git and nano. Use nano as the default git commit message editor, because vim support on the Windows command prompt is pretty poor: git config --global core.editor nano
  3. Install the Sublime Linter plugin for ST2, which will provide syntax checking support, –by checking out SublimeLinter into your ST2 packages directory (since Sublime Linter is ST3 now): %APPDATA%/Sublime Text 2/Packages– by installing Package Control and installing Preferences > Package Control > Install Package > (wait for list to load) > Sublime Linter for ST3 (seems to work OK). This will give you things like PHP syntax error checking.
  4. Install Node.js which will also install NPM (Node.js package manager)
  5. Use npm to install coffeescript: npm install -g coffee-script
  6. Check that coffeescript is working: coffee -v
  7. Install the CoffeeScript ST2 plugin by going Preferences > Package Control > Install Package > (wait for list to load) > CoffeeScript
  8. Sublime Text should now support coffeescript linting. (I couldn’t get this to work properly yet.)
  9. Create a file %APPDATA%/Sublime Text 2/Packages/Default/CoffeeScript.sublime-settings and configure ST2 to use spaces rather than tabs for CoffeeScript files.
  10. Edit the csslint settings because they are pretty insane. Preferences > Package Settings > SublimeLinter > Settings - Default and change csslint_options: ids to false, overqualified-elements to false
  11. Create a new Github repository https://github.com/soundasleep/todomvc-emberjs-coffee
  12. Checkout: git clone https://github.com/soundasleep/todomvc-emberjs-coffee
  13. Update push.default on git to a more intuitive value (and also removes a warning): git config --global push.default simple
  14. Follow the instructions in the EmberJS getting started tutorial, committing and pushing as necessary.
  15. Try to Cake building; unfortunately I couldn’t get this to work because of win32 problems
  16. Install Grunt for building Coffeescript instead: npm install -g grunt
  17. Install the Grunt CLI: npm install -g grunt-cli
  18. Create a package.json. Understanding package.json
  19. Create a Gruntfile.js.
  20. Install all of the necessary packages referenced in the Gruntfile: npm install grunt-contrib-uglify grunt-contrib-qunit grunt-contrib-concat grunt-contrib-watch --save-dev. --save-dev will also modify package.json with the new dependencies (under devDependencies).
  21. Install https://github.com/gruntjs/grunt-contrib-coffee to compile coffeescript in Grunt: npm install grunt-contrib-coffee --save-dev
  22. You can now compile Coffeescript by running grunt coffee. You can also configure Grunt to watch for new files by modifying your Gruntfile and running grunt watch.
  23. Configure Sublime Text to treat Handlebars templates as HTML: HTML syntax validation within Handlebars templates in Sublime Text 2
  24. Use the js2coffee interpreter a lot
  25. You will have problems with things like function(){...}.property("x"); wrap the function with brackets

DEPRECATION: Action handlers implemented directly on controllers are deprecated in favor of action handlers on an actions object

Can also mean that an error has been thrown and your ApplicationController does not define an ‘error’ action (or EmberJS has created you an ‘error’ action and its incorrectly misinterpreting it as a directly implemented action? I have no idea).

This looks like an EmberJS bug and I guess it can be ignored - any other errors will be correctly reported (just sadly with no reliable stacktrace).

arrangedContent.addArrayObserver is not a function

Are you trying to #each over a bare JS object rather than an Ember array? e.g. instead of going:

Todos.TodosIndexRoute = Ember.Route.extend(
	model: ->
		todos: @store.find 'todo'
		feeds: @store.find 'feed'
		# ...
)

{{#each itemController="todo"}}

Going:

{{#each todos itemController="todo"}}

Computed model properties

An idea. Instead of:

date: DS.attr('string')
time: DS.attr('string')

Maybe:

datetime: DS.attr('date')
date: (->
  datetime = @get('datetime')
  moment(datetime).format('YYYY-MM-DD') unless Em.isEmpty(datetime)
).property('datetime')
time: (->
  datetime = @get('datetime')
  moment(datetime).format('HH:mm) unless Em.isEmpty(datetime)
).property('datetime')

Cannot perform operations on a Metamorph that is not in the DOM

The Error: Cannot perform operations on a Metamorph that is not in the DOM. can be caused if you have a Handlebars template using HTML comments rather than Handlebars comments. e.g.:

<!-- something
      {{#each controller}}
    ...
-->

This should be:

{{!-- something
      {{#each controller}}
    ...
--}}

Tested with emberjs-handlebars-sanity.

Hooking to valueBinding

You can modify an existing View to handle valueBinding in any way you want:

updateValue: (->
    # this.value is set to the date, correctly
    @$().select2 "val", @value
  ).observes('value')

Prevent JQuery.ajax.error from triggering an error state in Ember

Normally if you call $.ajax() and the requests results in an error, your errorCallback will still be called, but then Ember in all its wisdom will redirect you to the error state regardless.

One way to solve this is to wrap the AJAX call in a Promise, which prevents the error state from being called - it looks like Ember assumes that a JQuery.ajax() error can reject the entire Promise within say, an afterModel callback.

App.MyAPI =
  query: (method, data, callback, errorCallback) ->

    App.MyAPI.queryPromise(method, data).then (results) ->
      # promise passed
      callback(results)
    , (status) ->
      # promise failed
      errorCallback(status)

  queryPromise: (method, data) ->
    new Ember.RSVP.Promise (resolve, reject) ->

      $.ajax
        type: "get"
        url: "http://whatever.com"
        crossDomain: true
        dataType: "json"
        success: (data) ->
          # All async code has to be wrapped with an Ember.run
          Ember.run ->
            resolve(data)
        error: (xhr, ajaxOptions, thrownError) ->
          Ember.run ->
            if (xhr.responseJSON) 
              resolve(xhr.responseJSON)
            else
              reject(xhr)

Get an object from the data store synchronously

this.store.getById('user', 1) (thanks @eoinkelly)

ManyArray

A ManyArray has no .length or [index] or for obj in array. Instead, use .get('length'), .objectAt(index) and array.forEach(function(obj) { ... }).

Adding a label from="id" to an Ember text field or view

From http://stackoverflow.com/questions/10468164/using-ember-js-text-field-ids-for-a-label-tag, the following won’t work:

<label {{bind-attr for="content.field_id"}}> {{content.label}}</label>
{{view Ember.TextField valueBinding="content.data" id="content.field_id"}}

You need to instead use a viewName and reference this with a bind-attr:

<label {{bind-attr for="view.textField.elementId"}}> {{content.label}}</label>
{{view Ember.TextField valueBinding="content.value" viewName="textField"}}

Initialising model properties

See also this discussion on why Ember uses prototype inheritance and how it can mess things up wonderfully.

var Month = Ember.Object.extend({
  setWeeks: function() {
    this.set('weeks', Em.A());
  }.on('init')
});

Run Javascript after EmberJS Route Render

For example, if you need to enable JQuery tooltips on an element in a Handlebars template, you can Ember.run.next:

App.FoosNewRoute = Ember.Route.extend
  model: (params) ->
    @store.createRecord('foo')

  renderTemplate: ->
    @render 'foos.new',
      controller: 'foosNew'

    Ember.run.next @, ->
      $(".tooltip-span").tooltip
        container: 'body'

Or, if you are using a view:

App.FooFormView = Ember.View.extend
  templateName: "foo/form"

  didInsertElement: ->
    Ember.run.next @, ->
      $(".tooltip-span").tooltip
        container: 'body'

TypeError: cyclic object value

Make sure that you aren’t trying to save an object property that isn’t a DS.Model object. If you are, you may need to define a transient flag on the property, so that the JSONSerializer does not try to serialize the cycle: see Transient DS.Model Attributes in EmberJS.

Untested

  • Em.set(App, 'mapInstance', Map)
  • Em.get(App, 'mapInstance') or App.get('mapInstance')
  • App.__container__.lookup('store:main') - maybe to get the data store instance (thanks @jamesotron)
  • App.__container__.lookup('router:main').router.transitionTo('myroute') - manually transition to a route (thanks @eoinkelly)