Switching out the Ember.js application template - ember.js

This is quite possibly a stupid question given my lack of experience with Ember JS at the moment. However I was wondering how one would approach an application that may have a few fundamentally different structural layouts. From what I do understand the application template is designed to display elements that will always be there.
Consider the following:
Login screen
No Header
No Sidebar
No Footer
Has Login box
Main Application
Has Header
Has Sidebar
Has Footer
Drawing part of the application
No Header
Has Canvas
Has Inspector
.. Etc
The question becomes how can one adjust the main application layout to cater to fundamental structural differences in an application. I'm assuming that one could leave the application template blank and render these static bits in where needed, but I think that opens yourself to repeating configurations. IE one wouldn't want to have to specify a layout for each possible route, or maybe you would?
Just looking for some pointers / best practice.
Thanks!

Totally opinion based here, but I think this is a perfect case for a blank application and different routes which are displayed completely differently.
App.Router.map(function(){
this.resource('login');
this.resource('home');
this.resource('drawing');
..... etc
});
And then you can share/reuse templates super easy, so maybe in the home template you'd have something like
{{render 'header'}}
other content
{{render 'footer'}}
then in your drawing template you'd have something like this
drawing stuff
{{render 'footer'}}
or whatever makes sense for your application.

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.

aurelia pages with different page formats

In the Aurelia SPA template it assumes that every page will be inside app.html and use the same nav-bar at the top. But I'll have many pages that don't want the nav-bar at the top and actually not use app.html at all. I was looking at main.js and it looks like I could hook into bootstrap() and change the aurelia.setRoot() for certain pages (I'm just guessing here), but then I start mucking up the main.js file and it won't be long before it gets really messy and maintenance headache. I really just want to have some pages use their own format altogether and ignore the app.html formatting without doing any crazy configurations.
My initial thought is maybe app.html should just be an empty file and make every page decide whether or not it wants the nav-bar and include it on the individual pages. But now I'm duplicating the code across many pages and if the standard page layout changes I have to change all the individual pages. Not sure the best way to go about his. Any suggestions?
I actually disagree with Gilbert's answer. Using .setRoot is a best practice; the root is just the parent view/viewModel pair and you will often have different parents. This is essentially what you're doing when you're creating an empty app view/viewModel, creating a new parent that doesn't do anything. But adding an unnecessary, unused layer is just extra complication.
One of the best use cases for this is a login page. The login page is totally different from your normal app page--there's a login prompt, no navigation bar, etc. Therefore, make a "login" app root and a "app" app root and switch back and forth between them. I've built a template called Sentry that demonstrates how to do this.
Sentry in action
Sentry on GitHub
Using set root, like you said, is a bad idea. Similar to what you said, you can make app.html contain just the router view tag. Different parts of your app, that you want to share a similar page layout, will be gruped under different routes. Now each of theses routes will point to another router that will have its different styles in the view
Just think of it as an empty app.html with child app.html's that have styles in them(e.g. Different navbars, page layout etc)

Converting an admin UI design into Ember components

I'm wondering if their is a tutorial on how to convert an admin UI into Ember components? What are the best practices? For example, the following UI framework: http://egemem.com/theme/kode/v1.1/blank.html
Has a main navigation, two sidebar menus, a content body and a footer. What would the best approach be to converting this into components? My initial thoughts, with very little Ember experience and based on the scattering of documents I've been able to find, I get the sense that creating unique components for everything would be the best approach. By everything I mean, everything that is unique. For example, if we take the navigation bar, there would be a parent component for the navigation as a whole and then child components for the sidebar collapse/expand buttons, the search, the drop down menus, notification indicator, etc. There would also be additional parent components for the right hand sidebar, left hand sidebar, and footer.
Looking at one of the sidebars, for example the left one, could that be one component or would child components be required here as well?
The right hand sidebar is more complex with tabs. In this example, would it make sense to break this sidebar into child components for the 3 different tabs? Would you want to go as far as a unique component for different elements of the tabs themselves. For example, each notification type would be a component?
Thank you in advance for your assistance send I look forward to understanding how best to handle this type of scenario.
Cheers,
Dan
Yes, your idea makes sense. It is a good practice to create components (or handlebars) for everything that repeats several times. I would not create different components for different tabs if they are not re-used.
Do not forget to not re-invent wheel. There are a lot of available components, take a look at Ember Observer or other similar resources.
Components are great but some the things you mentioned, like sidebars, might make more sense as nested routes, depending on what's in the sidebars.
Rock 'n Roll with Ember is a fantastic book that takes you all the way through the process of building an Ember application. It's the book I always recommend to people just getting started with the framework. http://balinterdi.com/rock-and-roll-with-emberjs/

Advice on WYSIWYG architecture for an Ember app

I'm having a hard time coming up with a solution for this problem.
I'm building a WYSIWYG designer, for micro sites. The templates for these microsites will be supplied by an intermediate user, and the end-user will manipulate these templates. So, there are really two groups of users of the app: template-buiders, and end-users. Think MailChimp.
This means my Ember app will start off with a template from a template-builder, say
<h1>An awesome product</h1>
<h2 contenteditable="true">Subtitle away</h2>
<p>{{#if optionA}} One thing {{else}} Another thing {{/if}}<p>
and the end user, having chosen this template, will then be able to customize it. There are a few requirements:
There will be static, uneditable portions of the page (h1 above)
There will be static, editable portions of the page (h2 above)
There will be options that affect the layout, style, etc. (p above)
So far, my attempts have lead me to build a handlebars helper that takes a string and a context, and returns a rendered template. This is because the above template will actually be coming over from a database, as a string - remember, it's user-generated.
That means, in my application's template, it would look like
<div class="preview">
{{preview-userTemplate template context}}}
</div>
where
template: '<h1>An awesome product</h1><h2 contenteditable="true">Subtitle away</h2><p>{{#if optionA}} One thing {{else}} Another thing {{/if}}<p>',
context: {optionA: true}
Now, this actually works, in the sense that it will update if context is updated, so I can add controls along the sides for the end-user to manipulate those options. So I have those (more of less) under control.
It's the WYSIWYG content editing that is giving me trouble. In the above template (from my template-builder users), I want them to be able to add contenteditable="true" to places in their templates where the end-users can change the content.
Now, these changes need to be saved. Ideally, I would be able to retrieve the instance view's template back from the DOM, after the inline edits have been made. Is this possible? The original {{data}} placeholder would need to be preserved.
Alternatively, I could make a view/component, so the template-builder would do something like this:
<h1>An awesome product</h1>
{{#editable}}
<h2>Subtitle away</h2>
{{/editable}}
<p>{{#if optionA}} One thing {{else}} Another thing {{/if}}<p>
but this seems like it would require a good deal of finagling to get the edits to stick - I'm not even sure right now how I'd go about it.
What do you guys think? Is there an easier solution that I'm overlooking? Thanks for any pointers!

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