I am new to Ember (only been using it about a week now), and I am very confused about the intended application design. From what I can tell so far, Ember sort of forces a particular design onto the application, and I am confused about why.
I have been told that I cannot have an MVC set (a model, a view, and a controller for a particular thing) without a route. To me, this is very confusing; I do not understand why Ember is forcing me to assign a navigable route to something that doesnât necessarily need (or makes sense to have) a user interface.
What I would like to do, is to have all of the components of a page (not âcomponentsâ as in the Ember âcomponentâ) be in an MVC format. However, not all of these components should have a route assigned to them.
For example, if I had an application that allowed users to CRUD entries about books, I would want them to be able to set the genre. The list of available genres would be loaded via Ember-Data since itâs not hard-coded. However, I donât want to have a route /genres, I just want to use the data in that model, or potentially use it as an MVC set (where genre would have a model AND a view and controller). I also donât want a nested route such as /book/genre/, I just want to be able to include the genre list wherever and whenever, allowing it to be controlled by the controller, viewed with the view, and backed by the model.
Iâve scoured the Internet and asked on StackOverflow, but I am still very confused.
Any help or clarity is extremely appreciated. I am also well aware that I am probably incorrect in my understanding of how Ember works.
Are you talking about ember routes or your REST API URLs? When using Ember Data, you will need to have /genres URL in your API if you wish to store list of genres as masMany relation, but you wouldât need to have one for, for example, comma-delimited string.
The reson why API should have an extra route is because it is recommended to follow JSON API conventions.
You centainly can create Ember.Controller or Ember.View without having related Ember.Route.
Routes are about routable state - urls. If you donât want an extra url then donât create a route.
You can use the {{render}} helper to render a template, controller, view and optionally provide a specific model in your templates. This is probably what you are looking for.
Be aware that the âMVCâ in ember is probably different to what you are used to - Model is the same, Views are an abstraction around DOM elements and are mostly used for handling DOM events or occasionally (to be avoided) manual DOM munging, and controllers are more of a âpresenterâ, they decorate your models and present them to the view and connect with other controllers through the âneedsâ api.
This isnât necessarily true - if you want to load your genres at the same time as your books you can sideload them in the request to /books. This would be recommended for performance (fewer http requests)
Thanks for all of your responses, but Iâm still extremely confused.
I still canât figure out how to properly put this list of genres onto a page about a book, to the point where I really donât even know how to ask the question without pasting code.
I have a route/model/view/controller/template for Book. That all works fine. In the book template, I want to show the list of genres⌠so I made a mode/view/controller/template for genres:
Controller:
App.GenresControllerExtend = Ember.ArrayController.extend({});
App.GenresController = App.GenresControllerExtend.create();
// simulate a REST call to populate the controller (model??) with data
setTimeout(function () {
App.GenresController.set('content', App.Genre.FIXTURES);
}, 500);
I then try to insert this view into the Book view with:
{{view WA.CategoriesView}}
Several questions:
Is there any way to just use the Chrome console instead of the annoying Ember debugging methods? I have to use the âlogâ Handlebars helper in order to get any useful data and I canât use my beloved Chrome console. I tried using âApp.container.lookup(âcontroller:genresâ);â as it says on the guide, but it returns âundefined is not a functionâ. If I use something like console.log(App.GenresController);, it just returns âApp.GenresControllerâ as text.
If something isnât part of a route, does it get all the naming-convention witchcraft? When I made the genres view, it wouldnât work unless I specifically told it to use that specific controller and template. Is this because it doesnât have a route? And does this affect all of the other places where the naming convention thing comes into play? For example, when âExampleControllerâ gets converte to âexampleâ for use in the âneedsâ property of another controller. I read somewhere on StackOverflow that it is bad practice to explicitly set the controller for a view, but I see no other way. Again, I donât want a route for genres. It doesnât need a route and shouldnât have one.
Instead of using the {{view}} helper, I tried using the {{render}} helper as such:
{{render âgenresâ genres}}
And that returned âundefined is not a functionâ, then I figured this was the wrong sort of helper entirely. The documentation says that the first parameter is the âcontextâ, but I donât know what that means in this situation. I figured it was just the variable off the Book model, but then I thought thatâs what the second parameter was.
When I create the controller, why do I first need to âextendâ it, THEN create it? From my understanding, âextendâ basically makes a subclass of the class being extended, but in my case they should be the same thing. I just want to create an instance of an ArrayController, not extend it into some other class first.
Is Ember the right framework for me? From what I am seeing and from what I have heard, EmberJS likes to force a specific type of application structure on the developer, and if you donât want to follow that structure, then youâre out of luck. Does Ember support the kind of things I want to do nicely, or would I have to hack it in with some way that defeats the purpose of using a framework at all? I want to have everything managed with MVC, but not at the level of routes. On one page, Iâd like several things to have a model/view/controller, but most of them wouldnât have routes.
Is there a good way to learn this framework quickly? From what Iâve read, it takes people months to get a handle on this framework. In terms of learning curve, this might be the steepest Iâve encountered. I really donât have months to learn it. From the taglines (âGetting started with Ember is easy!â, âMore productive out of the boxâ) I thought it would be an easy task to get a simple application up and running, but itâs turning into quite a chore. The taglines are very misleading. The fact that ember does do much âmagicâ under the covers is one of emberâs selling points, but it also makes it exponentially more confusing for someone trying to learn how it works.
I tried again and it looks using just create() instead of extend()+create() works for me. I must have had some other configuration written incorrectly.
App.GenresControllerExtend = Ember.ArrayController.extend({});
App.GenresController = App.GenresControllerExtend.create();
// simulate a REST call to populate the controller (model??) with data
setTimeout(function () {
App.GenresController.set('content', App.Genre.FIXTURES);
}, 500);
This is very wrong, you seem to be confused about the difference between classes and instances.
Ember will create the controller for you. You should pretty much never call create() on a controller. Ember must create the controller instances for you.
You should generally load the data into the controller in the model hook of a route:
You can simulate ajax there if you want, by returning a promise:
App.GenreRoute = Em.Route.extend({
model: function() {
return new Em.RSVP.Promise(function(resolve, reject) {
// or add setTimeout if desired.
resolve(App.Genre.FIXTURES);
}
}
})
Use the ember extension for this as mentioned by @muchweb
As mentioned you have been defining your controllers wrongly. Use the render helper.
You should be using the render helper for this.
Generally you assign content to controllers in a route, then you can use the render helper to render them. The render helper renders a controller, template and view combo, and you can optionally pass in a context.
In your case, it sounds like you donât need a route just for genres. Thatâs fine, in your existing route you can setup the controller appropriately using controllerFor:
App.BooksRoute = Em.Route.extend({
model: function() {
return Em.RSVP.hash({
books: $.getJSON('/books'),
genres: $.getJSON('/genres')
});
},
setupController: function (controller, context) {
this._super(controller, context.books); // this assigns the books to the BooksController
this.controllerFor('genres', context.genres);
}
})
Now you can use {{render âgenresâ}} in a template.
You donât. You should never manually create a controller. Ember will create the instances for you.
Ember supports what you are trying to do nicely, trivially in fact, with very little code. It just has to be the right code.
There are several books out, or you could go to a training course. But all the info you need is in the guides, and then the API docs. You should make sure to read all the guides in order, and consult the API docs for further information. Ember does have a steep learning curve but ultimately the decision to use it is up to you. I have found that it saves me massive amounts of time now that I know it.