Relevant information
I have a Rails 4.0 API server set up for data persistence, using ember-rails.
Ember Version: 1.3.0-beta.1+canary
Ember-Data Version: 1.0.0-beta.4+canary
Say I have a Categories model that contains a list of categories. I would like to render this at the Application level to be used as navigation.
Here is what I have
# templates/application.hbs
{{ render categories }}
{{ outlet }}
# templates/categories.hbs
<h1>Categories</h1>
{{#each category in controller}}
{{#link-to 'category' category}}
{{category.title}}
{{/link-to}}
{{/each}}
# routes/categories.js.coffee
App.CategoriesRoute = Ember.Route.extend
model: ->
#store.find 'category'
# models/category.js.coffee
App.Category = DS.Model.extend
title: DS.attr('string'),
slug: DS.attr('string')
# router.js.coffee
App.Router.map ->
#resource 'categories', path: 'categories'
#resource 'category', path: 'category/:slug'
Accessing the /#/categories path renders what I expect; a double of headings and the list of links, each pointing to a category.
If I access the root of the app (Application.Index) at '/', I am expecting to see the same result, albeit only a single rendering of a list of links. However, what results is just the single heading and no links. Using the Ember Inspector, it looks like there isn't a model tied to the {{ render categories }}.
From my understanding, rendering a template will use the relevant controller and view. What would be the correct way to bind the relevant model to the rendered template? Or better yet, what would be the best practice to achieve the same result?
When you call {{render categories}}, it will render the categories template with the categories controller. The CategoriesRoute is only used when going to the categories route in the url. In order to have the categories information available at the application level you will need to fetch the categories at that level and store it on the application controller somewhere for use when you render.
// controller would be application controller, and technically you wouldn't need to write controller
{{ render 'categories' controller.categories }}
http://emberjs.jsbin.com/IleQEFa/1/edit
In the example I'm attaching an additional set of models under the name someitems on the application controller. I'm doing this during the setupController, this is the hook that's fired after the model has been resolved in that route.
For you, in the setupController I'd do something like
this.store.find('category').then( function(records){ controller.set('categories', records)});
or maybe this, I'm not familiar with coffeescript
#store.find("category").then (records) ->
controller.set "categories", records
Related
I have an outlet in application.hbs called 'sidebar'. This outlet is used in some routes to render additional info using a component called 'sidebar-info'. In those routes I use renderTemplate to render stuff in the appropriate outlets. For example:
renderTemplate: function(controller, model) {
this.render('components/sidebar-info', {
into: 'application',
outlet: 'sidebar',
model: Ember.Object.create({
title: this.get('i18n').t('signup'),
detailsComponent: 'signup-help'
})
});
this.render('sign-up');
},
This is components/sidebar-info template:
<div class="title">
<h1>{{model.title}}</h1>
</div>
{{#if model.detailsComponent}}
<div class="details">
{{component model.detailsComponent}}
</div>
{{/if}}
When the route template (not the component one) is being rendered, the model defined by the route is overwritten by the model sent to the component. If the original model was something like this:
original_model = {
field_1: 1,
field_2: 2
}
Then using model.field_1 becomes undefined in the context of the template while model.title is available.
Why is the model being overwritten?
I am using Ember 2.2.0
It seems this is the correct behaviour. According to the Route API, this is the explanation of the controller and model options sent to the render method:
controller [String|Object]
the controller to use for this template, referenced by name or as a
controller instance. Defaults to the Route's paired controller
model [Object]
the model object to set on options.controller. Defaults to the
return value of the Route's model hook
This means that setting only the model option will set the model on the Route's paired controller because that is the default option.controller. This means we need either to create a dummy controller that only works to receive the model.
I have tested this and it works as expected.
I have designed an image carousel and navbar above it with different a category. The plan is when one of the categories are clicked the images in carousel change. The category are fetched from the backend and displayed in navbar. How do I relate it to the carousel for each category?
I am using ember js(1.13.0).
application.hbs
<ul>
{{#each result in model.results}}
<li><a href="" {{action 'carousel' result}}>{{result.gallery_name}}</a></li>
{{/each}}
</ul>
controller.js
export default Ember.ObjectController.extend({
actions:{
carousel:function (result) {
console.log(result.get('gallery_name'));
}
}
});
model.js
export default DS.Model.extend({
results: DS.attr()
});
server result (json)
results:[{name:abc,url:http://google.com},{name:acd,url:google.com}.....]
You JSON is
results:[{name:abc,url:http://google.com},{name:acd,url:google.com}.....]
//your Model
export default DS.Model.extend({
results: DS.attr()
});
I donot see "gallery_name" in your json.
I donot see name / gallery_name defined in your model
I see conflicting information on this. But this is what I'm currently doing. In my template, I have a form with the following action helper:
<button {{action "save" song}}>Save</button>
In my controller, I have the following:
App.SongsNewController = Ember.ObjectController.extend({
title: '',
actions: {
save: function() {
console.log(this.get('title'));
}
}
});
I also have a Song model defined and ideally, I'd like the values I submit from the form to be bound to that model and then just be able to reference the Song model in my controller, rather than getting properties from the controller and manually populating my model. Something like:
App.SongsNewController = Ember.ObjectController.extend({
actions: {
save: function(song) {
song.save();
}
}
});
I'm pretty sure this is possible (I hope anyway), I just am not finding the docs on that anywhere or am missing them.
Since you have array controller, I would assume that you would be iterating over your songs like this:
//songsNew.hbs
{{#each}}
{{input type="text" value=name}}
<button {{action "save" this}}>Save</button>
{{/each}}
Then you can have the "save" action as you mentioned in your post with song model passed as an argument.
But if you have itemController defined, then the action goes to the itemController itself, not the arrayController. If you want your array controller to handle the save, then you might have to set the target to the action as follows:
<button {{action "save" this target=parentController}}>Save</button>
EDIT:
In the SongNewRoute, define the model as:
model: function(){ return this.get('store').createRecord('song');}
This gives you new empty song model, you can bind your form to this model and when you make save action, the data gets persisted in db.
I have a nested route structure like this:
App.Router.map(function() {
this.resource('user', {path: '/user/:user_id'}, function() {
this.route('followers', {path: '/followers'});
});
});
when I hit the user/123/followers route I would expect that it automatically fetch the model from user/123/followers, but it just fetches the user model from user/123 again. What do I need to add so it fetches the right data for the route?
Each route have your own model, and this isn't propaged, by default.
So App.UserRoute model, returns the current model like expected:
App.User.find(params.user_id)
But because App.UserFollowersRoute have your own model hook, then you have to provided it.
You can do this easily using the modelFor.
App.UserFollowersRoute = Ember.Route.extend({
model: function() {
return this.modelFor('user');
}
});
The modelFor look for a model from a named route. So modelFor('user'), will retrieve the model from App.UserRoute.
And in your user/followers template, you will have the current user, in the current context:
<script type="text/x-handlebars" data-template-name="user/followers">
<h2>{{name}} followers:</h2>
<ul>
{{#each followers}}
<li>{{name}}</li>
{{/each}}
</ul>
</script>
Here a sample with this working
Ember will automatically call User.find(123) when you hit /user/123/... because that is the default model hook for App.UserRoute. If you want to fetch additional data when the followers route is accessed, define a model hook for App.UserFollowersRoute:
App.UserFollowersRoute = Ember.Route.extend({
model: function() {
user = this.controllerFor('user');
// Now find and return the list of followers
}
});
I have a simple app that is using ember-data to load from a RESTful web service and display the data using the route to specify the model.
App.AreasRoute = Ember.Route.extend({
model: function() {
return App.Area.find();
}
});
Then I can render the data in the handlebars template using {{#each content}}
But I want to have a second area of data from a different model displayed on the page as well. I started by creating a View and then rendering the view as part of my application template using {{view App.AnotherView}} which correctly renders the view.
However, this view doesn't have a route and therefore I have nowhere to tell it where to get it's data from. How do I do this?
The best place to load additional content is in the setupController hook of the route.
For example, if you define your route as
App.AreasRoute = Ember.Route.extend({
model: function() {
return App.Area.find();
},
setupController: function(controller) {
controller.set('someArea', App.Area.find('area_id'));
}
});
Then the Area model with id area_id can be accessed by {{someArea}} in your template.