How to get the Router instance in initializer - ember.js

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();
}

Related

Share service variable between controllers

I have a variable in a service that I want two share between two controllers.
As I know, Ember services are singleton.
I created a service file: app/services/data-manipulation.js:
import Ember from "ember";
export default Ember.Service.extend({
init() {
console.log('initService');
},
shouldManipulate: false
});
In first controller that is called one screen before the second controller:
dataManipulation: Ember.inject.service(),
init() {
this.updateManipulate();
},
updateManipulate: function() {
this.set("dataManipulation.shouldManipulate", true);
var currentValue = this.get("dataManipulation.shouldManipulate");
console.log(currentValue); // log true as expected
}
In second controller:
dataManipulation: Ember.inject.service(),
init() {
// it inits the service again so 'initService' is logged again.
var currentValue = this.get("dataManipulation.shouldManipulate");
console.log(currentValue); // log undefined
}
What is the problem and how can I make it works?

Ember 2.0 get another router from router/controller

Is there any way to call route action from another router/controller? Let's say I have two routes:
App.RouteOne = Ember.Object.extend({
actions: {
someCommonFunctionality: function() {
// ...
}
}
});
App.RouteTwo = Ember.Object.extend({
actions: {
// Here I want to call someCommonFunctionality function from RouteOne
}
});
Is this somehow possible? I have an AJAX get method that I do not want to repeat in RouteTwo as I have it already in RouteOne

Ember promise not resolved when I expect it to be

I have a custom component that expects data and not a promise, but I am unsure if they way that I am obtaining the data is the right way.
Is this the right way to do it?
component hbs
{{x-dropdown content=salutations valuePath="id" labelPath="description" action="selectSalutation"}}
Doesn't work
controller (this is the way I expect things to work
import Ember from 'ember';
export default Ember.Controller.extend({
bindSalutations: function() {
var self = this;
this.store.find('salutation').then(function(data) {
self.set('salutations', data);
});
}.on('init'),
components/x-dropdown.js
import Ember from 'ember';
export default Ember.Component.extend({
list: function() {
var content = this.get('content');
var valuePath = this.get('valuePath');
var labelPath = this.get('labelPath');
return content.map(function(item) {
return {
key: item[labelPath],
value: item[valuePath],
};
});
}.property('content'),
This works
controller
bindSalutations: function() {
var self = this;
this.store.find('salutation').then(function(data) {
self.set('salutations', data.get('content')); // pass the content instead of just the data
});
}.on('init'),
component
...
list: function() {
var content = this.get('content');
var valuePath = this.get('valuePath');
var labelPath = this.get('labelPath');
return content.map(function(item) {
return {
key: item._data[labelPath], // access through the _data attribute
value: item._data[valuePath],
};
});
}.property('content'),
Ember Data returns a Proxy Promise. This means you can use the promise as if it were a collection or model itself, as long as you aren't dependent on the property being completely populated when you use it. If you really want the promise resolved, you should probably be setting it up in the route.
If you want it on your controller, you can be lazy and do it like so:
Controller
salutations: function() {
this.store.find('salutation');
}.property(),
Component
...
list: function() {
var content = this.get('content'),
valuePath = this.get('valuePath'),
labelPath = this.get('labelPath');
return content.map(function(item) {
return {
key: item.get(labelPath),
value: item.get(valuePath),
};
});
}.property('content.[]'),
Template
{{x-dropdown content=salutations valuePath="id" labelPath="description" action="selectSalutation"}}
The real trick is to watch if the collection is changing. Hence you'll see I changed the property argument to content.[]

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.

EmberJS dynamic routing and configuration

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?