reset emberjs model in form - javascript

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'))

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 use Ember query parameters with beforeModel and select?

Demo: http://jsbin.com/zexopa/1/edit?html,js,output
I use the query parameters in my application. And the queryParameters are 'name' and 'category'.
The 'name' parameter is used in the select and the 'category' uses the input, but there is something wrong with the select 'name' if I set it default to null.
If I change the 'name', the 'name' always is undefined in the url.
Route:
App.IndexRoute = Ember.Route.extend({
beforeModel: function() {
this.controllerFor('index').set('products', [1,2,3]);
},
model: function() {
return [{'is_active':false, 'name':'One'}, {'is_active':false, 'name':'Two'}, {'is_active':false, 'name':'Three'}, {'is_active':false, 'name':'Four'},{'is_active':false, 'name':'Five'}];
},
actions: {
queryParamsDidChange: function() {
this.refresh();
}
}
});
Controller:
App.IndexController = Ember.Controller.extend({
queryParams: ['name', 'category'],
name: null,
category: null
});
Template:
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{view "select" content=products value=name prompt="all"}}
{{input type="text" value=category class="form-control"}}
<ul>
{{#each model as |item|}}
<li>{{item.name}}</li>
{{/each}}
</ul>
</script>
Can you help to check what happens to my application?
Query params must be string to be properly binded. Your input works, as the value is String object. In name array you provided Integer. Unfortunately, I have not found any mention about that in docs, but you can see a working demo here: http://jsbin.com/lixili/1/edit?html,js,output
If I can give you some tip about your code:
beforeModel is not a place for setting controller properties, do it in setupController method as in JSBin provided
You did not defined query params in route, but you could and get rid of the queryParamsDidChange
Hope I helped!

Emberjs: Dynamic template nesting and routing

I've been trying to figure this out for most of today and it's driving me insane, because I think i'm almost there, but just can't figure the last part out...
I have a route, called Map, which renders a sidebar, and within it has a named outlet for sidebar content:
map.hbs:
<div id="map-container">
{{render sidebar}}
<div id="map-canvas">
</div>
</div>
...
sidebar.hbs:
<div id="content-menu">
{{outlet sidebar-content}}
</div>
Each menu item in my sidebar has a custom action called loadModule, which performs a render of a named view into the sidebar-content outlet (using {{action 'loadModule' 'sidebar.module'}}):
var MapRoute = App.AuthenticatedRoute.extend({
actions: {
loadModule: function(module) {
//load a valid view template into the view
this.render(module,
{
into: 'sidebar',
outlet: 'sidebar-content'
});
}
}
});
module.exports = MapRoute;
Any action within the controller for that view works fine, I can trigger them from buttons etc, or by calling them in a didInsertElement in the SidebarModuleViews.
My issue is that I can't define a model for these views, so if I try and get data from my API in any of their Controllers, it won't render that data out to the templates.
I tried to use link-to, but I couldn't make the template append to the current viewport, rather than refreshing the entire page, which defeats the point of having a sidebar (I don't want the route to change)
var SidebarUserController = App.ApplicationController.extend({
actions: {
doSomething: function() {
alert('SOMETHING');
},
fetchUserProfile: function() {
//do something
var mod = this.store.find('profile', App.Session.get('uid'));
}
}
});
I can trigger either of those actions from the rendered template once it's rendered, however, although my store updates with the record, the handlebars helpers in the sidebar/user.hbs do not populate with the model data.
Here is my model:
var Profile = DS.Model.extend({
uid: DS.attr('string'),
firstName: DS.attr('string'),
lastName: DS.attr('string'),
gender: DS.attr('string'),
DOB: DS.attr('date'),
email: DS.attr('string')
});
module.exports = Profile;
and here is my sidebar/user.hbs:
<div class="container">
<button {{action 'doSomething'}}>Do A Thing</button>
<h1>{{firstName}} {{lastName}}</h1>
<h4>{{id}}</h4>
{{#if isAuthenticated}}
<a href="#" {{action 'logout'}}>Logout</a>
{{/if}}
</div>
In that template, the firstName, lastName and id fields do not populate, even though i'm pulling the data from the API and successfully storing it.
Additionally, if it helps, my router.map for sidebar/user looks like this:
this.resource('sidebar', function() {
this.route('user');
});
I believe that the fundamental issue here is that I can't work out how to set the model for the controller without triggering the route. Am I going about this wrong?
Ok so i've worked this out for my particular instance. It may not be the best way of doing it, but it's what I need:
In my MapRoute, I setup the model and controller for my additional sidebar menus in the setupController function. Doing this allows me to load critical data (such as user profile etc), on page load, and I can still retain the render function for each sidebar module in the Route, which will allow the intial data to load, and still allow me to update the model data for each sidebar module controller on subsequent functions:
map_route.js:
actions: {
loadModule: function(module) {
this.render(module, {into: 'sidebar', outlet: 'sidebar-content'});
}
},
setupController: function(controller, profile) {
var model = this.store.find('profile', App.Session.get('uid'));
var controller = this.controllerFor('sidebar.user');
controller.set('content', model);
},
...

Load data from controller in ember.js

I want to implement a system that shows me the newest posts. For this I do not want to use the index action from the user as this is already taken for another post function but a "newest" action. It is showed on the index route with a {{ render "postNewest" }} call. I would prefer to load the data in the PostNewestController or PostNewestView instead of the route for abstraction reasons.
I tried two ideas to achieve this, but none worked so far:
create a custom adapter and add a findNewest() method: the findNewest() method is sadly not found when trying to call in the init method of the controller.
write the request directly into the init method and then update with store.loadMany(payload): data is successful request. However, I do not know how to access the data from the template and set the content of the controller.
Is there any way for this?
EDIT:
Here is the source code to better understand the problem:
PostModel.js
App.Post.reopenClass({
stream: function(items) {
var result = Ember.ArrayProxy.create({ content: [] });
var items = [];
$.getJSON("/api/v1/post/stream?auth_token=" + App.Auth.get("authToken"), function(payload) {
result.set('content', payload.posts);
});
return result;
}
});
PostStreamController.js
App.PostStreamController = Ember.ArrayController.extend({
init: function() {
this.set("content", App.Post.stream());
},
});
index.hbs
{{# if App.Auth.signedIn}}
{{ render "dashboard" }}
{{else}}
{{ render "GuestHeader" }}
{{/if}}
{{ render "postStream" }}
postStream.hbs
{{#each post in model}}
<li>{{#linkTo 'post.show' post data-toggle="tooltip"}}{{post.name}}{{/linkTo}}</li>
{{else}}
Nothing's there!
{{/each}}
PostShowRoute.js
App.PostShowRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
},
setupController: function(controller, model) {
controller.set('content', model);
},
});
I Had this issue too. Just add init in your controller, and define the model you want to get there.
In your Controller
App.PostRecentController = Ember.ArrayController.extend({
init: function() {
return this.set('content', App.Post.find({
recent: true
}));
}
});
In your template
{{#each post in content}}
{{post.body}}
{{/each}}
I would recommend you check EMBER EXTENSION, it will give you a good idea of the naming, and see if everything is missing.
I figured out the problem. The Post model has a belongsTo relationship to another model. This relationship is not loaded by Ember so in the stream() method I have to load this manually. Then everything works as expected.

EmberJS is not automatically showing attributes from context object in view

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).

Categories

Resources