Some random notes on the pangs of ember. Will be expanding as they are uncovered.
Say you have a form that maps to a model, something like:
<form>
<fieldset>
<legend>Who are you?</legend>
<ol>
<li class='field string required validate'>
<label>First Name</label>
<input name='user[first_name]'/>
</li>
<li class='field string required validate'>
<label>Last Name</label>
<input name='user[last_name]'/>
</li>
<li class='field string required validate'>
<label>Email</label>
<input name='user[email]'/>
</li>
</ol>
</fieldset>
</form>
To handle this in jQuery all you have to do is this:
$(function() {
$('#user-form').submit(function() {
var form = $(this);
var data = {};
var id = form.attr('id');
var user = App.User.find(id);
$('.field', this).each(function() {
// really, some `serialize()` function...
var name = $(this).attr('name');
var value = $(this).val();
data[name] = value;
});
user.updateAttributes(data);
if (!user.valid()) {
for (var key in user.errors) {
// firstName-input (pretend at least)
$('#' + key + '-input', form).addClass('invalid')
.append("<output class='error'>" + user.errors[key].join("\n") + "</output>");
}
return false;
}
});
});
... it took me like 5 minutes to write that, and I'm sure I can refactor that to something reusable in any app in an hour or two. Maybe even make it a plugin on Github, another 1 or 2 hours...
Now to make that same thing in Ember...
- Build the HTML form using Handlebars markup.
- Build the views
- Build the controllers
Not only that, think about orders of magnitude more variables.
First, build the HTML, simple enough (and getting excited because of how simple it seems):
{{#with App.newUser}}
<form>
<fieldset>
<legend>Who are you?</legend>
<ol>
<li class='field string required validate'>
<label>First Name</label>
{{view Ember.TextField valueBinding="first_name"}}
</li>
<li class='field string required validate'>
<label>Last Name</label>
{{view Ember.TextField valueBinding="last_name"}}
</li>
<li class='field string required validate'>
<label>Email</label>
{{view Ember.TextField valueBinding="email"}}
</li>
</ol>
</fieldset>
</form>
{{/with}}
Now, I don't want the model to update every time I enter something in the keyboard. After reading through docs and source code for a few minutes, I realize I can just change
{{view Ember.TextField valueBinding="email"}}
to
<input type='text' {{bindAttr value="email"}} />
But now in the first case, I'm using an Ember.View
object, and in the second case, am I using an Ember.View
instance? Not clear, so look it up in the docs. Oh, and if I remove that <input...>
element, what's going to happen do the bindings? Now all of a sudden I can't do the quick-and-easy $('input').remove()
. Instead, I have to do Ember.View.VIEWS[$('input[name="email"]').attr('id')]].destroy()
. That's pretty ugly. There's a way around that though, no worries! All you have to do is make the <form>
an Ember.View
, or wrap it all in an Ember.View
as a template.
But now, I want to start adding something like an autocomplete box, or the stackoverflow-like tag box. In jQuery I can just listen to the keyup
event, run some ajax, and position some divs over the text field:
$('input').keyup(function() {
var input = $(this);
var position = input.offset();
$.ajax({
url: '/autocomplete',
data: {query: $(this).val()},
success: function(words) {
var divs = [];
for (var i = 0; i < words.length; i++) {
divs.push('<div>' + words[i] + '</div>');
};
$('#popup').empty().append(divs.join('\n'));
}
});
});
Again, took 2-3 minutes to whip together that function.
For Ember what do I have to do? I have to create an App.AutocompleteView
, and should that be an Ember.ContainerView
or Ember.CollectionView
? Then I have to think about how and where the event handlers go (for clicking on the tag in the autocomplete box, for example).
Anyway, all of a sudden, with Ember, I have to have a full-on set of UIComponents, with very rich event handling systems, like flamejs:
- alert_panel.js
- button_view.js
- checkbox_view.js
- collection_view.js
- disclosure_view.js
- form_view.js
- horizontal_split_view.js
- image_view.js
- label_view.js
- list_item_view.js
- list_view.js
- list_view_drag_helper.js
- loading_indicator_view.js
- menu_view.js
- panel.js
- popover.js
- progress_view.js
- radio_button_view.js
- root_view.js
- scroll_view.js
- search_text_field_view.js
- select_button_view.js
- stack_item_view.js
- stack_view.js
- tab_view.js
- table_data_view.js
- table_view.js
- text_area_view.js
- text_field_view.js
- tree_item_view.js
- tree_view.js
- vertical_split_view.js
And those aren't easy classes to make, they're pretty involved. And now I'm up to 300KB of JavaScript just to get back to the ability to do basic things I could do in a few lines of jQuery.
Anyway, I'm not going to spend the time describing the details of all this, it would take hours/days. All I'm going to say now is I feel like I have to build basically sproutcore and then some on top of Ember.js in order to get back to what I could do with jQuery 5 minutes with only a few lines of code.
So what's your opinion on it's practical use?
Presumably the counterarguments goes: "For complex apps, larger teams, and when robustness is key, the extra overhead of development has a lower cost to the organization as a whole". Now, I haven't used Ember, but I'm curious how for any project you might decide to use jQuery vs Ember. Would you always go jQuery?