Template without application.hbs as root? - ember.js

I've got an Ember-Cli App and would like to create an admin-interface for my application which looks nothing like the page set up in application.hbs.
How do I make the admin-interface independent from that one?

The way I achieved it was to have the base route and, in your case, admin route, kind of what #jcbvm was saying. So the router would look like:
this.resource('base', {
path: '/'
}, function() {
this.path('my-route');
// the rest of the app
});
this.resource('admin', {
path: '/admin'
}, function() {
// admin part
});

I think this can hardly be achieved, my best bet is to either creating a separate application for your admin interface or by moving your core application to a separate route.
When moving your core application to a separate route, you can move the contents of your application.hbs to the template of the new route and your admin interface to the admin route. The only drawback of this is that you will always see the name of your core route in the URL when going to the core application.

You should likely go down the path of Ember CLI addons, see here

Related

Combining two emberjs apps

I am currently using ember 1.13. I have two apps which use emberjs. Now I am thinking of integrating these two apps by creating a new route in the first app and display specific route of the second app. Many suggested to use ember-engines,but they need ember 2.10 or higher.Since my application mostly depends on IE 8,I cannot migrate from ember 1.x.
So what should I do? Thanks in advance!!
Cheers!!!
So one approach that would work pre engines is to leverage an addon for the common routes. Your addon will define routes, controllers, and templates as usual with the addons directory. You will also want to define something like addons/utils/router-utils:
// assume we have a single route foo
export function addRoutes(router) {
router.route('foo');
}
router is the this value that ember provides when invoking Router.map. So, within your addon, to allow for "normal" feeling development, you'll want to use this addRoutes function within the dummy app router in tests/dummy/app/router.js:
import EmberRouter from '#ember/routing/router';
import config from './config/environment';
import { addRoutes } from 'addon-with-routes/utils/router-utils';
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
addRoutes(this);
});
export default Router;
Note well, the above router.js file is what Ember 3.8 generates. Yours will most likely differ but the key point is that we invoke our addRoutes function with the anonymous Router.map this value to dynamically add our routes to the dummy app. See this twiddle for an example of adding routes to the router dynamically.
You can now run ember serve from within the addon project and test your routes. Acceptance tests run against the dummy app as well so you're not really constrained by this approach.
Now within your consuming app, you would do the same thing we did in the dummy app to add the routes. This approach, in general, though will require careful engineering to work effectively (a lot of the problems that ember engines solves must be solved by you in some way). Your addon will most likely have to expose a lot of configuration so that you can route outwards from the addon back into the consuming app which will not know about the routes in the consuming app. You'll have to avoid namespace collisions. Sounds fun though :)

Ember 2.5 Application Controller not present?

This is a very simple and probably easily resolved one.
I have created an emberjs application controller via ember generate controller application from which I want to return some basic computed properties based on the current path to higher level controllers and components. Basically, something like this:
export default Ember.Controller.extend({
entity: Ember.computed('currentPath', () => {
return this.get('currentPath').split('.')[0];
})
});
Oddly enough, I cannot access these computed properties anywhere (they turn out undefined, even if I replace them with a debug string), and in the Ember Inspector's view tree, the application controller is apparently not even present:
I have an older Ember 1.13.0 app, where I'm using the application controller with no difficulty. Have I missed a deprecation here? Or do I need to register the application controller in a specific location?
okay, I solved this differently using injection of the routing service directly into the component (see Component to be notified on route change in EmberJS 2 for details)

Multiple layouts in ember.js 2.7.0

