What's the purpose of ArrayController and ArrayProxy? - ember.js

I've been digging into EmberJS for one day :).
I've followed several examples. Some examples used ArrayProxy while others used ArrayController. I looked at the unminified source code and..guess what...Ember.ArrayController is simply extending Ember.ArrayProxy, but there's no extra methods or features in ArrayController.
So..my question is..why do we have two same classes?

From Ember's API Docs:
Note: As of this writing, ArrayController does not add any functionality to its superclass, ArrayProxy. The Ember team plans to add additional controller-specific functionality in the future, e.g. single or multiple selection support. If you are creating something that is conceptually a controller, use this class.

There is no difference between the two classes.
It's for all of us who are coming from SproutCore 0.9.x, 1.x and early SproutCore 2 betas and were just use to the name ArrayController I think. I'd recommend using ArrayProxy in case the core team decides to depreciate the one line of code that makes ArrayController possible :-)

Related

Template inheritance in Ember

I have several unrelated pages that use Layout A, and another set of unrelated pages that use Layout B. It's as simple as that, but I can't figure out how to do this in Ember the DRY way.
I understand that template nesting is equal to route nesting, but I do not want to nest routes because it'd mean the URL will be also nested. I want to nest templates only because the pages are unrelated.
What I want to achieve is essentially template inheritance.
I expected this to work, but Ember throws an error.
// app/routes/samePage.js
import Ember from 'ember';
export default Ember.Route.extend({
renderTemplate(){
this.render('somePage', {
into: 'layoutA'
});
}
});
This is the error I get:
ember.debug.js:18015 Assertion Failed: You attempted to render into 'layoutA' but it was not found
I also get this warning. It tells me to read this link, but I don't think it helps me.
DEPRECATION: Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated. [deprecation id: ember-routing.top-level-render-helper] See http://emberjs.com/deprecations/v2.x/#toc_rendering-into-a-render-helper-that-resolves-to-an-outlet for more details.
Here is what layoutA.hbs would look like. I know you can't have {{outlet}} multiple times in a same template, but you probably get what I want to achieve.
<div class="header">
{{outlet}}
</div>
<div class="content">
{{outlet}}
</div>
<div class="footer">
{{outlet}}
</div>
How do I go about doing this in Ember? It sounds like such a basic task that needs to be more clear. Do I need to implement a template inheritance helper (like the one shown here) by myself? Or perhaps, there's already an Ember add-on for that?
Unfortunately, there is no such thing as template inheritance in Ember. But there are two features that allows to reuse html-code:
Components is well-known feature of Ember. It allows to have a re-usable template and/or js code to control such template appearance and behaviour. Component has it's own context, so all data should be passed to it via properties. I recommend to use components for custom ui elements or when you need to reuse a part of template with some logic (for example, top navigation with user menu which depends on authentication can be moved to component). There is also a trick that allows to emulate template inheritance with components using multiple {{yield}}. Maybe that's what you want.
Partials seems to be less known (they are not even mentioned in official guide for 2.x) but very useful. This helper ({{partial}}) renders any template in current context. I recommend to use it when you need to break a big template into parts.
These features are enough to reduce an amount of duplicated code. You probably can't reduce duplicated code to zero with them, but in my opinion it's not critical. Just move what you can to partials/components and your templates will be clear enough. Use that trick with component and yield if you want to emulate inheritance.
Update
Couple of words about partials
If you google "ember component vs partial", you can see a few blog posts and answers on SO, in which ppl say "don't use partials". In many cases without explaining why. The main points that I found are:
Components are more isolated, decoupled and testable. And I agree with that.
Partials may be deprecated and removed in future. However, that was first said in year 2015, but at this moment partials are still there and not deprecated.
When I suggest to use partials?
When you have a big template that is hard to maintain and you can't drop that route in parts. It happens if you use some css-framework (like bootstrap or semantic-ui) and need to implement a couple of big 3-4 step forms, or add a couple of modals or display some complex entity. Using components in this case is unneccessary (you will not use them on any other page) and their isolation adds headache (you will need to pass data that you need to display as properties and add some action(s) to get user input in case of forms).
Why I suggest to use partials in this case?
There is no need to reuse such partial, we just want to break template for easier maintenance. For example, to have each step of 3-steps form in it's own .hbs file rather than having one big template.
If partials will be deprecated, it's easy to move that pieces back to one big template.
It sounds to me like your solution is pretty simply just to use Ember components. Ember components have their own template which can nested into your route's template with {{name_of_component}}, however using components does not affect the routing.
Perhaps I am misunderstanding your need, but it seems to me like this is the easy fix. Read about it here. If I am misunderstanding the question, please clarify!
What I want to achieve is similar to using named outlets, so I can output some content into a specific place. However, it seems like Ember's recommend way to do this is to use ember-elsewhere.
The documentation says:
Before named outlets were introduced to Ember the render helper was used to declare slots for this.render in routes. This usage is not common in modern, idiomatic applications and is deprecated. In general, the pattern of named outlets or named render helpers is discouraged. Instead use of ember-elsewhere or another DOM-redirection library should better serve these use cases.
I found this add-on to be easier to understand over partials and components.
This, or using partials/components is probably the best we can get as Handlebars do not have a template inheritance feature.
Or, I should be changing the way I'm creating the app, and use routes to do template nesting. That's probably the Ember way.

