view page source - page history - about editing

Revision History: EmberJS

This is revision 492 of the page EmberJS, as it appeared on Tue, 22 Apr 2014 16:09:41 -0700.
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. npm, bower

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}}
    ...
--}}

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')
});

Untested


view page source - what links to here? - page history - top
Last edited by jevon jevon 42 months ago