In my app, there are Templates and Documents. I want to be able to create a document from a template, i.e. the user will be able to go to the template show page, click a button, and be redirected to the new document page, with document text pre-filled from the template (I only need to have the text pre-filled, I don't care about the document knowing the template it's made from).
But how would I pass the text to the new document page?
I ended up doing the following:
App.Router.map ->
#resource 'documents', ->
#route 'new'
#route 'new_from_template', path: '/new/:template_id'
App.DocumentsNewFromTemplateRoute = Ember.Route.extend
model: (params) ->
model = App.Document.createRecord()
if params.template_id
App.Template.find(params.template_id).then (template) ->
model.set 'text', template.get('text')
model
setupController: (controller, model) ->
if model._reference.type == App.Template
model = #model(template_id: model.id)
#currentModel = model
#controllerFor('documentsNew').set 'model', model
renderTemplate: ->
#render 'documents/new'
And to link to new document form for template, I simply do
{{#linkTo 'documents.new_from_template' template}}Create a document{{/linkTo}}
You can define an action in the controller:
App.TemplateRoute = Em.Route.extend({
model: function() {
return Em.Object.create({
name: "A Template",
values: {title: "Templated Title"}
});
}
});
App.TemplateController = Em.ObjectController.extend({
goToNewDocument: function() {
var o = Em.Object.create(this.get('values'));
o.set('source', 'Template');
App.Router.router.transitionTo('newdoc', o);
}
});
App.NewdocRoute = Em.Route.extend({
model: function() {
return Em.Object.create({title: "Default Title", source: "Model hook"});
}
});
jsbin demo
Related
I'm trying to build a view that is going to display multiple models and aggregated data.
After doing some reading in the docs, the {{render}} helper is probably the right way to build a view like this. For setting the model normally I'd just set up a Route in which I pass the needed model data:
App.BuildingsRoute = Ember.Route.extend({
model: function() {
return this.store.find('buildings', '1');
}
});
But if I include a template via the {{render}} helper, the route is not called. I'd like to know how I can pass the different models for each {{render}} helper independently form each other, including first filtering the model?
The following may be relevant:
In your BuildingsRoute you can have all of the required logic to return all relevant models e.g.:
App.BuildingsRoute = Ember.Route.extend({
model: function() {
var self = this;
return new Em.RSVP.Promise(function (resolve, reject) {
new Em.RSVP.hash({
building: self.store.find('building', params.buildingId),
clients: self.store.find('client'),
products: self.store.find('product')
}).then(function (results) {
resolve({
building: results.building,
prods: results.broducts,
clients: results.clients,
foo: "bar"
});
});
}
});
See promises for more info on how to structure and chain these.
Then in your view you can access these models as follows:
{{render 'products' products}}
or
{{#each product in products}}
{{render 'product' product}}
{{/each}}
How do I get the the model to load without going to the route first?
App.UsersRoute = Em.Route.extend({
model: function() {
return ['bob', 'sue', 'tom'];
},
setupController: function(controller, model) {
controller.set('model', model);
}
});
From another controller using
needs: "users"
and
this.get('controllers.users.content');
works fine as long as I visit the UsersRoute first.
Load it in the topmost route that will need it, thusly:
App.SomeOtherRoute = Em.Route.extend({
setupController: function(controller, model) {
controller.set('model', model);
this.controllerFor('user').set('model', ['bob', 'sue', 'tom']);
}
});
Note that if you are using ember-data or epf or ajax, that the model will be a promise. You can't set the model on a controller to be a promise so you would do:
setupController: function(controller, model) {
controller.set('model', model);
return this.get('store').findAll('user').then(function(users) {
this.controllerFor('users').set('model', users);
});
}
Note in the second one I'm using UsersController, not UserController, because you seem to want a collection of users not a single user.
I hit this same problem this past weekend and the following worked for me:
App.SomeOtherController = Ember.Controller.extend({
needs: ['users']
});
App.SomeOtherRoute = Ember.Route.extend({
setupController: function( controller, model ){
this._super( controller, model );
controller.set( 'controllers.users.model', ['bob', 'sue', 'tom'] );
}
});
if it is an ajax call / ember data then you need something like this:
App.SomeOtherController = Ember.Controller.extend({
needs: ['users']
});
App.SomeOtherRoute = Ember.Route.extend({
setupController: function( controller, model ){
this._super( controller, model );
this.get('store').findAll('user').then(function(users) {
controller.set( 'controllers.users.model', users );
});
}
});
However, a colleague pointed out to me during our code review today that if I need to do this I have probably structured my routes / resources / models incorrectly. In other words an outer route should not depend on an inner route's model. So I am now thinking about going back and refactoring this so that the users model is part of the model for the outer route and then I can use that in my inner route controller.
I've been over the guide and some questions around the net. This has to be simple but I'm just missing something..The worst is that other stuff is working out great but not something that should be real trivial (imho).
I have a basic Ember app set up. I have an index template defined, as a landing page. There are elements I want it to reference right off the bat from a 'model' i have as just a javascript object in the script.
var company = {
id: '1',
name: 'Some Inc.',
email: 'guy#some-inc.com'
};
App.IndexRoute = Ember.Route.extend({
setupController: function(controller, company) {
// Set the IndexController's `title`
controller.set('title', "Publisher Dashboard");
controller.set('model', company);
}
});
In my HTML I have within the index template:
<script type="text/x-handlebars" data-template-name="index">
...
<span class="name">{{name}} ( {{email}} )</span>
I don't know if things have changed over versions. I have seen different syntax do/claim to do the same stuff. I'm using v1.0.0.
You have to declare a model that you are going to use for the IndexRoute
App.IndexRoute = Ember.Route.extend({
model: function() {
return 'SOMETHING' //could be 'company'
},
setupController: function(controller, company) {
// Set the IndexController's `title`
controller.set('title', "Publisher Dashboard");
controller.set('model', company);
}
});
SetupController model uses the model that is returned by the model hook on the route. So if you return 'company' in the model hook. You will have access to the that company object.
have you tried doing this ?
setupController: function(controller, company) {
this._super(controller, model);
// Set the IndexController's `title`
controller.set('title', "Publisher Dashboard");
controller.set('model', company);
}
I added one line, which is to call super.
I want to use the information already received within a linked template. Nesting routes has created a whole heap of errors, and I'm a little lost on how to pass this data, but it seems like it must be possible?
This works, but strikes me as a poor hack. Ideally I'd only want one API round-trip...
App.Router.map ->
#resource 'photos'
#route 'photo', path: 'photo/:photo_id'
App.PhotosRoute = Ember.Route.extend
model: ->
Ember.$.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?tags=cake&tagmode=all&format=json&jsoncallback=?')
setupController: (controller,model) ->
controller.set 'photos', model.items.map (i) ->
i.id = model.items.indexOf(i)
App.PhotoRoute = Ember.Route.extend
model: (params) ->
jQuery.getJSON('http://api.flickr.com/services/feeds/photos_public.gne?tags=cake&tagmode=all&format=json&jsoncallback=?').then (api) ->
api.items[params.photo_id]
App.PhotosController = Ember.ObjectController.extend
itemController: 'photo'
{{#linkTo 'photo' this }}<img {{bindAttr src="media.m"}} />{{/linkTo}}
You can use the modelFor(routeName) to get the model from some route. In your case probally you will fetch all data in PhotosRoute, and want to reuse it. You can use this in your PhotoRoute:
App.PhotoRoute = Ember.Route.extend
model: (params) ->
#modelFor('photos').items[params.photo_id]
So just one api call will be done.
Ember shows me the following error: Uncaught Error: No route matched the URL '/users'
Sks.IndexRoute = Ember.Route.extend
redirect: ->
this.transitionTo 'users'
Sks.Router.map ->
this.resource 'users', path: 'users/:user_id'
Sks.UsersRoute = Ember.Route.extend
setupController: (controller, model) ->
this.controllerFor('users').set 'content', Sks.User.find()
this.controllerFor('currentUser').set 'content', Sks.CurrentUser.find 1
this.controllerFor('top').set 'content', Sks.Top.find()
this.controllerFor('hamsters').set 'content', Sks.Hamster.find()
Everything works when I remove the dynamic segment.
Version: v1.0.0-rc.1-78-gd4e6a5c
edit#1
added IndexRoute
In Ember, collections and items actually use separate routes. Here's how I do it:
App.Router.map(function () {
this.resource('contacts', { path: '/contacts' });
this.resource('contact', { path: '/contact/:contact_id' });
});
App.IndexRoute = Ember.Route.extend({
redirect: function () {
this.replaceWith('contacts');
}
});
App.ContactsRoute = Ember.Route.extend({
model: function (params) {
return App.Contact.find();
}
});
App.ContactRoute = Ember.Route.extend({
model: function (params) {
return App.Contact.find(params.contact_id);
}
});
Here's a working jsFiddle.
It seems that I should have RTM :)
Sks.Router.map ->
this.resource 'users', ->
this.resource 'user', path: ':user_id'