Why doesn't Ember model update? - ember.js

My goal is to simply update append a number to an array model. This should create a new HTML element due to the iterator I have used in the template.
My action does get called, but the model doesn't really update.
Here is my directory structure:
- app
- routes
- compare.js
- templates
- compare.hbs
- application.hbs
- app.js
- index.html
- router.js
compare.hbs:
<div id="container">
<form method="post" name="login" {{action "submit" on="submit"}}>
<p>
Member ID
</p>
<p> {{input id="member-id" type="text"}} <input type="submit" value="Search"></p>
</form>
<div id="results">
{{#each model as |result|}}
<p>{{ result }}</p>
{{/each}}
</div>
</div>
router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('compare');
});
export default Router;
compare.js
import Ember from 'ember';
let results = [12, 34, 56];
export default Ember.Route.extend({
model: function() {
return results;
},
actions: {
submit: function() {
results.push(123);
this.get('model').push(123);
this.refresh();
}
}
});
What is the problem?

It looks like you have a few issues. You don't need results.push as that is just adding the value to the array outside of Embers knowledge. When adding to the model use pushObject as that should notify ember of the change. There is also no need to call refresh on the model.
The documentation for pushObject shows an example very similar to what you are attempting:
http://emberjs.com/api/classes/Ember.NativeArray.html#method_pushObject
import Ember from 'ember';
let results = [12, 34, 56];
export default Ember.Route.extend({
model: function() {
return results;
},
actions: {
submit: function() {
this.model().pushObject(123);
}
}
});

Related

unable to parse API response in ember

I am trying to learn EmberJS and restify. I have get method API with following response :
{"products":[{"id":1,"name":"lappy1"},{"id":2,"name":"lappy2"}]}
This response I am getting in my browser's network log.
My product route is like :
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return {
products :this.get('store').findAll('product')
};
}
});
My product.hbs is :
<div>
<div class="row">
<div class="col-md-4"><b>id</b></div>
<div class="col-md-4"><b>Name</b></div>
</div>
{{#each model.products as |product|}}
<div class="row">
<div class="col-md-4">{{product.id}}</div>
<div class="col-md-4">{{product.name}}</div>
</div>
{{/each}}
</div>
My product model is :
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string')
});
There is no any error on log, but my page only shows header part i.e
<div class="col-md-4"><b>id</b></div>
<div class="col-md-4"><b>Name</b></div>
which thing I am missing ?
Install Chrome Ember plugin and use Chrome for debugging.
I assume you are using the RESTAdapter?
Your Route's model hook returns an object, not a promise. This is a little odd, I would recommend using a Hash:
model() {
return Ember.RSVP.hash({
products: this.store.findAll('product')
});
}
Alternately, you could just return the result of calling the store:
model() {
return this.store.findAll('product');
}
But in this case, you would change your templates to just use model instead of model.products.

ember - loading model data in route for power sort?

I have a very simple set up right now. I have a book model that has a name and author. I'm trying to create a simple form that will create a new book. For the author I'm using power select to load the authors from the author model. The form set up looks like this:
<form {{action "save" on="submit"}}>
{{input value=model.title placeholder="Title"}}<br>
{{#power-select class="select"
selected=model.author
options=authors
onchange=(action (mut model.author)) as |author|}}
{{author.name}}
{{/power-select}}
<input type="submit" value="Save">
</form>
However I'm having trouble setting up the route to get this working. So far no authors show up in the select, even though there are authors stored in my database. My route looks like this:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.createRecord('book');
},
actions: {
save() {
this.modelFor(this.routeName).save();
}
},
store: Ember.inject.service(),
authors: Ember.computed({
get() {
return this.get('store').findAll('author');
}
}).readOnly()
});
First of all, how should I properly load data from the author model in the route for the books/new route? Secondly, should I be doing this in the route? From what I have read, and what people have told me, loading model data should be done in the route.
Move authors property to corresponding controller.
Also you don't need to add readonly.
So in controller :
authors: Ember.computed(function(){
return this.get('store').findAll('author');
})
And for loading model in route. Yes you should load that model which is to be a resource manipulating, in route. So now you're doing it right.
1) Using Ember.RSVP.hash inside route model hook
your route file-> I assume books/new.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return Ember.RSVP.hash({
newBook : this.store.createRecord('book'),
authors : this.store.findAll('author')
});
},
actions: {
save() {
this.modelFor(this.routeName).newBook.save();
}
}
});
and inside template you can access authors by using model.authors. and title by using model.newBook.title
<form {{action "save" on="submit"}}>
{{input value=model.newBook.title placeholder="Title"}}<br>
{{#power-select class="select"
selected=model.newBook.author
options=model.authors
onchange=(action (mut model.newBook.author)) as |author|}}
{{author.name}}
{{/power-select}}
<input type="submit" value="Save">
</form>
2) Like ebrahim suggested, you can have the below code in required controller,
authors: Ember.computed(function(){
return this.store.findAll('author');
})
3)As author model data is going to be shared data model for authors,books,books.new routes. so you can keep it in service and access it from all the required routes.
authors-service.js -> In service
import Ember from 'ember';
export default Ember.Service.extend({
store:Ember.inject.service(),
authors: undefined,
init(){
this._super(...arguments);
this.get('store').findAll('author', { reload: true }).then(function(results){
this.set('authors',results); //As this is going to be Ember.enumerables, you can iterate and get the data.
});
}
});
You can access authors from authors-service.js in any where by injecting it
authorsService:Ember.inject.service(). I guess in your case, you need to create controller books/new.js for books/new.hbs template,
books/new.js -> controller file
import Ember from 'ember';
export default Ember.Controller.extend({
authorsService:Ember.inject.service(),
authors: Ember.computed.alias('authorsService.authors');
});
Inside books/new.hbs template you can access authors property.