Customizing the implementation for auto generated controllers using EmberCLI

When using globals we could have defined App.Controller, App.ObjectController and App.ArrayController to control what class Ember will use to generate controllers.
With EmberCLI, I see documentation for routes - using app/routes/basic.js. This works fine.
Does it also work for views? What about controllers? How would I implement the 'basic' for each kind of controller?
Yes, this works for just about any object Ember would generate, including controllers. If you look here you can see that Ember looks for 3 different types of controllers to generate: basic, object, and array. You can override these defaults by creating the following files:
app/controllers/basic.js
app/controllers/object.js
app/controllers/array.js
Ember is moving away from views and controllers in favor of components. (See the Routable Components section of The Road to Ember 2.0.) To that end, I don't believe Ember-CLI provides the ability to provide a basic implementation of each of these controllers in order to discourage their use. (At least I could not find anything from searching the code base.)

Where can I find documentation on Ember's {{control}}?

I don't see a listing in the Ember API. Where can I find which parameters for this template method? Can I use it, given that it's an unfinished feature?
It is not a good idea to use {{control}} yet as it is still being developed and is very likely to change behaviour. Basically it will be like a sandboxed {{render}} which won't inherit any context. It is mentioned on this page of the emberjs guide:
{{control}} works like render, except it uses a new controller instance for every call, instead of reusing the singleton controller.
This helper is currently under heavy development, and will likely change soon.

When to use which controller type?

