I have a model and I would like to use it with two different templates on the page. I didn't find anything on how to specify what model to use for a template (other than its name).
For example, I would like to display all the subusers from the model "subusers" in the template named "assignationdd". Right now, I already have a template named "subusers" so it links it with the model automatically, but can I reuse the model in another template?
EDIT :
I have a multi-model ressource because I need both all conversations and subusers at the root of the app. I should have precised that before. So there is no change in the url or route, I just want to display my model in 2 different templates. And yes I read the docs on ember-data (and it shows very few and simpler examples).
Router :
App.Router.map(function(){
//Routing list to raw namespace path
this.resource('conversations', { path : '/' }, function() {
this.resource('conversation', { path : '/:conversation_id'});
});
});
Route :
App.ConversationsRoute = Ember.Route.extend({
subusers: null,
currentUser: null,
model: function(params){
return this.store.find('conversation', { status : params.status});
},
setupController: function(controller, model){
this.controller.set('content', model);
if(!this.get('subusers'))
{
this.set('subusers', this.store.findAll('subuser'));
}
this.controllerFor('subusers').set('content', this.get('subusers'));
},
queryParams: {
status: {
refreshModel: true
}
}
});
If I understand you correctly, the model is assigned by the Route and not the template. You can use one model in multiple routes. I suggest you read the getting started section on Ember and Ember Data.
First of all, don't nest resources. A resource should only be a noun, and a route should be a verb. So your router should be like this:
//Routing list to raw namespace path
this.resource('conversations', { path : '/' }, function() {
this.route('view', { path : '/:conversation_id'});
});
Secondly, try this for multiple models:
model: function (params) {
return Ember.RSVP.hash({
conversation: this.store.find('conversation', { status: params.status}),
subusers: this.store.findAll('subuser')
});
}
Related
Getting all articles is ok, but when try to retrieve just one article through route url directly, system error - undefined
var articles = Ember.$.getJSON('http://localhost/emberdata/api/articles');
will return:
[{"articles":
[
{
"id":1,
"title":"Ember is the best",
"author":"brk","excerpt":"Programming is awesome"
},
{
"id":2,
"title":"Backbone not a framework",
"author":"krb",
"excerpt":"Server-side controller sucks"
},
{
"id":3,
"title":"Javascript pwned",
"author":"rbk",
"excerpt":"I know right"
}
]
}]
API is created using PHP Slim Rest API
this Route working find, showing all the data in the handlebar template
App.ArticlesRoute = Ember.Route.extend({
model: function() {
return articles;
}
});
However for child view routing, undefined is returned
App.ArticleRoute = Ember.Route.extend({
model: function(params) {
var article = articles.findBy('id', params.article_id);
console.log(article);
return article;
}
});
Directly invoking the child view URL is not working:
http://localhost/emberdata/#/articles/1
However clicking the link of articles, those child view route works:
this.resource('article', { path: ':article_id' });
This is the error:
Ember.$.getJSON() will return a promise (see: http://emberjs.com/api/classes/Ember.PromiseProxyMixin.html). You can't call the findBy() method on a promise.
That being said, you're making it yourself very difficult. I recommend to start using the DS.RESTAdapter. In your case it would be something like this:
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'emberdata/api'
});
then clear (or remove) ArticlesRoute because you will use convention (instead of configuration):
App.ArticlesRoute = Ember.Route.extend({
});
idem for ArticleRoute. Except, if your backend doesn't support calls like /emberdata/api/article/1 use the following code:
App.ArticleRoute = Ember.Route.extend({
model: function(params) {
var article = this.store.find('article').findBy('id', params.article_id);
console.log(article);
return article;
}
});
I am working on learning how to work with Ember JS and I have run into an issue.
I have been developing a very simple application that allows users to add/edit/delete books from a library and then search for books based on either the title or the author. Based on that I am attempting to create a link-to that would render like "/search/title/adventures_of_huckleberry_finn" which would tell the router to filter the model so that it only returns books with the title equals "Adventures of Huckleberry Finn" (I know I'll need to do some string formating for the character case and replacing spaces with underscores for the URL, but I'm not worried about that).
I have the following link-to in my template (the title is hard coded to simplify testing)
{{#link-to "books.search" "title" "adventures_of_huckleberry_finn"}}Search by title{{/link-to}}
I have the following route defined (I suspect I need to nest the second dynamic segment but I'm not sure how to do that since I don't want a new controller/route involved)
Books.Router.map(function () {
this.resource('books', { path: '/' }, function () {
this.route('search', { path: 'search/:search_by/:keyword' });
});
});
<!-- ... additional lines truncated for brevity ... -->
Books.BooksSearchRoute = Ember.Route.extend({
model: function (params) {
return this.store.filter('book', function (book) {
return book.get(params.search_by) == params.keyword;
})
},
renderTemplate: function (controller) {
this.render('books/index', { controller: controller });
}
});
Now if I hard code the value or either the :searchBy or :keyword parms in the BooksSearchRoute then this works fine, however when I attempt to dynamicly pass both params I get the following error:
More context objects were passed than there are dynamic segments for the route: books.search
How can I update the route so that it allows me to pass both dynamic params into the BooksSearchRoute correctly?
Here's the general concept, you essentially use a route as a dummy route used just for the composite key. Personally I'd still prefer joining the key with a dash or something and using a single route, but hey, here's how this would work.
App.Router.map(function() {
this.resource('colorWrap', {path:'/:pk1'}, function(){
this.resource('color', {path: '/:pk2'});
});
});
App.ColorWrapRoute = Ember.Route.extend({
model: function(params) {
return {pk1:params.pk1};
}
});
App.ColorRoute = Ember.Route.extend({
model: function(params) {
var wrapModel = this.modelFor('colorWrap');
return $.getJSON('/colors/' + wrapModel.pk1 + '/' + params.pk2);
}
});
{{link-to 'Click to see the red color!' 'color' 1 2}}
http://emberjs.jsbin.com/OxIDiVU/273/edit
I have these routes defined:
this.resource('projects', function() {
this.resource('project', { path: ':project_id'}, function() {
this.route('details');
this.route('members');
});
});
What I thought was that by convention project.details route would look for "project/details" template. It does but strangely it does not get the correct model. See http://jsbin.com/ELaxigE/19/edit
Now instead of providing "project/details" template if I create "project" template then it works. See http://jsbin.com/ELaxigE/21/edit
I am confused what is happening. Can someone explain?
This has nothing to do with templates. You haven't defined the model for the ProjectDetails route. You can do so like this:
App.ProjectDetailsRoute = Em.Route.extend({
model: function() {
return this.modelFor('project');
}
});
Given a route. When the model hook ins't defined, and have a dynamic segment that ends with _id:
this.route('edit', { path: ':user_id' });
This will generate a route like this:
App.EditRoute = Ember.Route.extend({
model: function(params) {
return App.User.find(params.id);
}
});
In your case the only dynamic segmented route is project, because the :project_id.
this.resource('project', { path: ':project_id'}, function() { ... });
So because details and members, are just normal routes, it doesn't have a model.
When you change the template project/details to project, the things work because:
You transition to project.details, first is transitioned to project route, since you have declared this.resource('project'...). And because it's a dynamic segmented route, the App.Project instance is returned, and the your template is rendered bound to this model.
After this, the child route project.details is transitioned, but this time, the template project.details not exist. So nothing is rendered.
I think that the solutions are the #alexspeller answer, or:
this.resource('project', function() {
this.route('details', { path: 'details/:project_id' });
this.route('members', { path: 'members/:project_id' });
});
I hope it helps.
Ember.Route.model has access to the params variable, but Ember.Route.setupController does not. This is troublesome for me, because my path has multiple dynamic segments, and I need to use all of them in my template.
Specifically, my path looks like this: /project/:project_id/task/:task_id. Note that a task can belong to many projects, not just one. Therefore we can't tell what project we're looking at just be looking at the task itself: we have to use the project ID found in the URL. Here's how I'm doing it currently:
App.TaskRoute = Ember.Route.extend({
// This works just fine:
serialize: function(model) {
return {
task_id: model.get('id'),
project_id: this.modelFor('project').get('id')
};
},
model: function(params) {
this.set('parentProjectId', params.project_id);
return App.Task.find(params.task_id);
},
setupController: function(controller, model) {
var parentProject = this.modelFor('project') ?
this.modelFor('project') :
App.Project.find(this.get('parentProjectId'));
controller.set('parentProject', parentProject);
controller.set('content', model);
}
});
Maybe I'm being paranoid, this just feels hacky. If the route was meant to have access to the parameters, then it would already have a params property attached to it. Is there a better way?
EDIT: I made some update to the code above. Also, my routes look like this:
App.Router.map(function() {
this.resource('project', { path: '/project/:project_id' });
this.resource('task', { path: 'project/:project_id/task/:task_id' });
});
You have no access to these params in the setupController hook. The model hook has access to a params object, because it is just called, when your app is entered via URL.
Your code looks quite fine, it you really know, that you want to do it this way. What does feel hacky to you about it? When looking at this code, i am asking myself why you did not split the logic of your Route into a ProjectRoute and a subordinated TaskRoute. Wouldn't that work for you?
Update: Response to your changes
Nesting resources is likely the key to success in your case:
App.Router.map(function() {
this.resource('project', { path: '/project/:project_id' }, function(){
this.resource('task', { path: '/task/:task_id' });
});
});
Since the TaskRoute is nested not you have to rename it to ProjectTaskRoute:
App.ProjectTaskRoute = Ember.Route.extend({
...
});
This should enable you to remove the parentProjectId property from the Route.
Since Ember 1.8, the Route class has a paramsFor function:
import Route from '#ember/routing/route';
export default Route.extend({
setupController(controller) {
this._super(...arguments);
const params = this.paramsFor('name.of.your.route')
}
});
So, I'm having some issues with Ember's new router. I'm trying to save and later return to the current path for a given dynamic segment, so my urls might look like
#/inventory/vehicle/1001
Which can then branch off into
#/inventory/vehicle/1001/details
#/inventory/vehicle/1001/photos
#/inventory/vehicle/1001/description
etc. I need a way to return to the most recent route. The Ember guides have a method for this here:
http://emberjs.com/guides/routing/redirection/
The problem with this method is that by creating the "/choose" route and assigning it to "/", this overwrites the standard "/inventory/vehicle/1001" route. For instance, if I were to try to create a linkTo a vehicle like so:
{{#linkTo "vehicle" vehicle}}
Then Ember will throw an error because the "vehicle" route no longer exists. Instead, it must be set to:
{{#linkTo "vehicle.choose" vehicle}}
Which works, activates the VehicleChooseRoute and everything. Except, since "vehicle.choose" is technically a child of "vehicle", the #linkTo ONLY has an active class applied when the current route is
#/inventory/vehicle/1001
Which instantaneously redirects to the latest filter, and so it's basically never on. So basically I'm trying to figure out a way around this. I tried changing the path of "vehicle.choose" to be the standard path (#/inventory/vehicle/1001/choose) so it doesn't overwrite the "vehicle" route, and then setting up VehicleRoute like so:
Case.Router.map(function() {
this.resource('inventory', function(){
this.route('review');
this.route('sheets');
this.resource('vehicle', { path: '/vehicle/:vehicle_id' }, function(){
this.route('choose');
this.route('details');
this.route('consignor');
this.route('additional');
this.route('price');
this.route('dmv');
this.route('expenses');
this.route('description');
this.route('tasks');
});
});
});
App.VehicleRoute = Ember.Route.extend({
model: function(params) {
return Case.Vehicle.find(params.vehicle_id);
},
setupController: function(controller, model) {
model.set('active', true);
},
redirect: function() {
this.transitionTo('vehicle.choose');
}
})
Case.VehicleChooseRoute = Ember.Route.extend({
redirect: function() {
var lastFilter = this.controllerFor('vehicle').get('lastFilter');
this.transitionTo('vehicle.' + (lastFilter || 'details'));
}
});
But the problem that arises from this (aside from feeling rather hacked together) is that redirect replaces the entire template that would normally be rendered by "vehicle" so I only get the subview. So that's not an option.