I want to have two layouts, one for guests which can see some routes like: /, /contacts, /rules, etc... and another one for authenticated users, it means they must login before they can go to authorized routes. How can I define two layouts for different groups of routes?
there is a way to use Ember's router to your advantage to solve this problem by nesting the authenticated routes inside a route. Here's an example router:
Router.map(function() {
this.route('contacts');
this.route('rules');
this.route('authenticated', { path: '/' }, function() {
this.route('settings');
this.route('profile');
});
});
Going to /contacts and /rules wouldn't need any authentication, but going to /settings would.
Notice the path option passed to the authenticated route. Since we set it to / so it doesn't show up in the URL, it'll take the place of application.index. If this sounds strange to you, read about what an index page is in the Ember.js tutorial.
The answer is to maintain a service that saves the user's state.
// services/user-state
import Ember from 'ember';
export default Ember.Service.extend({
loggedIn: true
});
Then, depending on how you organized things, you could inject the service into a controller or a route. So - you'd have access to loggedIn
In your template, you would use handlebars/htmlbars if helper.
{{#if loggedIn}}
render logged-in stuff...
{{/else}}
render message explaining that this is only for logged in users
{{/if}}
You can also redirect the user to another route based on the current session data. You may have entire routes that are for certain roles, or you may have portions of your template that behave differently based on role.
If you weren't logged in, then you may not be able to visit your profile page. That route may be off limits entirely, or it may redirect you to a login page. On the other hand, maybe it's just a "login" button component or a portion of your template that shows if you aren't logged in vs. "hello sheriffderek" if you were.
There are also Ember addons for more robust "role" outlines. Think about a blog page, that may have an 'edit' button for the actual user, but 'flag' button for a moderator. In this case, you can't just have an entirely different route nested somewhere.
Most authentication addons / libraries are going to have a 'service' with some sort of session state. But Template wise, the basic idea is like a JS if/else statement.
if (helpful) {
this.upvote();
} else {
// something else
}
I hope this helps. : )
Have a look at the ember-simple-auth addon.
It has many useful classes all about authorization, including mixins for your usecase. If you want to make route only visible for logged-in users, simply use the AuthenticatedRouteMixin like this:
/app/routes/protectedRoute.js
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin);

ember-cli & common route and controller behavior options: Subclass, Mixin or initializer (service)?

I have properties and methods I want exposed to most/all instances of a class (i.e. all but a handful of routes, controllers, whatever). There seems to be multiple ways to accomplish this and I'm looking for guidance for best practices here.
More specifically, I've created a property on my application controller to hold a user session object. I want all other controllers to expose this data as if I had typed:
needs: ['application'],
userSession: Ember.computed.alias('controllers.application.userSession')
directly into the controller.
Further, I want to override all routes (other than the login route and maybe a couple more) implementations of beforeModel to check for the presence of userSession and redirect to the login route if absent.
This is being implemented in ember-cli FYI. So, that being the case, what's the "right" approach here? Do I try to inject these changes via initializers/services? Do I create mix-ins to do this stuff (I'm not a fan of having to remember to do that every time someone working on this does ember g controller that they then have to remember to add the mixin).
Sounds very much like the use of an initializer and a service is the best approach (them being split up makes for cleaner code). The initializer is just the code to load the service, the service does the hard work. The initializer should look something like:
import AuthService from '../services/auth';
export default {
name: 'auth-service',
initialize: function( container, app ) {
app.register( 'service:auth', AuthService, { singleton: true } );
app.inject( 'controller', 'auth', 'service:auth' );
app.inject( 'route', 'auth', 'service:auth' );
}
};
This then injects auth into every controller and route, and you should move the userSession from your application to the service.
My auth service is too big (and in my case: too specific, as it uses Firebase) to be quoting it here. I gave the gist of it in an answer yesterday: Short delay when trying to run redirect with ember route with firebase authentication
And as you mentioned it: people don't strictly need to remember to include mixins as you can override the blueprint that is used when someone does ember generate: http://www.ember-cli.com/#generators-and-blueprints

How to load parts of Ember.js on demand?

I want to load parts of my Ember.js application on demand (app is structured with AMD but merged into a few big script files for production).
An example:
Browse to '/'
The user starts at /, the HTML loads the file core.js which contains Ember.js, the routings and the application controller + view.
Browse to '/user/settings'
So now the user browses to /user/settings for the first time. The views, controllers and templates for this are in user.js which is loaded via a script loader in the according route:
App.UserRoute = Em.Route.extend({
enter: function(ctx) {
this.ajaxLoadFiles("user.js", function() {
// ???
});
}
});
Problem
Somehow Ember.js needs to wait for the script to load and then continue routing ... how do I do this?
I am using require.js, it is great for modularising your code!
You can clone the todoMVC AMD version to study here
https://github.com/addyosmani/todomvc/tree/gh-pages/dependency-examples/emberjs_require
for further advice, see this post:
Is there any way to split an Ember.js app across a few files?