I seem to be getting more and more confounded at what appears, on the surface at least to be pretty basic architectural questions regarding building ember apps.
Which Controller type?
In the last month or so, I've seen people implement controllers through Ember.Controller, Ember.ArrayController, Ember.ObjectController, and Ember.ArrayProxy. Removing ArrayController and ArrayProxy (due to them being identical), what are common use cases between each type?
So far, i've been able to gather that:
ArrayControllers/Proxies should be used when you have n elements within the view you intend to control
ObjectControllers should be used when the view is simple enough to maintain it's state in a single object, or be a single instance of a model's object.
Controllers --- ? No idea.
What are some basic differences between the controller types? There doesn't seem to be concrete information on when to use which, and for which use case. The API docs are good at telling me the nitty gritty of each of them, but not WHEN to use each.
The relationship between a View and a Controller can be baffling
When a View is connected via a routes ConnectOutlets function call, what exactly happens between the controller and the view?
Are events tied into the view itself (which seems to be the case) and if so, where on earth do you interact with the controller singleton to perform CRUD-esq things on its properties? this.get('controllerName') doesn't seem to do the trick, and nearly each post or tutorial or code sample out there does this a different way.
Models that aren't
I realize that Ember Data looks to help solve some of the more irritating parts of dealing with data and keeping it in sync, but at a larger perspective, in the concept of "MVC", ember doesn't really seem to have a Model of any kind. It's just some object that gets subclassed from a specific thing and then tracked....somewhere? Somehow? Magical?
#trek sufficed that an Ember.Object could manage ajax'ing data and handling state on the client just fine, but if you look at something like the todomvc.com ember app, it uses a localStorage paradigm that is COMPLETELY different in implementation then everything i've looked at.
How EXACTLY should the 'Model' part of the MVC equation be done here?
Views make me want to murder children
There seems to be a significant number of ways to construct a "view" in terms of displaying markup to a user.
ContainerViews, using subviews / childviews
nested outlets
Handlebars templates + an outlet
using #each foo in controller
Injection through literals (template: Ember.Handlebars.compile('<h1>foo</h1>') etc)
With that in mind, what's the 'proper' way to build modular UI components with ember? This more than anything is a major pain point for the adoption of this framework for me.
I love the direction that Ember is going with application development on the web. The concepts seem simple, but the verbosity is that of Objective-C (which makes sense given it's lineage) but I swear to god I feel like i'm fighting the god damned framework more than i'm actually working on my application. The verbosity of the syntax and the lack of structured documentation outside of API documentation (which lets face it, 300k of javascript is a significant amount of code to throw some breakpoints down and try to debug your issues).
I realize the challenge that you guys are up against, but hopefully this at least makes you pause for a minute and think of how you could make life easier for the incoming developer who's worked with other frameworks (or hell, even worked within an MVC framework, like rails or django or backbone or angular) and say "this is how we think ember should be used".
Take some of the opinionated software design decisions and apply them toward the community. We'll do nothing but be cheerleaders for you if you do it, promise.
Please don't hurt any children. AFAIK the ember-core team are all over 18, so any ember-view-related frustration is clearly better directed towards adults. With that in mind...
Which Controller Type?
You've got the "what" right, but maybe missing the "why". Controller can be a little misleading, especially coming from rails. Think of these controller singletons as representing the state (in-memory) of your application.
Which kind of controller to use depends on what is required for that part of your application. For example, a back-of-napkin sketch for any app might have a topnav, postList, postDetails section. In ember, each is represented by one or more view/controller pairs. In this app I would expect to see ApplicationController and NavigationController extending Ember.Controler while postList would extend ArrayController and PostDetails would be an ObjectController.
You could do it all using just Ember.Controller but ObjectController and ArrayController are really useful for wrapping model data. Any non-trivial ember app will probably use all three.
The relationship between a View and a Controller
A controller's job is to provide the context in which the view will be rendered. Ideally you'd like to keep logic out of views, so a typical controller will have lots of computed properties to do things like:
transform data from the underlying model objects
sort/filter/select a list of objects
reflect application state
whats the deal with connectOutlets? This is where you should be using the requested route/context to decide which views/data should be plugged into the outlets of your application. The controller's connectOutlet method has a bunch of magic to make it easy, but maybe too much magic. What happens (afaik) when you call: parentcontroller.connectOutlet 'child' is
Ember creates an instance of ChildView
The {{outlet}} handlebars helper in parentController's view is bound to this childView instance
The childView is rendered with the router.childController singleton as it's context
where to do crud stuff?: Typically in an action on the router. This seems crazy at first. Think of ember router not like rails but as a stateManager that just happens to also handle routing. In near-future router API will change to make this more clear. Anyway, use router actions to do things like create model instances, commit/rollback transactions and trigger state change. This is easy to do if you use the handlebars {{action}} helper for links/buttons as it targets the router by default.
Views on the other hand should have logic for "reacting to browser events" - that means really low-level stuff like show/hide something on mouseover or integrate with 3rd party libraries to do effects and animations.
You might find this screencast helpful in understanding how to do CRUD-esq things:
http://blog.bigbinary.com/2012/09/06/crud-application-in-emberjs.html
Models WTF?
Agreed in Ember any object could be used as a 'Model'. I think #trek does a good job of demonstrating how one might accomplish this via Ember.Object. This works great for a simple app, and six months back maybe would've been your best bet as ember-data was really immature. I'm not clear on the history of ember's todomvc app, but for sure it was written months ago. For sure it should be updated, but meantime I'd not recommend using it to learn about current ember best-practices.
Instead, you should go with ember-data. Over the last few months it has really evolved and should be the default choice for any new, non-trivial ember app. #tomdale just gave a great presentation on this topic, I'd recommend having a look: https://speakerdeck.com/tomdale/ember-data-internals
what's the 'proper' way to build modular UI components with ember?
For building modular UI components:
ContainerViews, using subviews / childviews
Injection through literals (template: Ember.Handlebars.compile ...)
For building an individual application:
nested outlets
Handlebars templates + an outlet
using #each foo in controller
Building modular UI components is a totally different problem than building an application. Ember.View and it's subclasses were designed for this purpose. You can easily extend/combine them to compose widgets with custom behaviors and share those widgets across applications.
At least that's how i've seen it done. If they are for internal use could also reference handlebars templates instead of object literals, but if planning to distribute the object literals approach seems best.
A great real-world example of this is the ember-bootstrap project. I learned a lot about working with ember-views by reading through that project's source. http://emberjs-addons.github.com/ember-bootstrap/
TLDR
Pick controller that maps to type of data being represented
Controllers provide context for the view and remember application state
Use ember data for your models
Use subclasses of Ember.View to make components
Be nice to children

What are Ember.Controllers used for?

I'd like some examples please of how you use Ember.Controller objects. Apart from the StateManager, I really don't find myself using Ember.Controllers much at all. In the Ember source code it says that actions should be sent to the controller, but I really don't find myself using these so much, because I abstract the views so much, and therefore use the in-built actions like click, change, and keyUp. Am I abstracting too much?
For instance, if I'm displaying a button on the page, then I'll create a new Ember.View in my controller view, and then simply include that on the page.
Most direct interaction with controllers is indeed through the StateManager/Router. The controller's main responsibility is to present data to the views for rendering. They do this by proxying to models as well as maintaining transient state.
You are also correct that a single controller can often be responsible for a hierarchy of views.
I recently did a talk about the responsibilities of various layers in Ember apps. Slides are here: http://www.lukemelia.com/devblog/archives/2012/08/23/architecting-ember-js-apps/
This website has a pretty good presentation of how to use each part of Ember's MVC, and their relationship with each other:
http://www.lukemelia.com/blog/archives/2012/08/23/architecting-ember-js-apps/