I didn't set tagName in TreeGridRowComponent. Since it's used to show each row in a table, so I had <tr> in the template. This should be in <tbody>. Ember.js wraps the template in <div>. The Html is supposed to be <tbody><div><tr>...</tr></div></tbody>. But for some reason Firefox rearranges it to <div></div><tbody><tr>...</tr></tbody>. It looked fine at the beginning. But when I tried to update the row, it failed. What happened was that Ember.js looked up the target element from <div> element. <tr> was't a descendant of <div> any more. Ember.js failed to find the element and it didttn't do anything.
The best way to learn is to practice. So I made a small component with Ember.js.
This component is a tree grid. It's a grid, and it acts like a tree too. It presents a tree in a grid. Each node in the tree is a row in the grid. So node and row are used interchangeable. There is a parent-children relationship between rows. All children rows are displayed under their parent row. These children rows are indented. There are operations on rows too. You can choose to show or hide their children rows.
I'm not going to write an Ember.js tutorial. You can find good ones online, for example, http://code.tutsplus.com/tutorials/ember-components-a-deep-dive--net-35551 and http://coding.smashingmagazine.com/2013/11/07/an-in-depth-introduction-to-ember-js/#what_is_handlebars_template_precompiling. I'm not going through all details of how I made it. You can read the code and history from Github https://github.com/kceiw/treegrid-emberjs. The purpose of this blog is to share the lessons I learned, something that are not obvious or I didn't pay attention to it at the beginning. You may have a much better idea of how to make it and how to use ember.js. But as I began, I made these mistakes.
1. User .get('propertyName') instead of .propertyName.
Accessing to properties directly will give you undefined. e.g. ArrayProxy.length is undefined. You have to use ArrayProxy.get('length') or ArrayProxy.set('length');
It confused me at first, especially when I looked at the API. There is length in ArrayProxy. How come it's undefined. But later I realized that I needed to use get() to get property values. It's documented in the official guide. But I didn't think too much of it at the beginning. I think this is weird to some extent that properties are not accessible directly.
2. Set tagName in view/component.
If it's not set, the default value <div> will be used. Everything in the template is wrapped in the tagName. I think it's always a good idea to set a tagName in view/component because <div> is not always the correct one.
3. classNameBindings value is an array of string. Each string is a class name or expression to determine the class name. It's in the form ['property1:style1:style2', 'property2:style3:style4'].
You should read this API.
The view API:
4. Css icon
This page http://www.dynamicdrive.com/style/csslibrary/item/css_triangle_arrow_divs/ explains how it works. Didn't know it before.
Don't need to set both height and width to 0 though.
They'll affect the perceivable width and height.
In my tree grid, I shown the down arrow when the row is expanded and right arrow the the row is collapsed. I used to set both height and width to 0. When I expanded and collapsed, I noticed that the height of the row changed too. So I just set only one of them to zero and the other was the size that the icon should be.
5. Keyboard focus
Focus is always the prerequisite of keyboard events. There is a way to set the focus to the tree grid in initialization.
6 Only one action
One thing I like to be in Ember.js is to support multiple actions. Each component can only send one action now.
There are a few things worth writing down in the end.
There are a few confusions such as render and component and view. There are no clear guidelines when/how to use them.
Action is a good concept to handle semantic events. But it has the limitation that one component/controller can only send one action.
Css icon is an interesting way to draw simple icons. I'm not clear the performance v.s. image icon.