Well, I don't know EmberJS but for the handlebars code you showed, seems like the controller is somewhat more like a ViewModel (MVVM pattern), maybe learning KnockoutJS first would help a bit?
Rob has done knockout, and that's pretty unrelated I feel. I've spent a lot of time doing Knockout and a fair amount of time in Angular and Backbone, and personally I sort of agree with what rob is saying. I feel like they have taken MVC and just loosely applied it in Ember, because they have Models Views and Controllers. I see and understand where his confusion is coming from. I probably also haven't spent enough time with Ember to get it, but I also don't feel like I want to.
> The downside to this approach is that your HTML is "compromised", if you will, and many developers don't like that. My thought is that it's already compromised using Handlebars so what's the difference here? Personally I have no issue using the ng-* directives. Some people do, and I respect that.
I'm a bit off-topic, but you don't need to "compromise" your HTML with AngularJS, you can place "data-" in front of your attributes and you're HTML-compliant again :).
Absolutely true - I should add that in. I think people look at that, however, and don't like functionality etc. shoved into the DOM. But your point stands.
When I hear this argument I believe the concern is not the syntax of the binding with respect to the HTML spec, but rather the declaration of bindings in HTML at all. So the issue is not "ng-click" vs. "data-ng-click", but that "ng-click" in any form is no different than the pre-JS MVC horrors of onclick="mutateGlobalStateAndPerformIO()"; which is precisely the barbaric approach we thought we were vanquishing. I think that some people prefer to see bindings sprinkled on the DOM via code, as part of the bootstrapping process. I haven't used Backbone for a year but I'm pretty sure it is a strong proponent of "let nothing live in the DOM" school of thought. I don't subscribe to that, by the way, but that's the argument.
Nothing, but some feel rather strongly averse to it, and plainly view this as Angular's self-evident fatal flaw. As I said I do not subscribe to this line of thinking. My allusion to the horror and barbarism of the pre-JS MVC was merely a jape.
What happens when you want to add a second, unrelated, thing? Just stick it on the end in the onclick? Create a new function called doTwoThings()? This is one of the reasons I prefer using an observer pattern over MVC.
That doesn't really happen though - also, Ng-click is a specific directive you can choose not to use.
A more general argument is that any behaviour specified in markup is bad. I'd counter that by saying that it's already there in HTML. Input boxes for example have behaviour intrinsic to their being. So angular let's you create a (for example) richtext tag. You attach behaviour to that tag, say on click. In the HTML it's as clean as <richtext>. Within the directive you can make it behave as you please.
I think that people see the shortcut directives used in angular (eg Ng-click) and the purists shout "unclean"! The reality is that You can do things a slightly longer way and end up with something thy looks a lot like the observer pattern.
In Angular HTML is the view so that's where ng-click and friends go, while other MVC frameworks have view js files. I know people like to be 'unobtrusive' but many JS MVC apps would be useless without JS so there's nothing to fall back to (other than a plz turn on JS message).
I dislike data binding with a vengeance. From Windows Forms, to Web Forms, to WPF, to Swing, to QT QML, to AngularJS. I don't think this pattern will ever work for me.
The examples provided to describe the difference between controllers in Ember and Angular do not appear to be different to me at all. In fact I'd argue that they are identical. It feels to me as though the author is wanting them to be different because maybe it's a style preference from the templating perspective?
The examples were to show how $scope is used in Angular vs direct use of the Controller/Model proxy in Ember. This makes a bit more sense to me, personally.
Interesting - didn't know this. $scope is injected by Angular and available to the view - is this the same thing? I didn't think Ember had a DI aspect to it.
Really nice constructive writeup (as always by Rob), and I think it should be addressed by some better EmberJS docs and tutorials. They do a good job explaining the "what", but it could probably use more "why".
It took me a while as well to figure out why controllers proxied to models. However it started to make a lot of sense in when building an app, since the controllers are there to stay around, and the models are swappable.
Having the option to easily swap out a model at the controller level is worth the extra layer abstraction. That and the ability to add additional UI specific properties on the controller that don't necessarily belong in the model (since they don't need to be persisted).
I've never used EmberJS and am not familiar with any of the front-end JavaScript frameworks, but I don't get what's confusing.
It looks like instead of the controller pushing data to the view, the view asks the controller for data (which it might proxy to the model).
This makes sense with a long-running controller, right? On the web both the controller and view are ephemeral -- they last for just that one request -- but if the controller is running continuously then it needs to reflect changes in the models as they happen. The model(s) the controller references can change without the view changing its reference to the controller.
Without something like this the view would render stale data. I'm assuming this is why we have a controller.model, to add that layer of indirection.
What am I missing? How is this more complicated making the controller<->view relationship pull instead of push?
The controller is the data. The model is grafted onto it for convenience. This ties the view to the model to the controller which is sort of orthogonal to "separation of concerns". In my opinion at least.
The controller is responsible for rendering the view when the data changes. It does graft the model data - and any other data you want renderable into the view. I wouldn't characterize it as "the data" however.
As mentioned above, the proxied model data is actually stored in a controller's "content" field. So that snippet is actually just shorthand for {{#each controller.content}} {{/each}}
It's not quite a shorthand as the controller can have properties of its own as well. However, the general understanding is correct, the controller proxies to the content. The controller is not the data, but it acts like it.
@rob: The controller should be the data as far as the view is concerned. Otherwise the view knows too much and the controller can't re-proxy a different model.
Knows too much about what? The view lives to present the data to the user - that's all it should know. The fact that the controller is the data is a design problem.
The data could be coming from multiple places and sources, only some of which are "models." This is true in Rails, too.
For the sanity of the view, the controller is the single point where it can get the data. It shouldn't know the nitty gritty details about where it came from, whether it's a "model," or anything else. The view is just, "Gimme the data, controller! Gimme!"
This principle is just as valid in Ember as it is in Rails. The only difference I see is that because the controller and view have to live forever, so to speak, it makes more sense for the view to pull data from the controller rather than have the controller push data to the view.
Maybe think about it this way. How is this any different than rails, really? In Rails you set goddamn instance variables in your controller actions. The view and controller are straight-up sharing state.
How is that less coupled?
This would be like the controller exposing getting and setter methods and instead of typing
<% @users.each do |user| %>
<li><%= user.name %></li>
<% end %>
you'd type
<% controller.users.each do |user| %>
<li><%= user.name %></li>
<% end %>
It seems like Ember does some "nice things" to handle the common cases and that there are additional assumptions, like maybe one model per controller (not sure I understand that), but there you go.
Ember seems less coupled all around than Rails and because of its long-running nature needs the view to poll the controller.
That's not how I'm seeing it. The controller has data, some of which might be from the model. The view shouldn't care whether the data came from a model or not. It would be coupling if the view did care.
The view asks the controller for data. The controller might delegate that question to the model. The view shouldn't care whether the data was delegated or not; it should just get a response from the controller.
Seems like textbook object-oriented design. Otherwise how will the views update automatically when the models change? The views shouldn't know what models it needs. In fact, it seems they shouldn't know that models are a thing at all. It's just data from the controller.
This is actually where I think Ember does better than the Angular sample provided. Ember controllers hold the "data" in a "content" field on the controller (proxied). Any model can be placed there. If you do add a "people" field to the controller (as in the sample) I'd argue that does what you're describing here as "bad" because it's specifying information in the view about the model.
Great explanation. I'm not sure why (or if) ember states it so clearly.
A view calling controller.model.property is MORE tightly coupled than controller.property. The controller is tied to the view and the model as it's supposed to be. The view is not tied to the model.
No, it's not. Because a single controller over its lifetime can be bound to many different models.
The controller is glue. It brings together whichever model is appropriate at the moment with whatever view is appropriate at the moment, and makes decisions about when to change those things.
The Angular example is a bit incorrect... when you do an ng-repeat, you're going to do like ng-repeat="person in people" and then each template item will be like {{person.name}} as opposed to just {{name}}.
Just a little clarity in the code. Thanks for the writeup!
> When talking routes, urls, and resources - that's a RESTful consideration and involves stateless state "stuff" (sidestepping the REST debate here). What is this concept doing in a desktop app?.
Ember is explicitly not about "desktop apps". That's actually why Ember broke off from Sproutcore. Ember is very opinionatedly focused on building web applications that are native to the web and stick to web conventions.
The best web applications still behave like the web is supposed to behave: they have shareable, bookmarkable URLs that allow the application's state to be recreated. This is a big reason Ember's router is different than the other examples you mentioned -- in Ember the router automatically handles a lot more of the state reconstruction stuff.
> The team has been rather clear that Ember is Desktop MVC, not web/server based
That's orthogonal to what I'm talking about. I agree that their use of the term "MVC" is much closer to the original meaning it had on the desktop (like in Cocoa) than the meaning in server-side frameworks like Rails.
But I'm not talking about what MVC means. I'm talking about what kind of applications Ember is intended to be used to build.
A flagship example would be Discourse, which is very deeply web-focused, and nothing like the way you would structure a desktop application.
I'd definitely say that Ember is more Desktop MVC than MVC2. True to it's Sproutcore/Cocoa roots, you are supposed to be able to wire up a lot of the application with the built-in controllers that don't have to be customized (or at least customized very little). Ember is trying to take that approach, make it more familiar to web developers, and add in some additional parts that are part of what makes the internet work (ie, routers for managing state/bookmarkable urls).
Think of Ember controllers as proxies, or pointers if you will.
The idea is you can have a commentsController instance, and when you switch to a different post, the view(s) bound to it will automatically pick up the new comments array that is swapped out on behind the controller.
Routing is just rewiring the pointers on your controllers and getting the right views up on the page.
While I actually totally agree with the confusion in the router, I want to explain what I see in Ember's MVC:
As far as I attempted to implement it in my app (https://github.com/thomasboyt/noted-app), it seemed simple enough. Models were data; all they contained was their properties and operations that controlled their properties.
I mainly used controllers as the "state" for parts of my app. In Ember, this doesn't even need to mean it's tied to a specific model type. For example, my Dropbox integration is handled within a controller that's bound to several separate views (in this case, those views included buttons that triggered syncing and modals that displayed the progress of syncing). There's no "Dropbox model," just other models that I'm using this controller to sync. Controllers are not simply an intermediary between models and views, they are an intermediary between state and views.
> I'm trying my best to reconcile this with the notion that a controller (classically speaking) is supposed to ... well control the view. Here, it's not doing that.
I think what the author was looking for in controllers is what's actually handled by, well, views. The view handles any user interaction, and then uses the controller to change the state of various bits (whether calling methods in the controller or simply updating properties on it).
To sum up: model is data, controller is state (including instance(s) of models), and the view is user interaction. Templates can bind to properties on any of these. Routes are what hook these components together depending on the page.
Seems reasonable, but the Ember team sees it differently... they put state in the router:
>Most of your controllers will be very small. Unlike other frameworks, where the state of your application is spread amongst many controllers, in Ember.js, we encapsulate that state in the router. This allows your controllers to be lightweight and focused on one thing.
Nah, kidding. So they're totally right that there's a significant amount of state in the router, in that that's where you define which model and controller (and, depending on how fancy you get, what views and templates) to use on a given page. So those are essentially state.
The state that can make a controller fat is essentially state that's too important for a view but doesn't need to be universal to the page. For example, with my Dropbox controller, the controller has a state property that handles the various permutations of the state of syncing (i.e. it could be doing nothing, currently saving, done saving, failed saving, etc.). This state is set by the controller on the controller, and used by multiple views to determine things like which label a progress modal should have.
For example, if you had a controller representing a list, you might want to keep track of which item is selected on the controller. That way, if there are multiple views that can act on the currently selected item (for example - you might have a list item view that has a template that renders the item, and then a separate view that are buttons that trigger actions that act on the current item), they all have access to it.
Plus, I always think of state defined in a router as being limited to specific pages/routes, whereas some of my controllers are used on several different routes.
In this case, the "state" that we're talking about is "what state are you in". In other words, the router manages high-level state ("I am looking at a post now"), and provides long-lived controllers with data reflecting that state. So even though there is information about the current state in the controller (and the view), the source of truth about the current high-level state is in the router.
"Application state", rather than "stateful vs stateless" state. The router specifies "I'm looking at a post now" and the controller specifies "Looking at a post means loading this particular Post model as well as these comment models"
I've found a more specific term than 'high-level' state to explain the router state is 'addressable state'. A single page web application has two types of state. Addressable state (which is stored in the Ember router) and then another form of state, let's call it non-addressable state which is stored in the controllers.
As an example you could have a web application that has multiple documents and inside each document there are panels that can be expanded and collapsed. As you switch between documents each document maintains its own version of which panels are expanded or collapsed.
In the Ember world the router would maintain which document was opened (addressable state) and the DocumentController would maintain which panels are opened (non-addressable state).
I think that that's exactly what it is. I've come to believe that every application needs a state machine that contains the shared logic and state that everything could possibly need to interact with.
I think the problem is MVC itself is a confused mess. It means whatever each person wants it to mean, since it's too easy to make up a bunch of reasonable sounding argumentation for whatever you want to do if you use the words model, view, and controller a lot.
Yeah, I even wrote my own MVC framework for a small project and I still don't know what MVC is "supposed" to mean because every single implementation example I see is completely different and at odds.
This is the comment I agree with most. Replace a solution defined as a "design pattern" with one defined as a data structure and you get a lot more clarity. The problem MVC solves can be recomposed as "synchronization of concurrent, related, mutable data structures." The relations are definable as a DAG for each direction; the synchronization process with a cyclical graph.
That, coupled with the fact that MVC (the classic, desktop MVC) seems shoehorned in webapps, makes me weary when frameworks tout their MVCness before stating their distinctive features.
BTW, I'm much more adept of removing the controller and going to a tightly coupled stack of view-model with the use of the observer pattern where needed. Controllers remind me of that extra indirection that seems useful in design but is never really used and is thus just unnecessary complexity.
I feel that as with many things in Computer Science, the original MVC-stuff is regrettably "under-read"[1] by a lot people. I highly recommend having a look at the various links on:
for those that haven't read what the original model-view-controller-user idea was all about. It makes more sense from a Smalltalk/Self/Object-C/Message-passing style of object orientation ("true object orientation") than from java -- in this sense it should be a good fit for javascript as well -- but unfortunately java/c++ style object orientation (really "class-inheritance orientation") have bastardized MVC to mean something subtly different (I am not quite sure what, exactly, but I don't think I'm the only one...).
> I think the problem is MVC itself is a confused mess.
I tried to get to the core idea, and I think it is to separate things as much as possible, and minimize interconnections, so as to keep complexity down.
In practice it means to create components (objects) that keep their guts hidden and offer an official "API" to use them.
This might seem far from MVC, but what is the purpose of MVC if not to protect us from the exponential complexity black hole?
Your examples are incorrect. The Route's model is set as the content of the controller, so all you need to say is #each item in content. Your model is set as the "content" of your controller, so your model is not "nowhere to be found"
You should use {{#each item in controller}}, otherwise you won't get things like sorting of filtering right. Yes, content is an underlying array, but controller may present it differently (filter out, sort, paginate etc.).
Instead of controlling the view directly from the controller, the view uses the controller object (proxy to model) in any way it wants allowing you to change the view without changing the controller and same with the controller. I think the issue you are facing is thinking that you are tightly coupled to the controller by using the controller object, depending on what you think about how much coupling is too much coupling you can argue that just using one object might really be decoupling. I'm not sure if I was able to get my point across.
I think the way controllers work here is similar to Ruby on Rails? It confused me in Rails at first (coming from the Java world), but I think it is essentially just a hack to allow for "easier" passing of data to the view (the controller gets exposed to the view). So instead of scope.whatever = "hello world" you can write this.whatever = "hello world" (OK not really shorter, but something like that).
That usage of Controllers is not part of the MVC pattern, I'd say. It's just a recycling of the controller instance - not forbidden, just confusing if you wonder what it has to do with MVC.
Actually it's also the RoR way to have short lived controllers (a controller is instantiated for every request), other frameworks use one static controller instance instead.
That's the hunch I had reading this (as someone with no EmberJS experience).
To digress a little, it's not much different than the terminology confusion in Backbone, where:
- Router(s) work as front controllers,
- templates (along with the browser's DOM) as views, and
- Views as presenters (from the MVP pattern).
Models are flavored with the Active Record pattern. Presenters and views are tightly coupled.
MVC and MVP coexist because the controllers respond to navigational input (mapping to model-presenter pairs) and the presenters respond to page-specific input (mapping to model manipulations and, possibly, server calls).
At first read, I thought your point about routing was really good - why not have route('about').template('aboutTemplate').controller('aboutController') - and then I realized this is all reapeating the same mumbo jumbo. This is all automatically matched up by the naming convention (which frustrates me too, but until I figure out a better way...)
Though, I understand the pain of coming from a server-side MVC architecture, I found it refreshing that Ember.js takes the "desktop" MVC approach. Our web apps are now living on the client, acting like desktop apps. Most people struggle with this reverse at first, but can conceptually catch on if shown the way. I think what really needs to happen is a good screencast or two walking through these concepts. I'm interested in putting something together and will when I have the time.
While there is quite a deal of information on integrating ember-data with rails, there is much less on integrating it with other server-side MVC/REST frameworks.
This means that using it with another framework often means modifying that interaction pattern to be more like how rails views ajax, complete with the root objects ({"model":{}}).
This may more accurately apply to the REST driver in ember-data, but that is quite tightly coupled with the rest of it.
As far as the root objects are concerned, I've always been a fan of that part of Rails. Not to say that it cannot be easily gotten rid of with something like this (for ActiveResource)...
ActiveResource::Base.include_root_in_json = false
Or, like in my example app, with this (for ActiveModelSerializers)...
There seems to be some very positive buzz around this screencast mentioned both in the OP's blog and around HN in general: https://peepcode.com/products/emberjs . I found it particularly instructive but found that it only scratched the surface of this new framework. At least, it scratched enough off the top that I feel comfortable rooting through source and API documentation to figure out the rest. YMMV, of course.
i felt it did very well as an introduction. I think a deep dive into ember-data would be great for those who have been traditionally server side devs now getting into more of the client side stuff.
I come from Backbonejs background with which I have worked for about 1.5 years. So I feel quite comfortable with it.
I decided to try Emberjs - not for any other reason than trying to pick up something else and see how other JS framework approaches.
I gave full two-days worth of time into it. Initially I thought - "How different can it get?" Plus, I believe even if it's very foreign I'll just keep reading, googling, stackoverflowin', youtube-tutorialin' to get my head around.
I gave up though. Here's my hopefully constructive rant, though my views are probably not as deep as the OP's.
* Many of the posts on the net are outdated. I followed a few tutorials here and there, and then things didn't work, so I asked on Stackoverflow, then the answer I got was "Dude, your code is outdated". Sure this is probably similar thing for other frameworks - but I'm just sayin'
* Models - So there is Ember Object, which you can use as models, but you can also use Ember-data.js which is more "glorified" data. Documentation wasn't clear on the difference. Plus, Ember-data.js was quite hard to get started with. It didn't work well with other versions of Emberjs. I really had to dig in to find the right one to start off with. I ended up cloning a github repo of a tutorial that worked, because nothing else did.
* Documentation on "convention over configuration" - OK, so convention over conf. is fine. But the official documentation and many of the tutorials didn't explain what all the conventions there were. I went through a tutorial app, which only had Controller, but things just "worked", because the Emberjs builds all other things for you. Well I didn't know that! THE BEST INTRO EMBERJS VIDEO I found was this.
* But in the end, among all other things I wanted to do, I gave up, because the frustration was mounting up. I guess I can still persist through it. But I just finished AngularJS tutorial demo and in 2 hours, it makes sense to me.
The Ember teams has been planning for a sweep of all outdated information about Ember. We'll be updating SO questions and asking blog authors to add a disclaimer.
Ember Data is a completely optional component of Ember that seeks to bring ORM-like abilities to the client side. It's not as far along or as stable as core Ember. For what it's worth, you can easily just use jQuery.ajax and create Ember.Objects from the response. We probably do need better documentation in this area to make this clear. That said, it's not fair to count Ember Data as a point against Ember since no other framework has anything at all similar in scope.
Our overview documentation is lacking. This is something that we're actively working on improving. The hardest part for new developers coming to Ember is that the paradigms are very different than what they're used to. We believe that the paradigms are the correct ones, but we need to do a better job explaining them.
Without meaning to offend, I'm afraid I have to take issue with your points about Ember-Data.
Yes it's optional, and yes you can use jQuery.ajax or whatever, but in reality, it's not quite that simple.
The official guides in Ember default to assuming you're using Ember-Data (though they do at least mention it explicitly). This despite Ember-Data being far from production ready (as stated on the Github page) and far too slow for dealing with large quantities of data. At the same time, the conventions that are found in Ember-Data appear to be built in to core Ember (it says as much in the guides).
As far as Ember-Data not counting against Ember - it may be larger in scope than other client side data libraries (or the M part of other MVC frameworks or whatever) but the fact is that they are most definitely comparable, as it's the way that Ember gets stuff off the server, and saves it back to the server. Without Ember-Data, Ember has no built in way of doing that, which counts against it. With Ember-Data, well, it's not really ready yet, which also counts against it.
Ember is built to work with Ember Data out of the box, but it's trivial to make your own methods that fit with the conventions. I assume you're referring to the default `find` support in the router. All that Ember does is attempt to infer a class name and call `find(id)` on it if the `find` method exists. You can implement this method however you want, or even change your routes to call an entirely different method.
I totally get that it's different to what's in other frameworks (the router is similarly different), it's just that, for the most part, on the surface, it pretty much serves the same purpose (other than some relationship stuff that half works). That is, it's the same the same part of the framework, just with extra features. Oh, and with a whole load of undocumented coventions in it.
Btw, is there a diagram or something that shows how it's put together internally (I'm pretty comfortable with how to use it from an API perspective, but find myself having to dive into the source code fairly regularly)?
Unfortunately, no such diagram exists though it would certainly be useful. The lack of documentation is tied a lot to the instability of the Ember Data API, both of which are reasons why it hasn't had a formal release yet.
But, I really really think for a newbie (like me) to even find out that I can use jQuery.ajax to create Ember.Objects is confusing. The immediate questions following that would be
* How do I do that? Can I see an example? And where do I find a counter-example?
* Then why Ember Object (ok fine they provide cool ORM features, but when I'm starting, I just want to understand what/where things are)
I know a lot of people are raving about Emberjs, and personally it looks good and I really want to get into it, but really really really, I found it not-newbie friendly.
Creating an Ember Object is very simple: `Ember.Object.create(properties)`. If you want, you can subclass `Ember.Object` and then `create` an instance of your subclass. The main benefit to using `Ember.Object` is that you get convenience methods like `get` and `set` (instead of having to use `Ember.get` and `Ember.set`). You can also add computed properties and the like to subclasses. I think this is actually covered fairly well in the guides: http://emberjs.com/guides/object-model/classes-and-instances....
Creating an object instance with AJAX is as simple as just calling `create` with the data provided in the callback. However, you may want to create the object first, then update the object's properties in the AJAX callback. This is similar to how Ember Data handles things.
Also, `Ember.Object` has nothing to do with ORM. Ember Data addresses this with `DS.Model`.
Since Ember 1.0 isn't compatible with Ember x.0 you could save yourself a lot of that work by sticking to semantic versioning and just calling it 'Ember2'
I went through the same thing grandparent post did - a lot of old tutorials. I think it would be a good idea for Ember to make a complete break and to call this 1.0 release something else.
Semantic versioning states everything inthe public API should be considered unstable and changing until the major version is 1.
So whatever code samples are out there on blogs and SO were from the initial days of the API when it was changing a lot. I am with you and have been going through the pain of weeding out examples from the web that works with the latest version on GitHub. There were many methods that weren't even available in the current API.
Given the paradigm shifts with Router and the Controller, maybe what the Ember team needs to do now is to stop doing everything else and finish up on the documentation for their 1.0.0-rc.1 release before it is finalized to 1.0.0
141 comments
[ 4.4 ms ] story [ 220 ms ] threadI'm a bit off-topic, but you don't need to "compromise" your HTML with AngularJS, you can place "data-" in front of your attributes and you're HTML-compliant again :).
What's wrong with that? Other than scoping problems (which Angular solves), this is far more in line with classic view-controller than anything else.
A more general argument is that any behaviour specified in markup is bad. I'd counter that by saying that it's already there in HTML. Input boxes for example have behaviour intrinsic to their being. So angular let's you create a (for example) richtext tag. You attach behaviour to that tag, say on click. In the HTML it's as clean as <richtext>. Within the directive you can make it behave as you please.
I think that people see the shortcut directives used in angular (eg Ng-click) and the purists shout "unclean"! The reality is that You can do things a slightly longer way and end up with something thy looks a lot like the observer pattern.
It took me a while as well to figure out why controllers proxied to models. However it started to make a lot of sense in when building an app, since the controllers are there to stay around, and the models are swappable.
Having the option to easily swap out a model at the controller level is worth the extra layer abstraction. That and the ability to add additional UI specific properties on the controller that don't necessarily belong in the model (since they don't need to be persisted).
It looks like instead of the controller pushing data to the view, the view asks the controller for data (which it might proxy to the model).
This makes sense with a long-running controller, right? On the web both the controller and view are ephemeral -- they last for just that one request -- but if the controller is running continuously then it needs to reflect changes in the models as they happen. The model(s) the controller references can change without the view changing its reference to the controller.
Without something like this the view would render stale data. I'm assuming this is why we have a controller.model, to add that layer of indirection.
What am I missing? How is this more complicated making the controller<->view relationship pull instead of push?
How is the controller not the data as far as the View is concerned?
For the sanity of the view, the controller is the single point where it can get the data. It shouldn't know the nitty gritty details about where it came from, whether it's a "model," or anything else. The view is just, "Gimme the data, controller! Gimme!"
This principle is just as valid in Ember as it is in Rails. The only difference I see is that because the controller and view have to live forever, so to speak, it makes more sense for the view to pull data from the controller rather than have the controller push data to the view.
Maybe think about it this way. How is this any different than rails, really? In Rails you set goddamn instance variables in your controller actions. The view and controller are straight-up sharing state.
How is that less coupled?
This would be like the controller exposing getting and setter methods and instead of typing
you'd type It seems like Ember does some "nice things" to handle the common cases and that there are additional assumptions, like maybe one model per controller (not sure I understand that), but there you go.Ember seems less coupled all around than Rails and because of its long-running nature needs the view to poll the controller.
The view asks the controller for data. The controller might delegate that question to the model. The view shouldn't care whether the data was delegated or not; it should just get a response from the controller.
Seems like textbook object-oriented design. Otherwise how will the views update automatically when the models change? The views shouldn't know what models it needs. In fact, it seems they shouldn't know that models are a thing at all. It's just data from the controller.
A view calling controller.model.property is MORE tightly coupled than controller.property. The controller is tied to the view and the model as it's supposed to be. The view is not tied to the model.
No, it's not. Because a single controller over its lifetime can be bound to many different models.
The controller is glue. It brings together whichever model is appropriate at the moment with whatever view is appropriate at the moment, and makes decisions about when to change those things.
text-only: http://webcache.googleusercontent.com/search?q=cache:http://...
Just a little clarity in the code. Thanks for the writeup!
Ember is explicitly not about "desktop apps". That's actually why Ember broke off from Sproutcore. Ember is very opinionatedly focused on building web applications that are native to the web and stick to web conventions.
The best web applications still behave like the web is supposed to behave: they have shareable, bookmarkable URLs that allow the application's state to be recreated. This is a big reason Ember's router is different than the other examples you mentioned -- in Ember the router automatically handles a lot more of the state reconstruction stuff.
They say as much in their guides as well.
That's orthogonal to what I'm talking about. I agree that their use of the term "MVC" is much closer to the original meaning it had on the desktop (like in Cocoa) than the meaning in server-side frameworks like Rails.
But I'm not talking about what MVC means. I'm talking about what kind of applications Ember is intended to be used to build.
A flagship example would be Discourse, which is very deeply web-focused, and nothing like the way you would structure a desktop application.
These apps are built on the web. One look at the Discourse Ember code and I think you'll understand perfectly the confusion I'm writing about.
But I'm curious: do you use Ember or are your responses "what you think"
While we're being pedantic, it's Model 2, not MVC2: http://en.wikipedia.org/wiki/Model_2
The idea is you can have a commentsController instance, and when you switch to a different post, the view(s) bound to it will automatically pick up the new comments array that is swapped out on behind the controller.
Routing is just rewiring the pointers on your controllers and getting the right views up on the page.
As far as I attempted to implement it in my app (https://github.com/thomasboyt/noted-app), it seemed simple enough. Models were data; all they contained was their properties and operations that controlled their properties.
I mainly used controllers as the "state" for parts of my app. In Ember, this doesn't even need to mean it's tied to a specific model type. For example, my Dropbox integration is handled within a controller that's bound to several separate views (in this case, those views included buttons that triggered syncing and modals that displayed the progress of syncing). There's no "Dropbox model," just other models that I'm using this controller to sync. Controllers are not simply an intermediary between models and views, they are an intermediary between state and views.
> I'm trying my best to reconcile this with the notion that a controller (classically speaking) is supposed to ... well control the view. Here, it's not doing that.
I think what the author was looking for in controllers is what's actually handled by, well, views. The view handles any user interaction, and then uses the controller to change the state of various bits (whether calling methods in the controller or simply updating properties on it).
To sum up: model is data, controller is state (including instance(s) of models), and the view is user interaction. Templates can bind to properties on any of these. Routes are what hook these components together depending on the page.
>Most of your controllers will be very small. Unlike other frameworks, where the state of your application is spread amongst many controllers, in Ember.js, we encapsulate that state in the router. This allows your controllers to be lightweight and focused on one thing.
Nah, kidding. So they're totally right that there's a significant amount of state in the router, in that that's where you define which model and controller (and, depending on how fancy you get, what views and templates) to use on a given page. So those are essentially state.
The state that can make a controller fat is essentially state that's too important for a view but doesn't need to be universal to the page. For example, with my Dropbox controller, the controller has a state property that handles the various permutations of the state of syncing (i.e. it could be doing nothing, currently saving, done saving, failed saving, etc.). This state is set by the controller on the controller, and used by multiple views to determine things like which label a progress modal should have.
For example, if you had a controller representing a list, you might want to keep track of which item is selected on the controller. That way, if there are multiple views that can act on the currently selected item (for example - you might have a list item view that has a template that renders the item, and then a separate view that are buttons that trigger actions that act on the current item), they all have access to it.
Plus, I always think of state defined in a router as being limited to specific pages/routes, whereas some of my controllers are used on several different routes.
"Application state", rather than "stateful vs stateless" state. The router specifies "I'm looking at a post now" and the controller specifies "Looking at a post means loading this particular Post model as well as these comment models"
As an example you could have a web application that has multiple documents and inside each document there are panels that can be expanded and collapsed. As you switch between documents each document maintains its own version of which panels are expanded or collapsed.
In the Ember world the router would maintain which document was opened (addressable state) and the DocumentController would maintain which panels are opened (non-addressable state).
BTW, I'm much more adept of removing the controller and going to a tightly coupled stack of view-model with the use of the observer pattern where needed. Controllers remind me of that extra indirection that seems useful in design but is never really used and is thus just unnecessary complexity.
http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html
for those that haven't read what the original model-view-controller-user idea was all about. It makes more sense from a Smalltalk/Self/Object-C/Message-passing style of object orientation ("true object orientation") than from java -- in this sense it should be a good fit for javascript as well -- but unfortunately java/c++ style object orientation (really "class-inheritance orientation") have bastardized MVC to mean something subtly different (I am not quite sure what, exactly, but I don't think I'm the only one...).
[1] "Well, I'm an old-fashioned guy. And I also happen to believe in history. The lack of interest, the disdain for history is what makes computing not-quite-a-field." -- Alan Kay http://www.drdobbs.com/architecture-and-design/interview-wit...
I tried to get to the core idea, and I think it is to separate things as much as possible, and minimize interconnections, so as to keep complexity down.
In practice it means to create components (objects) that keep their guts hidden and offer an official "API" to use them.
This might seem far from MVC, but what is the purpose of MVC if not to protect us from the exponential complexity black hole?
Just don't mix things more than you have to.
That usage of Controllers is not part of the MVC pattern, I'd say. It's just a recycling of the controller instance - not forbidden, just confusing if you wonder what it has to do with MVC.
Actually it's also the RoR way to have short lived controllers (a controller is instantiated for every request), other frameworks use one static controller instance instead.
Potatos, Potahtos.
To digress a little, it's not much different than the terminology confusion in Backbone, where:
- Router(s) work as front controllers,
- templates (along with the browser's DOM) as views, and
- Views as presenters (from the MVP pattern).
Models are flavored with the Active Record pattern. Presenters and views are tightly coupled.
MVC and MVP coexist because the controllers respond to navigational input (mapping to model-presenter pairs) and the presenters respond to page-specific input (mapping to model manipulations and, possibly, server calls).
http://vimeo.com/24487742
Though, I understand the pain of coming from a server-side MVC architecture, I found it refreshing that Ember.js takes the "desktop" MVC approach. Our web apps are now living on the client, acting like desktop apps. Most people struggle with this reverse at first, but can conceptually catch on if shown the way. I think what really needs to happen is a good screencast or two walking through these concepts. I'm interested in putting something together and will when I have the time.
This means that using it with another framework often means modifying that interaction pattern to be more like how rails views ajax, complete with the root objects ({"model":{}}).
This may more accurately apply to the REST driver in ember-data, but that is quite tightly coupled with the rest of it.
As far as the root objects are concerned, I've always been a fan of that part of Rails. Not to say that it cannot be easily gotten rid of with something like this (for ActiveResource)...
ActiveResource::Base.include_root_in_json = false
Or, like in my example app, with this (for ActiveModelSerializers)...
https://github.com/rails-api/active_model_serializers#1-disa...
I decided to try Emberjs - not for any other reason than trying to pick up something else and see how other JS framework approaches.
I gave full two-days worth of time into it. Initially I thought - "How different can it get?" Plus, I believe even if it's very foreign I'll just keep reading, googling, stackoverflowin', youtube-tutorialin' to get my head around.
I gave up though. Here's my hopefully constructive rant, though my views are probably not as deep as the OP's.
* Many of the posts on the net are outdated. I followed a few tutorials here and there, and then things didn't work, so I asked on Stackoverflow, then the answer I got was "Dude, your code is outdated". Sure this is probably similar thing for other frameworks - but I'm just sayin'
* Models - So there is Ember Object, which you can use as models, but you can also use Ember-data.js which is more "glorified" data. Documentation wasn't clear on the difference. Plus, Ember-data.js was quite hard to get started with. It didn't work well with other versions of Emberjs. I really had to dig in to find the right one to start off with. I ended up cloning a github repo of a tutorial that worked, because nothing else did.
* Documentation on "convention over configuration" - OK, so convention over conf. is fine. But the official documentation and many of the tutorials didn't explain what all the conventions there were. I went through a tutorial app, which only had Controller, but things just "worked", because the Emberjs builds all other things for you. Well I didn't know that! THE BEST INTRO EMBERJS VIDEO I found was this.
http://toranbillups.com/blog/
It finally made sense in the end for me.
* But in the end, among all other things I wanted to do, I gave up, because the frustration was mounting up. I guess I can still persist through it. But I just finished AngularJS tutorial demo and in 2 hours, it makes sense to me.
Ember Data is a completely optional component of Ember that seeks to bring ORM-like abilities to the client side. It's not as far along or as stable as core Ember. For what it's worth, you can easily just use jQuery.ajax and create Ember.Objects from the response. We probably do need better documentation in this area to make this clear. That said, it's not fair to count Ember Data as a point against Ember since no other framework has anything at all similar in scope.
Our overview documentation is lacking. This is something that we're actively working on improving. The hardest part for new developers coming to Ember is that the paradigms are very different than what they're used to. We believe that the paradigms are the correct ones, but we need to do a better job explaining them.
Yes it's optional, and yes you can use jQuery.ajax or whatever, but in reality, it's not quite that simple.
The official guides in Ember default to assuming you're using Ember-Data (though they do at least mention it explicitly). This despite Ember-Data being far from production ready (as stated on the Github page) and far too slow for dealing with large quantities of data. At the same time, the conventions that are found in Ember-Data appear to be built in to core Ember (it says as much in the guides).
As far as Ember-Data not counting against Ember - it may be larger in scope than other client side data libraries (or the M part of other MVC frameworks or whatever) but the fact is that they are most definitely comparable, as it's the way that Ember gets stuff off the server, and saves it back to the server. Without Ember-Data, Ember has no built in way of doing that, which counts against it. With Ember-Data, well, it's not really ready yet, which also counts against it.
I also highly recommend watching one of the follow talks about Ember Data: http://www.youtube.com/watch?v=_6yMxU-_ARs or http://www.youtube.com/watch?v=V8nnE948zxk. Both talks make it very clear that Ember Data is not at all comparable to what is offerred by other frameworks.
Btw, is there a diagram or something that shows how it's put together internally (I'm pretty comfortable with how to use it from an API perspective, but find myself having to dive into the source code fairly regularly)?
But, I really really think for a newbie (like me) to even find out that I can use jQuery.ajax to create Ember.Objects is confusing. The immediate questions following that would be
* How do I do that? Can I see an example? And where do I find a counter-example? * Then why Ember Object (ok fine they provide cool ORM features, but when I'm starting, I just want to understand what/where things are)
I know a lot of people are raving about Emberjs, and personally it looks good and I really want to get into it, but really really really, I found it not-newbie friendly.
Creating an object instance with AJAX is as simple as just calling `create` with the data provided in the callback. However, you may want to create the object first, then update the object's properties in the AJAX callback. This is similar to how Ember Data handles things.
Also, `Ember.Object` has nothing to do with ORM. Ember Data addresses this with `DS.Model`.
If there's a specific case you feel like we've missed in the guides, we'd love to have you file an issue about it at https://github.com/emberjs/website/issues.
I went through the same thing grandparent post did - a lot of old tutorials. I think it would be a good idea for Ember to make a complete break and to call this 1.0 release something else.
So whatever code samples are out there on blogs and SO were from the initial days of the API when it was changing a lot. I am with you and have been going through the pain of weeding out examples from the web that works with the latest version on GitHub. There were many methods that weren't even available in the current API.
Given the paradigm shifts with Router and the Controller, maybe what the Ember team needs to do now is to stop doing everything else and finish up on the documentation for their 1.0.0-rc.1 release before it is finalized to 1.0.0