So I want to store all of my API keys in a config file in my backend so I don't have them scattered all over the place. So I thought I would be a able to create a Model on the frontend to do a GET on /config and then I would be returned a config object with any API keys I would need. So I'm basically trying to access a model from the ApplicationRoute. To be clear, the request happens right now but I have no idea how to access the data from the index template. I've tried things {{App.Config.apiKey}}, {{apiKey}}, trying to set #get.controllerFor('application').get('model') in the index controller and see if I could look at values, none have worked. I'm using Ember 1.0.0 .4pre. Thanks
So I have something like this:
App = Ember.Application.create
rootElement: '#app'
# Models
App.Store = DS.Store.extend
revision: 11
App.User = DS.Model.extend
firstName: DS.attr 'string'
lastName: DS.attr 'string'
accountType: DS.attr 'string'
email: DS.attr 'string'
_id: DS.attr 'string'
password: DS.attr 'string'
fullName: (->
"#{#get('firstName')} #{#get('lastName')}"
).property('firstName', 'lastName')
App.Config = DS.Model.extend
secret: DS.attr 'string'
apikey: DS.attr 'string'
# Controller
# This is has validations for a form in it but I don't think its relivent
App.IndexController = Ember.ObjectController.extend()
# Routes
App.ApplicationRoute = Ember.Route.extend
model: ->
App.Config.find()
App.IndexRoute = Ember.Route.extend
model: ->
App.User.createRecord()
DS.RESTAdapter.configure "plurals", {
config: "config"
}
App.Router.map ->
#resource 'index'
And my templates look something like this:
<!--- index.html --->
<html>
<head></head>
<body>
<div id="app"></div>
</body>
</html>
<!--- application.hbs --->
<div class="container">
{{outlet}}
</div>
<--- index.hbs --->
<div>
{{apiKey}} <!-- This is a value from the Config Model -->
{{firstName}} <!-- This is a value from the User Model -->
</div>
Either define explicitly your ApplicationController as an ObjectController
App.ApplicationController = Ember.ObjectController.extend()
then in your ApplicationRoute set the content of the controller to the config object
App.ApplicationRoute = Ember.Route.extend
setupController: (controller, model) ->
this._super(controller,model);
controller.set('content',App.Config.find(1));
Or, set your config in your index controller such as
App.IndexRoute = Ember.Route.extend({
setupController: function(controller,model) {
this._super(controller,model);
controller.set('config',App.Config.find(1));
}
})
and then in your template
<div>
{{config.apiKey}} <!-- This is a value from the Config Model -->
{{config.firstName}} <!-- This is a value from the User Model -->
</div>
See a working jsfiddle using the first approach
You can learn about the different type of controller supported by ember here
Related
Heyy!!
I'm having trouble passing a model to a route in ember cli. I'm making a simple app where posts have and author and a title. When you click the title you go to the post details and when you click the author you go to the author's profile. My problem is that I go to the respective user but when I refresh the page I get a n error in the author route. I have no idea why, I'm guessing it has to do with the model not being fetched again when I refresh since it passes the model using link-to helper
My code (client):
app/models/author.js
import DS from 'ember-data';
export default DS.Model.extend({
posts: DS.hasMany('post', {async: true}),
name: DS.attr('string'),
url: DS.attr('string')
});
app/models/post.js
import DS from 'ember-data';
var attr= DS.attr;
export default DS.Model.extend({
author: DS.belongsTo('author'),
title: attr('string'),
description: attr('string'),
date: attr('date'),
url:attr('string'),
});
app/routes/author.js
import Ember from 'ember';
export default Ember.Route.extend({
setupController: function(controller, model) {
model.reload();
controller.set('model', model);}
});
app/templates/posts.hbs
<div class="container" style="width:70%">
{{#each model as |post|}}
<div class="well">
<div class="media">
<a class="pull-left" >
<img class="media-object" src={{post.url}} style="width:200px;height:200px">
</a>
<div class="media-body">
<h1>{{#link-to 'post' post}}{{post.title}}{{/link-to}}</h1>
<h4>Posted by: {{#link-to 'author' post.author.id}} {{post.author.name}}{{/link-to}} </h4>
<p>{{post.description}}</p>
</div>
</div>
</div>
{{/each}}
</div>
My Code (server):
var authors=[];//list of authors
var profileRouter= express.Router();
profileRouter.get('/', function(req, res) {
res.send({
'authors':authors
});
});
profileRouter.get('/:id', function(req, res) {
res.send({
'author': authors.find(function(user){
return author.id==req.params.id
// id: req.params.id,
})
});
});
app.use('/api/author', profileRouter);
You are correct that link-to is passing the model, which is not happening when the page is refreshed. You need to define the model hook on the author route (which is not called when the model is passed) -
model: function(params) {
return this.store.find('author', params.id);
}
I am building an Ember app to show a simple Twitter-like tagging system. When a user visits /items, he or she will see a list of all items. When the user visits /tags, the user will see a list of tags as links. When the user clicks one of these links, the user should be directed to /tags/:id and will see all items tagged with that specific tag. Then the user will be able to search/sort/manipulate the items as he/she would be able to from the ItemsRoute.
How can I make TagRoute use ItemsController and render the items template, using the tag's associated items as the model?
I have tried different combinations of the hooks in TagRoute, and I'm not able to find a recipe that works. There seems to be a fundamental misunderstanding on my part.
Here is my relevant code:
router.js.coffee
App.Router.map ()->
#resource 'items'
#resource 'tags', ->
#resource 'tag', path: ':tag_id'
routes/tag.js.coffee
App.TagRoute = Ember.Route.extend
model: (params)->
#get('store').find 'tag', params.tag_id
controllerName: 'items'
setupController: (controller, model)->
#controllerFor('items').set('model', model.items)
renderTemplate: ->
#render 'items', ->
into: 'tags'
controller: 'items'
templates/tags.hbs
<ul class="tag-list">
{{#each tag in model}}
<li>
{{#link-to 'tag' tag}}
{{tag.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
models/items.js.coffee
App.Item = DS.Model.extend(
body: DS.attr('string')
checked: DS.attr('boolean')
tags: DS.hasMany('tag')
)
models/tags.js.coffee
App.Tag = DS.Model.extend(
name: DS.attr('string')
taggings_count: DS.attr('number')
items: DS.hasMany('item')
)
Currently, this give me an error:
Error while processing route: tag Cannot assign to read only property 'name' of function () {
return {
into: 'tags',
controller: 'items'
};
} TypeError: Cannot assign to read only property 'name' of function () {
return {
into: 'tags',
controller: 'items'
};
}
Looking at the Ember Routes Inspector in Chrome, the controllerName property is the only one which overrides Ember's defaults, and Ember still tries to render a generated tag template.
As ahmed.hoban suggested, I have solved this using query params. This helps me avoid duplicating routes and having a tangled router. It hits the database, which is not preferable, but I'm not sure at this point if I'll make that a requirement. I have control over the full-stack, so I was able to make adjustments on the back-end to support the request.
router.js.coffee
App.Router.map ()->
#resource 'tags', path: '/', ->
#resource 'items'
routes/tag.js.coffee - deleted
templates/tags.hbs
<ul class="tag-list">
{{#each tag in model}}
<li>
{{#link-to 'items' (query-params tag=tag.id)}}
{{tag.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
{{outlet}}
controllers/items.js.coffee
App.ItemsController = Ember.ArrayController.extend(
needs: 'tags'
queryParams: ['tag']
tag: null
items: (->
tag = #get 'tag'
if tag
#store.find 'item', tag: tag
else
#get 'model'
).property('tag', 'model')
)
I'm building the mandatory TODO app to learn ember.
I have tasks and tags in a belongsTo/hasMany relationship (each tag hasMany tasks). When showing tasks, I want to show a computed property on each available tag.
Models:
App.Tag = DS.Model.extend({
tasks: DS.hasMany('task', {async: true}),
..
});
App.Task = DS.Model.extend({
tag: DS.belongsTo('tag', {async: true}),
..
});
Route:
App.TasksRoute = Ember.Route.extend({
model: function(params) {
return Ember.RSVP.hash({
tasks: this.store.find('task'),
tags: this.store.find('tag')
});
},
setupController: function(controller, model) {
this.controllerFor('tasks').set('content', model.tasks);
this.controllerFor('tags').set('content', model.tags);
}
});
Tags controller:
App.TagsController = Ember.ArrayController.extend({
needs: ["tag"]
})
Tag controller:
App.TagController = Ember.ObjectController.extend({
taskCount: function() {
// FOLLOWING DOES NOT WORK
return this.get('tasks.length')
}.property('tasks')
});
Tag partial:
<ul>
{{#each tag in model}}
<li>
{{tag.name}} ({{controllers.tag.taskCount}} tasks)
</li>
{{/each}}
</ul>
The computed property 'taskCount' does not work. There is something wrong with 'this'.
Is this canonical way of doing it? And if so, what is wrong? Thanks
EDIT: FIXED
I had missed out
App.ApplicationSerializer = DS.ActiveModelSerializer.extend();
And I've used render to get the controller decoration:
{{render 'tag' tag}}
which calls the controller before rendering
If I have an "organization" that has many "clinics" and in my app I don't want the routes nested, but I want to access the clinics on an organization page and the organization on a clinic page, is there something special I need to do? I am using rails as a backend and if I switch from the RestAdapter to the ActiveModelAdapter and embed the clinic ids it works, but I would like to know how to do it with the standard RestAdapter.
Router:
App.Router.map ->
#resource 'organizations', ->
#resource 'organization', path: 'organization/:organization_id', ->
#resource 'clinics', ->
Organization template:
<h1>{{name}}</h1>
<h2>Clinics</h2>
{{#link-to 'clinics.new'}}New Clinic{{/link-to}}
<ul id="org-clinics">
{{#each clinics}}
<li>{{#link-to 'clinic' this}}{{name}}{{/link-to}}</li>
{{else}}
<strong>No clinics yet...</strong>
{{/each}}
</ul>
Organization model:
App.Organization = DS.Model.extend
name: DS.attr 'string'
clinics: DS.hasMany 'clinic', async: true
Clinic template:
<h1>{{name}}</h1>
<strong>Organization: </strong>{{organization.name}}
Clinic model:
App.Clinic = DS.Model.extend
name: DS.attr 'string'
organization: DS.belongsTo 'organization'
Depends on how you want to go about it, but you can bind controller content super easily. For example:
App.OrganizationsController = Ember.ArrayController.extend({
needs: ['clinics'],
clinics: null,
clinicsBinding, 'controllers.clinics.content',
clinicsUpdated: function () {
// Do something here because some record updated
}.observes('clinics.#each.content') // Bind properties
});
App.ClinicsController = Ember.ArrayController.extend({
needs: ['organizations'],
organizations: null,
organizationsBinding, 'controllers.organizations.content'
});
You can acess them in templates, too. For example, {{#each clinics}}
Hope that helps!
I have prepared this jsfiddle. This is the code:
App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 13,
adapter: 'DS.FixtureAdapter'
});
App.Router.map(function() {
// put your routes here
});
App.User = DS.Model.extend({
name : DS.attr('string'),
email : DS.attr('string'),
});
App.User.FIXTURES = [{ id: 'me', name: 'Max Smith', email: 'max.smith#email.com' }];
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
And this is the template:
<script type="text/x-handlebars" data-template-name="index">
{{#each model}}
<div class="form_labels_wrapper">
<dl class="dl-horizontal">
<dt>Id:</dt> <dd>{{id}}</dd>
<dt>Name:</dt> <dd>{{name}}</dd>
<dt>Email:</dt> <dd>{{email}}</dd>
</dl>
{{/each}}
</div>
</script>
What I want to do is to display the data of a single user. The opbject has no id (it represents the logged in user, which is session related, and has no id visible for ember). Instead, I am forced to create a list of users (with one user), and give it a fake id (me). This makes no sense in my application.
I would like to use this template, but I have no idea how to configure ember for this:
<script type="text/x-handlebars" data-template-name="index">
<div class="form_labels_wrapper">
<dl class="dl-horizontal">
<dt>Name:</dt> <dd>{{name}}</dd>
<dt>Email:</dt> <dd>{{email}}</dd>
</dl>
</div>
</script>
With this fixture:
App.User.FIXTURES = { name: 'Max Smith', email: 'max.smith#email.com' };
Note that this is a single element, and that I am not looping through the models with #each, because this should not be a list: there is only a single element.
Ember refuses to accept this. What can I do to get this to work?
You can returning an array of records from the model hook, as a result ember is generating an ArrayController for it, which expects it's content to be an array.
Change the model hook to return the single record. For instance using me as the id.
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.User.find('me');
}
});
Then your template works. See the updated jsfiddle.