EmberJS is not automatically showing attributes from context object in view - javascript

After following the "Outlets" guide on Emberjs.com (http://emberjs.com/guides/outlets/) I am unable to show the title and body of the post in the Post (child/singular) template. Have any of you run into this? Here's the rundown:
# PostsTemplate
{{#each post in controller}}
<h1><a {{action showPost post href=true}}>{{post.title}}</a></h1>
<div>{{post.body}}</div> <------ title and body show up correctly here
{{/each}}
# PostTemplate
<h1>{{title}}</h1> <---- but title and body are EMPTY here
<div class="body">
{{body}}
</div>
{{outlet}}
# Router
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: '/',
redirectsTo: 'posts'
}),
posts: Ember.Route.extend({
route: '/posts',
showPost: Ember.Route.transitionTo('post'),
connectOutlets: function(router) {
router.get('applicationController').connectOutlet('posts', App.Post.find());
}
}),
post: Ember.Route.extend({
route: '/posts/:post_id',
connectOutlets: function(router, post) {
console.log(post); <------------------ This tells me the post has the write attributes.
router.get('applicationController').connectOutlet('post', post); #This post does not show up in PostTemplate above!
}
})
});
When I run console.log(post), and inspect the post, I see that I have something like the following:
Class = {
id: "1",
_data:
{
attributes:
{
body: "a",
title: "a"
}
},
title: null,
body: null
}
Anyone have any ideas as to why I'm not seeing the title or body attributes show up in the view?
p.s. the Post model is an Ember data model that correctly retrieves the Post with id 1 from a Rails application.

I believe you can use {{content.title}} and {{content.body}} since your Post model should be set to the content of the postController. An easy way to debug this within the view is to put {{content}} in the view which will render the type of model that the item is (such as App.Post).

Related

Emberjs - model hook returns null from BelongsTo relationship

