EmberJS dynamic routing and configuration - ember.js

I use EmberJS v1.0.0-rc.2 and requireJS.
My app structure is kinda like that.
- app
- - moduleA
My main file:
#app/main.js
var App = Ember.Application.create({
VERSION: '1.0',
//Log router transitions:
LOG_TRANSITIONS: true
});
App.Router.map(function() {
AppRouting.call(this);
});
App = AppRoutingExtend(App);
App.initialize();
Functions AppRouting() and AppRoutingExtend() could be find in the fellow file:
#app/routing.js
function AppRouting() {
this.resource('root', {path: '/'}, function() {
this.resource('moduleA', {path: '/'}, function() {
ModuleARouting.call(this);
});
});
}
function AppRoutingExtend(App) {
var ModuleARouting = ModuleARoutingExtend();
//Check if ModuleARouting is not empty
if (!Ember.isEmpty(ModuleARouting)) {
$.each(ModuleARouting, function(key, value) {
//Check if key is a string of only letters
// And if value is like Ember.Route.extend({})
if (typeof key === 'string' && /^[a-zA-Z]+$/.test(key)
&& value.toString() == '(subclass of Ember.Route)') {
eval("App.Root" + "ModuleA" + key + "Route = value");
} else {
//Throw error
}
});
}
return App;
}
Functions ModuleARouting() & ModuleARoutingExtend() could be find in the follow file:
#app/moduleA/routing.js
function ModuleARouting() {
this.route("contributors", {path: "/"});
this.resource('aContributor', {path: "/:githubUserName"}, function() {
this.route("details", {path: "/"});
this.route("repos", {path: "/repos"});
});
}
function ModuleARoutingExtend() {
var routes = {};
routes['Contributors'] = Ember.Route.extend({
/*
Some Code
*/
});
routes['AContributor'] = Ember.Route.extend({
/*
Some Code
*/
});
routes['AContributorDetails'] = Ember.Route.extend({
/*
Some Code
*/
});
routes['AContributorRepos'] = Ember.Route.extend({
/*
Some Code
*/
});
return routes;
}
I created AppRouting() and ModuleARouting() to be able to add dynamically some routing path to my application, by adding a new module or remove one. By this way, each module could have its intern structure and AppRouting() just merge them.
However, I'm not sure about ModuleARoutingExtend() and more specifically AppRoutingExtend(). In the last one, I try to modify routes like App.RootModuleAContributorsRoute. By the way I don't have information directly which routes have been created by the ModuleARouting.call(this), I cannot know the name of the variable RootModuleAContributorsRoute. This is the reason I use eval to be dynamic by getting the 'Contributors' from ModuleARoutingExtend() and its value, Ember.Route.extend({/* some code *});
So, my question is: Is there a better way to add dynamically some routes for my application and to get their configuration? And if not, is it still a good way?

Related

Go to new item route after creation in Emberjs

I've something like this in my route:
actions: {
save(title, description) {
const newCard = this.get('store').createRecord('card', { title, description } );
newCard.save().then((card) => {
// card.id contains the id of the new card
this.transitionTo('cards.all'); // problem with this line
});
}
}
I want to go to the new card route after creating it. I can get the id of the new item from card.id. I've tried the following but of no use:
this.transitionTo('cards.card', card.id);
This throws some error since the cards.card route can't find the id in the params.
The following:
this.transitionTo('cards/' + card.id);
throws some error stating that cards/45 route not found but if the new item is created and I can navigate to it.
I'm using Ember 2.6.1.
EDIT
My router.js file:
this.route('cards', function() {
this.route('all');
this.route('card', {path: '/:card_id'}, function() {
this.route('edit');
});
this.route('new');
});
Is this what your router currently looks like?
this.route('cards', function() {
this.route('all');
this.route('card', {path: '/:card_id'}, function() {
this.route('edit');
});
this.route('new');
});
If your wanting to go to the new route for a specific card then you would need to define a slug for new. Something like
this.route('new', {path: /:card_id});
The transition in your action hash would like like this:
this.transitionTo('new', card.id);
Hopefully I'm understanding your use case correctly.
It should be this:
this.transitionTo('cards.card', card);
I only needed to do this since my card.js was expecting params object and I was trying to pass a number:
model(params) {
return this.store.find('card', params.id);
}

How to get the Router instance in initializer

I have a use-case where I want to register routes dynamically in an initializer.
Because the application is a self-defining app I don't know the routes at development time.
Currently I created an instance-initializer:
import Ember from 'ember';
const myTempRouteList = ['home']; // this is retrieved from the backend
export function initialize(instance) {
let container = instance.container;
let router = container.lookup('router:main');
myTempRouteList.forEach(function (name) {
let routeName = name.dasherize();
router.map(function(){ // router.map is undefined here
this.resource(routeName, {path: routeName});
});
container.register(`route:${routeName}`, Ember.Route.extend({
}));
}, this);
}
export default {
name: 'register-routes',
initialize: initialize
};
The problem is that the router instance is present but is has no method map. In the documentation it is described as a public method. Some other methods I checked are present, f.i. hasRoute.
It turns out I had to call the lookupFactory method instead of the lookup method on the container.
export function initialize(instance) {
let container = instance.container;
let router = container.lookupFactory('router:main');
...
}
For people who are working on latest ember with ember-cli (Ember > 2.0). This might be helpful
//initializer.js
export function initialize(application) {
var routeNames = [];
var router = application.__container__.lookupFactory('router:main');
application.deferReadiness();
//if you want to have your custom routes on the highest level
if (routeNames.length > 0) {
router.map(function() {
var _this = this;
routeNames.forEach(function(item,index) {
_this.route(item);
});
});
}
//if you want to have your custom routes as a child of another parent route
if (routeNames.length > 0) {
router.map(function() {
this.route('parentRoute', {path:'/'}, function(){
var _this = this;
routeNames.forEach(function(item,index) {
_this.route(item);
});
});
});
}
application.advanceReadiness();
}

EmberJs routing

I am trying to create EmberJs / RequireJs application and ran into a problem. According to examples, I defined my app.js like this:
(function () {
define(['../app/routing'], function (routing) {
return {
Router: routing,
LOG_TRANSITIONS: true
};
});
}());
, routing.js as:
(function (root) {
define(["ember"], function (Ember) {
var router = Ember.Router.extend({
todosRoute: Ember.Route.extend({
viewName: 'todos',
model: function(){
return this.todos.find('todos');
}
})
});
return router;
});
}(this));
and main.js:
require(['app', 'ember'], function(app, Ember){
var app_name = config.app_name || "app";
root[app_name] = app = Ember.Application.create(app);
The problem I have is that no matter how I define my routes, I cannot get them to work, emberJs also reports, that such routes do not exist.
How can I define routes and pass them to Application.create(obj) as argument object? If possible, I would still like to keep them in separate file.
Please note, that routing.js should be executed before main.js, therefore App object is not available like it is suggested in tutorials
js/app.js
App = Ember.Application.create();
App.Router.map(function() {
this.route('index', {
path: '/'
});
this.route('about');
});
App.IndexRoute = Ember.Route.extend({
//
});
I know you'll want to pull these all out into different files, but have you been able to make things work in a simple environment?
As far as the Require JS stuff... I don't know much about that - but there seems to be a thread here: Ember.js and RequireJS that gets to the bottom of it.
Make your router.js file look like this:
(function (W) {
'use strict';
define([
'ember'
], function (Ember) {
var Router;
Router = Ember.Router.extend();
Router.map(function () {
var _this = this;
_this.route('index', {path: '/'});
_this.route('todos', {path : '/todos/'});
});
return Router;
});
})(window);
For individual route, add a new file.
(function (W) {
'use strict';
define([
'ember',
'models/todosModel'
], function (Ember, TodosModel) {
var TodosRoute;
TodosRoute = Ember.Route.extend({
model: function () {
return TodosModel;
}
});
return TodosRoute;
});
})(window);
Add the individual routes to object returned by your app.js.

Empty controller blocks view. Why?

I have been experimenting with using Ember with a JSON server but without without ember-data. My test app renders a directory of images from a small JSON structure (generated from a little Go server).
Can anyone explain to me why, if I uncomment the App.FileController in the code below, the corresponding File view fails to render?
window.App = Ember.Application.create();
App.Router.map(function() {
this.resource('files',function(){
this.resource('file',{path:':file_id'});
});
});
App.FilesRoute = Ember.Route.extend({
model: function() {
return App.File.findAll();
}
});
App.FileRoute = Ember.Route.extend({
setupController: function(controller, args) {
controller.set('model', App.File.find(args.id));
},
model: function(args) {
return App.File.find(args.file_id);
}
});
App.File = Ember.Object.extend({
urlPath: function(){
return "/pics/" + this.get('id');
}.property('id'),
});
If I uncomment this, things break:
// App.FileController = Ember.Controller.extend({
// });
(namely, the File sub-view no longer renders at all.)
App.File.reopenClass({
find: function(id){
file = App.File.create({'id':id});
return file;
},
findAll: function() {
return $.getJSON("http://localhost:8080/api/").then(
function(response) {
var files = [];
response.Files.forEach(function (filename) {
files.push(App.File.create({'id':filename}));
});
return files;
}
);
},
});
Also, is there something fundamental that I'm doing wrong here?
As noted by Finn MacCool and agmcleod I was trying to use the wrong type of controller. The correct lines should be:
App.FileController = Ember.ObjectController.extend({
});
Not that I need to explicitly set a FileController in this small example. However, should I go on to expand the code I will no doubt need one and will need to use the correct one.

Ember namespaces creating reusable apps

Hi I am new in ember I tried to solve my self but no success.
Take a look at code:
// works
window.App = Em.Application.create();
window.Core = Em.Namespace.create({ Beta: Em.Namespace.create() });
App.Router.map(function() {
this.route("registration", {
path: "/beta/registration"
}); // also Core.Beta.registration tried
});
App.IndexRoute = Em.Route.extend({
redirect: function() {
this.transitionTo('registration'); // also Core.Beta.registration tried
}
});
// never is called
Core.Beta.RegistrationController = Em.Controller.extend();
Core.Beta.RegistrationView = Em.View.extend({ template: Em.TEMPLATES['beta.regisration'] });
Core.Beta.RegistrationRoute = Em.Route.create({
setupController: function() {
console.log(arguments);
},
setupView: function() {
console.log(arguments);
}
});
All inside Core.Beta never is called as should in ember pre4... Using Core.Beta I can generate reusable micro apps to use in other projects. Do you know the way how ember inject that app in router so it could create instances inside the namespaces.
You need to create your namespace within the App itself
window.App = Em.Application.create();
window.App.Core = Em.Namespace.create({ Beta: Em.Namespace.create() });