Passing a relationship model through link-to helper? ember 2

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);
}

Ember select not binding to a property in the model

If I understand the ember.js documentation correctly then I should see the models systemStatus value get populated, but I'm not:
<div class="form-group">
<label class="col-sm-2 control-label" for="name">Description</label>
<div class="col-sm-10">
{{view "select" content=statuses value=model.systemStatus }}
</div>
</div>
This is the controller:
import Ember from "ember";
export default Ember.Controller.extend({
statuses: ["Being Built", "Active","Inactive"],
selectedSystemStatus: 'Active',
actions: {
save: function() {
// this.model.set('systemStatus', this.selectedStatus);
var s = this.get('selectedSystemStatus');
this.model.save();
},
cancel: function() {
}
}
});
The model:
import DS from "ember-data";
export default DS.Model.extend({
name: DS.attr('string', {defaultValue: 'Hello'}),
systemStatus: DS.attr('string', {defaultValue: 'Active'}),
description: DS.attr('string', {defaultValue: 'Describe me'})
});
The router:
import Ember from "ember";
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('software-system');
}
});
Everything works up until you try to select an option from the UI. I'm not sure what I'm doing wrong here, and would like some help.
do you have any place where you call this.store.find('my-model')? This is where the model gets populated.
The default way would be to put it into a corresponding route in the model hook:
// routes/my-model.js
export default Ember.Route.extend({
model: function() {
return this.store.find('my-model');
}
});
With this approach, your controller will wait until the model is loaded.

How do I pass the value of a query param into the form?

My URL looks like http://localhost:4099/checkout/schedule/new?addressId=12 I am trying to pass the query param addressId to the form.
I've tried submitting it as a hidden input, but by the time it hits the save action. I check the Network tab of Ember inspector and this is what it is passing:
{"delivery":{"instructions":"foo","deliver_on":"bar","address_id":null}}
address_id is still null. What am I missing?
Full code below:
// app/pods/checkout/schedule/new/route.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('delivery');
// return this.store.createRecord('delivery', { addressId: this.get('addressId')});
},
// Cleanup the controller, when you leave the new route so the stale new record is also
// removed from the store.
// You can also use https://github.com/dockyard/ember-data-route instead
resetController: function (controller, isExiting) {
var model = controller.get('model');
if (!model.get('isDeleted') && isExiting && model.get('isNew')) {
model.deleteRecord();
} else {
model.rollback();
}
}
});
// app/pods/checkout/schedule/new/controller.js
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: ['addressId'],
addressId: null,
actions: {
save: function() {
var _this = this;
// this.get('model').set('addressId', this.get('addressId'));
this.get('model').save().then(function(){
_this.transitionToRoute('checkout.address.index');
}, function() {
// Need this promise, so we can render errors, if any, in the form
});
return false;
},
cancel: function() {
return true;
}
}
});
// app/pods/checkout/schedule/new/template.hbs
<form {{action "save" on="submit"}}>
{{addressId}}
{{input type="hidden" value=addressId}}
<p>
<label>Instructions:
{{input value=model.instructions}}
</label>
{{#each error in errors.instructions}}
<br />{{error.message}}
{{/each}}
</p>
<p>
<label>Deliver on:
{{input value=model.DeliverOn}}
</label>
{{#each error in errors.DeliverOn}}
<br />{{error.message}}
{{/each}}
</p>
<input type="submit" value="Next"/>
<button {{action "cancel"}}>Cancel</button>
</form>
// app/models/delivery.js
import DS from 'ember-data';
export default DS.Model.extend({
address: DS.belongsTo('address', { async: true }),
items: DS.hasMany('item', { async: true }),
instructions: DS.attr('string'),
deliverOn: DS.attr('string')
});
I believe what's happening is that you are not really submitting your form. Instead, you are calling save() on your model, which submits your model data. Therefore, hidden parameter in the form will not help you here.
Your addressId in the URL is tied to your addressId property in the controller, where as the addressId: null you are seeing being submitted in Chrome is the value of addressId property in the model