I have a form within the new-phone route which populates a phone model. This model has a belongsTo relationship with the client.
App.Router.map(function() {
this.resource("client", { path: "/client/:id" }, function(){
this.resource("phone", function(){
this.route("new-phone")
})
})
})
App.Client = DS.Model.extend({
name: DS.attr(),
phone: DS.belongsTo("Phone", { async: true })
});
App.Phone = DS.Model.extend({
name: DS.attr(),
model: DS.attr(),
year: DS.attr()
});
When I complete the form, the response from the server comes back correctly with the newly created record.
I'm getting data from JSON driven API.
So I'm posting to:
POST: /api/client/1/phone
I have set the transition to go back to the phone.index page (after the save is complete) which in turn (should) fire the model hook (GET request: /api/client/1/phone) and get the new data for the (phones.index) page. But for some reason, I get a 'data is null' error from Ember. It doesn't even seem to make the request before this error appears.
If I use the HTTP requester outside of the Ember app, the data appears.
App.ClientRoute = Ember.Route.extend({
model: function(){
return this.store.find("client", 1)
}
});
App.PhoneIndexRoute = Ember.Route.extend({
model: function(){
return this.modelFor("client").get("phone").then(function(data){
//Reload to manually get new data
return data.reload();
});
}
})
This is the version of Ember I'm using:
DEBUG: Ember : 1.8.1
DEBUG: Ember Data : 1.0.0-beta.11
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.10.2
I dont think you need a new route to show a form for person's phone. Instead make a property to toggle when user clicks for phone form
Let's say your template looks like this
/user/1.hbs
{{model.user_name}} {{model.first_name}}
{{model.phone.number}}
{{#if showPhoneForm}}
<div class="form">
{{input value=model.phone.number placeholder="phone nr"}}
</div>
<div class="button" {{action "saveUser"}}> Save </button> // Save form data, hide user form, updaet user phone data
{{else}}
<div class="button" {{action "makePhoneForm"}}> Add phone </button> // Create form for user
{{/if}}
controllers/user/
showPhoneForm: false,
actions: {
makePhoneForm: function() {
this.set('showPhoneForm', true);
},
saveUser: function() {
this.get('model.phone').then(function(phoneRecord) {
phoneRecord.save().then(function(){
this.set('showPhoneForm', false);
}.bind(this):
}
}

how to define nested routes + ember not rendering template for nested route

I have a rails 4 + emberjs application. I am trying to create nested routes in ember. I am refering the 'nested routes' section from http://emberjs.com/guides/routing/defining-your-routes/. All the defiend routes for post work fine but the routes for 'comments' dont work. My current ember routes are as:
App.Router.map ->
#resource 'posts', ->
#route 'edit',
path: '/:id/edit'
#route 'show',
path: '/:id'
#resource "comments",
path: '/:post_id/comments'
, ->
#route "new"
I have a CommentsNewRoute file as:
App.CommentsNewRoute = Ember.Route.extend
model: (params) ->
post: #store.find 'post', params.post_id
And have a template as comments.handlebars containing {{outlet}} and comments/new.handlebars containing 'Hello World'. Have places comments.handlebars and new.handlebars inside posts templates as well as at the same level. Still, none are rendered.
the link-to helper is as:
{{#link-to 'comments.new' id classNames='pull-right' }}Add New Comment{{/link-to}}
The problems are that 1) The params in the CommentsNewRoute is an empty object and doesnt contain post_id. 2) The new comments template isnt rendered when i click a link that points to '/#/posts/2/comments/new'. 3) How can i display the post's objects data on the new comments page? What am I doing wrong?
Dynamic segment values are only available to the route that the dynamic segment belongs to.
Which means you should load the post on App.CommentsRoute and reuse it on App.CommentsNewRoute, see the example
App.CommentsRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('post', params.post_id);
}
});
App.CommentsNewRoute = Ember.Route.extend({
model: function () {
return this.modelFor('comments');
}
});
More info

Meteor.js Handlebar Returns different Text depending on current Route in Iron Router

When using Iron Router with Meteor.js 0.8.3, how can I have a text in a view template that changes depending on which route the user is on?
For example, if a user is at /profile, the text would be User Profile and if he is at / the text will be Home.
header.html
<template name="header">
<h1>{{ routeTitle }}</h1>
</template>
profile.html
<template name="profile">
{{> header}}
</template>
router.js
Router.map( function() {
this.route('index', {
path: '/',
template: 'index'
})
this.route('profile', {
path: '/profile/:_id',
template: 'profile',
data: function() { return Users.findOne(this.params._id); }
})
})
I personally store my own properties in the route options like this :
Router.map(function(){
this.route("index", {
// iron-router standard properties
path: "/",
// custom properties
title: "Home"
//
controller: "IndexController"
});
this.route("profile", {
path: "/profile/:_id",
title: "User profile",
controller: "ProfileController"
});
});
Then I extend the Router with a set of utilities functions to access the current route.
_.extend(Router,{
currentRoute:function(){
return this.current()?this.current().route:"";
}
});
UI.registerHelper("currentRoute",Router.currentRoute.bind(Router));
Using these utilities, you can call Router.currentRoute() in JS which happens to be a reactive data source too, as it acts as a wrapper for Router.current().
Use Router.currentRoute() && Router.currentRoute().options.title to check whether there is a current route and fetch the title you declared in the route definition.
In templates you can use {{currentRoute.options.title}} to fetch the current title, this is helpful when working with iron-router layouts.
If you want to get more specific you can even mimic the Router.path and pathFor helper behavior :
_.extend(Router,{
title:function(routeName){
return this.routes[routeName] && this.routes[routeName].options.title;
}
});
UI.registerHelper("titleFor",Router.title.bind(Router));
Now you can call Router.title("index") in JS and {{titleFor "index"}} in templates.
You can even get as far as having a dedicated helper for the current route title, as you suggested in your question :
UI.registerHelper("currentRouteTitle",function(){
return Router.currentRoute() && Router.currentRoute().options.title;
});
You can achieve this very easily with data param of the path:
Router.map(function() {
this.route('...', {
...
data: function() {
return {
importantText: 'User Profile',
};
},
});
});
Now use it as any other data object in your rendered template, layout template, or any of the templates rendered to named area:
{{importantText}}

reset emberjs model in form

I have a route that displays a list of posts and also a form for creating a new post.
posts_route.js.coffee:
Fortchan12.PostsRoute = Ember.Route.extend
model: ->
Ember.RSVP.hash
posts: #get('store').findAll 'post'
newPost: #get('store').createRecord 'post'
actions:
create: (post) ->
post.setProperties
name: this.controller.get('name')
body: this.controller.get('body')
photo: this.controller.get('photo')
post.save()
and here is the handlebars template:
<h2>make a new post</h2>
<form {{action 'create' newPost on="submit"}}>
{{#if isSaving}}
<p>saving post...</p>
{{/if}}
<p>{{input type="text" value=name}}</p>
<p>{{textarea value=body}}</p>
<button type="submit">Create</button>
</form>
<h2>posts</h2>
{{#each posts}}
{{name}} says
{{body}}
{{created_at}} {{#link-to 'post' this}}
{{id}} {{/link-to}}
<br />
This seems to work fine, but I want to clear out the form after it is submitted and saved so I can make another post. I can do this in the create action in the route to clear out the form (although it doesn't seem to clear out the file input field):
self.controller.setProperties({name: '', body: '', photo: ''})
but that doesn't seem to 'reset' the model, when I submit the form again its trying to PUT to /posts/:id, instead of POST to /posts:
PUT http://0.0.0.0:3000/posts/70 404 (Not Found)
I'm not exactly sure what I am supposed to do, I've read that using setupController is an option but I'm not sure how to do that with using multiple models in my route like I am.
You'll want to create a new record as well, the page still has a reference to the other record, which you saved, and now that record has an id, which is why its trying to update that record (excuse the javascript).
actions:
create: (post) ->
self = #
post.save().then(function(){
self.set('controller.newPost', self.get('store').createRecord('post'));
});
Psuedo code mix for using all
model: function(){
return Ember.RSVP.hash({
posts: #get('store').findAll 'post',
newPost: #get('store').createRecord 'post'
});
},
setupController: function(controller, model){
controller.set('posts', this.get('store').all('post'));
controller.set('newPost', model.newPost);
}
reversed computed property
on the controller
reverseProperty: function(){
this.get('posts').sortBy('foo').toArray().reverse();
}.property('posts.[]')
Have you tried resetting the model like this?
#controller.set('content', #get('store').createRecord('post'))

Seo routes with ember serializer

Im following the example emberjs guides
...
this.route('author', { path: '/author/:post_userName' });
...
App.PostsAuthorRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find({userName : params.userName});
},
serialize:function(model) {
return { post_userName: model.get('userName')};
}
});
Then here is the link to
Author {{#linkTo 'posts.author' post }} {{post.userName }} {{/linkTo}}
The fun is when I click on the link I get a routing error
Error while loading route: TypeError {}
Uncaught TypeError: Object [Object Object] has no method 'slice'
But when I reload the page, the full data appears.
How can I solve the routing error, really I don't understand why I get the error and is solved on reload the page
Here is the jsbin of a similar case.
http://jsbin.com/aZIXaYo/31/edit
The problem is with the object you're passing to your link-to. You're doing this :
Author {{#linkTo 'posts.author' post }} {{post.userName }} {{/linkTo}}
which passes, a Post to the author route. Passing a model to link-to causes the model hook on the route to be skipped and the passed model is used instead. When you hit reload, the model hook is executed and the model for PostsAuthor route is set to be a collection of Post objects, and then things work as expected.
To do things The Ember Way (TM), you'd want to have an Author model that was related to your Post model. Then you'd have an AuthorRoute and AuthorController that needs a PostsController. In your link you'd pass post.author, and then use the setupController hook to prime the collection for the PostsController. Something like this:
App.Post = DS.Model.extend({
author : DS.belongsTo('post'),
title : DS.attr('string')
});
App.Author = DS.Model.extend({
name : DS.attr('string'),
userName : DS.attr('string')
});
App.AuthorRoute = DS.Route.extend({
model : function(){ // not called when the author is passed in to #link-to
return this.store.find('author',{userName : params.post_userName})
},
setupController : function(controller,model){
this._super(controller,model);
this.controllerFor('posts').set('content', this.store.find('post',{userName : model.userName}))
}
});
App.AuthorController = Ember.ObjectController.extend({
needs : ['posts']
});
App.PostsController = Ember.ArrayController.extend({
sortProperties : ['name']
});
Then the template :
Author {{#linkTo 'posts.author' post.author }} {{post.author.name }} {{/linkTo}}

Categories

Resources