Ember novice here. I have been following along with the tutorial on the Ember website here.
I have been R&D'ing the example to the word and everything works...until I try implementing Mirage. The data just never shows up on the index.hbs page.
Here's my model hook:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('rental');
},
});
And my model: rental.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
owner: DS.attr('string'),
city: DS.attr('string'),
type: DS.attr('string'),
image: DS.attr('string'),
bedrooms: DS.attr('number')
});
My index.hbs:
<h1> Welcome to Super Rentals </h1>
We hope you find exactly what you're looking for in a place to stay.
{{#each model as |rentalUnit|}}
{{rental-listing rental=rentalUnit}}
{{/each}}
{{#link-to "about"}}About{{/link-to}}
{{#link-to "contact"}}Click here to contact us.{{/link-to}}
and lastly my app/mirage/config.js:
export default function() {
this.get('/rentals', function() {
return {
data: [{
type: 'rentals',
id: 1,
attributes: {
title: 'Grand Old Mansion',
owner: 'Veruca Salt',
city: 'San Francisco',
type: 'Estate',
bedrooms: 15,
image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg'
}
}, {
type: 'rentals',
id: 2,
attributes: {
title: 'Urban Living',
owner: 'Mike Teavee',
city: 'Seattle',
type: 'Condo',
bedrooms: 1,
image: 'https://upload.wikimedia.org/wikipedia/commons/0/0e/Alfonso_13_Highrise_Tegucigalpa.jpg'
}
}, {
type: 'rentals',
id: 3,
attributes: {
title: 'Downtown Charm',
owner: 'Violet Beauregarde',
city: 'Portland',
type: 'Apartment',
bedrooms: 3,
image: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Building_-_Portland_Oregon.jpg'
}
}]
};
});
}
I get two messages in Chrome developer console:
Mirage: Your Ember app tried to GET 'http://localhost:4200/assets/vendor.js', but there was no route defined to handle this request. Define a route that matches this path in your mirage/config.js file. Did you forget to add your namespace?
and this warning:
WARNING: Encountered "data" in payload, but no model was found for model name "datum" (resolved model name using super-rentals#serializer:-rest:.modelNameFromPayloadKey("data"))
However it looks like the info was sucessfully retrieved as I see a:
Successful request: GET /rentals
Object {data: Array[3]}
which reflects the proper data. It just is breaking somewhere between that and the index.hbs and I am to novice to figure it out. I'm sure it's just a small misunderstanding on my part. Any help would be appreciated!
You have the wrong version of Ember Data installed. Also make sure you restart the server any time you install a dependency.
The error message that you are getting means that your application is using RESTAdapter (the default adapter for Ember Data 1.x). That is why it looks at the top-level data key and tries to singularize and find the related model.
You can update by following the instructions on the latest Ember CLI release. Or, you can npm install -g ember-cli#beta and start from scratch.
Related
I'm trying to learn Ember.js by building a web application using the framework for the front end and node.js for the backend as well as mongoDB as a database.
I am using/attempting to use the url to feed in a parameter id and then query on that id.
I am having trouble grabbing the information from my model. My query works fine when I am using findAll(). However, when I switch to find() or query() I can't retrieve any results.
All the documentation I have looked at use different syntax that I have tried but none have worked.
I would greatly appreciate any hint or input. Thank you.
app/router.js
Router.map(function() {
this.route('stock', { path: '/:stock_id' });
});
app/routes/stock.js
export default Ember.Route.extend({
model: function(params) {
this.store.query('stock', {filter:{id : params.stock_id}}).then(function(stock){return stock.get('firstObject')});
}
});
app/models/stock.js
export default DS.Model.extend({
Symbol: DS.attr('string'),
Name: DS.attr('string'),
LastSale: DS.attr('string'),
MarketCap: DS.attr('string'),
IPOyear: DS.attr('string'),
Industry: DS.attr('string')
});
app/serializers/stock.js
export default DS.RESTSerializer.extend({
primaryKey: '_id',
serializeId: function(id) {
return id.toString();
}
});
app/templates/stock.hbs
{{#each model as |item|}}
<h3>{{item.Name}}</h3>
{{/each}}
my nodejs server
app.get('/api/stocks/:id', function(req, res){
StockModel.findOne({'_id': req.params.id},function(err,docs){
console.log(docs.symbol);
if(err){
res.send({error:err});
}
else{
res.send({stock:docs});
}
});
});
Model hook should return the result, only then this will be set in model in corresponding controller through setupController method hook.
model: function(params) {
return this.store.query('stock', {filter:{id : params.stock_id}}).then(function(stock){return stock.get('firstObject')});
}
Update:
Your model field name should be camelCased
// app/models/stock.js
export default DS.Model.extend({
symbol: DS.attr('string'),
name: DS.attr('string'),
lastSale: DS.attr('string'),
marketCap: DS.attr('string'),
iPOyear: DS.attr('string'),
industry: DS.attr('string')
});
and ensure, your backend is accepting the filter and returning the required result in the below format,
"stocks": [
{
"id": 1,
"symbol": "foo",
"name": "foo",
"lastSale": "foo",
"marketCap": "foo",
"iPOyear": "foo",
"industry": "foo"
}]
You need to return the query from the model. Update your app/routes/stock.js to look like
export default Ember.Route.extend({
model(params) {
return this.store
.query('stock', {
filter: {
id: params.stock_id
}
})
.then(stock => stock.get('firstObject'))
}
})
Needless to say, new to Ember and just trying to get a proof of concept done. Already had some help with EmberCLI but this a new oddness for me.
/routes/index.js
export default Ember.Route.extend({
model() {
return this.store.findAll('skill');
}});
/models/skill.js
import Model from 'ember-data/model';
export default Model.extend({
name: DS.attr('string'),
desc: DS.attr('string'),
type: DS.attr('string')
});
/adapters/application.js
import DS from "ember-data";
export default DS.JSONAPIAdapter.extend({
namespace: 'v1',
host: 'http://edu-api.app:8000',
});
/serializers/application.js
import DS from "ember-data";
export default DS.JSONAPISerializer.extend({});
/templates/index.hbs
<h2>Skills</h2>
<ul>
{{#each model as |item|}}
<li>
<div>
<li>{{item}} {{item.id}} {{item.type}} {{item.name}} {{item.desc}}</li>
</div>
</li>
{{/each}}
</ul>
It seems that the id attr is available and correct, but yet all the other attrs are not being loaded from the json. If I copy/paste the json and manually set it in the model, it works as expected, so is there some filtering going on when coming from the model store or serializer?
The JSONAPISerializer and JSONAPIAdapter are not to for simple JSON/REST Backends but for a fully JSONAPI compatible Backend.
You say it works when you copy & paste and set it on the model, so probably you mean something like this:
this.store.createRecord('skill', {
id: '1',
name: 'foo',
desc: 'bar',
type: 'baz'
});
This will indeed work for a model creation but is not a JSONAPI compatible response! In JSONAPI you would have something like this (if the request should return multiple entities:
{
data: [{
id: '1',
attributes: {
name: 'foo',
desc: 'bar',
type: 'baz'
}
}]
}
So now you have two options:
Make your API JSONAPI compatible, or
use a different adapter & serializer.
The RESTSerializer/RESTAdapter are a simple default implementation that can handle a structure like this:
{
id: '1',
name: 'foo',
desc: 'bar',
type: 'baz'
}
Also they are highly customizable.
Checkout the official API for documentation.
I'm attempting to grab some data from my Rails API and display it in the template.
I'm very new to ember so the simpler the explanation the better and forgive me if this is a very stupid question.
The problem seems to be that the api data is not reaching the model correctly, it works when I have static fixture data but not for server data. The Get request to the server is going through and I'm getting a good response, so there must be something wrong with how the json is moved to the model.
My route in routes/external/jobs.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('job');
}
});
My job model in models/job.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
id: DS.attr('string')
});
I am expecting my API to return data in the form
{
"jobs": [
{
id: "jfdsa132113",
title: "developer",
type: "Job",
body: "lorem ipsum",
published_at: date,
tags: [
"some stuff",
"more stuff"
]
},
{
id: "fdsafd3432",
title: "designer",
type: "Job",
body: "lorem ipsum",
published_at: date,
tags: [
"some stuff",
"more stuff"
]
}
]
}
My router
Router.map(function () {
//index route
this.route('external', function () {
this.route('jobs');
this.route('support');
});
export default Router;
I think you have a misunderstanding with regards to DS.Models, you should take a look at the guides, specifically http://guides.emberjs.com/v2.1.0/models/finding-records/.
Assuming the route and template are properly set up, and that ApplicationAdapter is extending RESTAdapter/ActiveModel Adapter — see expected JSON formats here —, I believe the problem is in models/jobs.js, which is unnecessary.
Ember Data should make the right request to /jobs when you do store.findAll('job'). Try removing models/jobs.js and adapters/jobs.js, and doing the following:
// routes/external/jobs.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('job');
}
});
If this doesn't help try also posting your router and any errors you get.
Assuming your models are loading up fine from your API I think the issue is in your template.
According to the docs, you need to access the attributes of each model explicitly. http://guides.emberjs.com/v2.1.0/templates/displaying-a-list-of-items/
So rather than {{title}} use {{job.title}}.
{{#each model as |job|}}
<a href={{job.title}}>
<div class="info">
<div class="title">{{job.body}}</div>
</div>
</a>
{{/each}}
This fixed it
adding the file
serializers/job.js
with the lines
import DS from 'ember-data';
export default DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, {
});
I did not build the api and I noticed that some of the id's were underscored convention. More can be read about it here http://ember-doc.com/classes/DS.ActiveModelSerializer.html
I'm writing an ember-cli app. I have the following model:
// app/models/school.js
export default DS.Model.extend({
name: DS.attr('string', { defaultValue: '' })
});
It was generated using an ember generator like all my other models. It has a functioning unit test as well that tests for the default value of it's name attribute. All tests are green until another model belongs to school like this:
// app/models/professor.js
export default DS.Model.extend({
name: DS.attr('string', { defaultValue: '' }),
email: DS.attr('string', { defaultValue: '' }),
courses: DS.hasMany('course'),
posts: DS.hasMany('post'),
school: DS.belongsTo('school')
});
This test is totally green until I add the school attribute. It's even green with 'model:school' defined in the needs array of the moduleForModel helper:
// tests/unit/models/professor-test.js
// this is green w/o belongsTo('school') in the model
moduleForModel('professor', {
// Specify the other units that are required for this test.
needs: ['model:school', 'model:post', 'model:course']
});
The error I'm getting is:
Error: No model was found for 'school'
Here's the models directory
$ ls app/models/
course.js post.js professor.js school.js student.js
Why is it not finding my model?
You need to import the school model in your test:
import '[appName]/models/school';
I am using EmberJS 1.0.0 with Ember Data 1.0.0 beta and the latest version of the LocalStorage Adapter. When I try to load a record with a hasMany relationship from the store I get the follwing error:
ember-1.0.0.js (Line 394)
Assertion failed: You looked up the 'items' relationship on
'App.List:ember236:1' but some of the associated records were not
loaded. Either make sure they are all loaded together with the parent
record, or specify that the relationship is async (DS.attr({ async:
true }))
and ember-data.js (Line 2530)
TypeError: resolver is undefined
}).then(resolver.resolve, resolver.reject);
Quick demo app: http://jsbin.com/oKuPev/49 (watch the console)
<script type="text/x-handlebars">
List: {{name}}
<div>
{{#each items}}
{{id}} - {{name}}<br/>
{{/each}}
</div>
</script>
<script type="text/javascript">
window.App = Ember.Application.create({});
App.ApplicationAdapter = DS.LSAdapter.extend({});
var FIXTURES = {
'App.List': {
records: {
'1': { id: '1', name: 'The List', items: ['1','2'] }
}
},
'App.Item': {
records: {
'1': { id: '1', name: 'item 1', list: '1' },
'2': { id: '2', name: 'item 2', list: '1' }
}
}
}
// Store fixtures in localStorage
localStorage.setItem('DS.LSAdapter', JSON.stringify(FIXTURES));
// Models
App.List = DS.Model.extend({
name: DS.attr('string'),
items: DS.hasMany('item')
});
App.Item = DS.Model.extend({
name: DS.attr('string') ,
list: DS.belongsTo('list')
});
// Route
App.ApplicationRoute = Ember.Route.extend({
model: function() {
// Fails!!!
return this.store.find('list', 1);
}
});
</script>
I'm not sure if the problem is ember.js, ember-data.js or the LocalStorage adapter.
You need to define "items" on your model as being async in nature as ember makes separate requests for those models and then joins them together asynchronously.
App.List = DS.Model.extend({
name: DS.attr('string'),
items: DS.hasMany('item',{async:true})
});
This works if you define items as an asynchronous relationship.
item: DS.hasMany('item',{async:true})
Here's a working jsbin : http://jsbin.com/oKuPev/53/edit
Anyone else that stumbles on this thread b/c associations aren't loading (but w/o an error) notice the items: [1, 2] which associates the parent to child records.