I'm trying to add a custom property to an Ember Data Model. Specifically I want to add a property which defines the REST end point to use in an Ember Data Adapter I'm writing.
My Model is defined as such (with custom property 'endPoint'):
import DS from 'ember-data';
export default DS.Model.extend({
partner_id : DS.attr('string'),
partner_key : DS.attr('string'),
partner_name : DS.attr('string'),
created : DS.attr('string'),
status : DS.attr('string'),
type : DS.attr('string'),
endPoint : 'api_entry'
});
In my Adapter I'm trying to access the property as follows:
_buildURL: function (modelName, store, id, snapshot, requestType, query) {
var host, namespace, url;
var model = store.modelFor(modelName);
var endPoint = model.endPoint;
var endPoint2 = Ember.get(model, 'endPoint');
console.log(endPoint, endPoint2);
host = Ember.get(this, "host");
namespace = Ember.get(this, "namespace");
url = [];
if (host) {
url.push(host);
}
if (namespace) {
url.push(namespace);
}
url.push(modelName);
url = url.join("/");
if (!host) {
url = "/" + url;
}
return url;
},
In the console.log above, both endPoint and endPoint2 are undefined. I'm new to Ember and Javascript. What am I doing wrong? Is there a more 'Ember' way to do this? I don't want to use the actual REST endpoint names as my model names as they do not adhere to Ember model naming conventions.
Help much appreciated.
Your buildURL function dealing with the model class as opposed to the model instance. You need to add the property to the class:
var model = DS.Model.extend({
partner_id : DS.attr('string'),
partner_key : DS.attr('string'),
partner_name : DS.attr('string'),
created : DS.attr('string'),
status : DS.attr('string'),
type : DS.attr('string')
});
model.reopenClass({
endPoint : 'api_entry'
});
export default model;
Related
Version: Ember 2.11
I am trying to use Ember data model to load the data from REST API but it is failing with error message as
"ember.debug.js:17634 TypeError: Cannot read property 'type' of undefined
at Class._pushInternalModel (store.js:2005)
Here is more details:
1. REST API response is:
{
"sfresults":[
{
"url":"https://google.com/1",
"title":"Titl1",
"description":"Description1",
"type":"KB",
"lastModifiedDate":"12/23/16",
"viewScore":"86.12006476690622",
"caseNumber":"case1",
"id":"cd4ac3e8-c3ac-4be5-ad11-c62a85ddf289"
},
{
"url":"https://google.com/2",
"title":"Titl2",
"description":"Description2",
"type":"KB",
"lastModifiedDate":"12/23/16",
"viewScore":"86.12006476690622",
"caseNumber":"case2",
"id":"cd4ac3e8-c3ac-4be5-ad11-c62a85ddf289"
},
],
"message":"SUCCESS",
"id":"3bd116c7-db63-4277-8ace-a7ea846a04ee"
}
Controller code:
let sfdata = this.store.query('sfresult',{ 'searchText': inputSearchText, 'searchType' : 'SF' } );
this.set('sfresult', sfdata);
My Models
sfresult.js
import DS from 'ember-data';
export default DS.Model.extend({
sfresults: DS.hasMany('sfresults'),
message: DS.attr('string')
});
sfresults.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
caseNumber: DS.attr('string'),
lastModifiedDate: DS.attr('string'),
type: DS.attr('string'),
url: DS.attr('string'),
searchText: DS.attr('string'),
messageId: DS.attr('string')
});
export default DS.RESTAdapter.extend({
host: 'http://localhost:8080',
namespace: 'server'
});
Then i wanted to iterate sfresult and show it in the UI. but here as soon as API call response comes back it is unable to load into ember data models. fails with above error.
Note: if i try without hasMany model it works fine - meaning json response having array of elements and using only sfresults model without sfresult, but wanted to get the message in the JSON response to act accordingly - please ignore this statement if it is confusing a bit.
Any help would be greatly appreciated.
You'll need to make sure you are using the RESTSerializer. By default the serializer in a new app is JSONAPISerializer, which throws the error that you are seeing.
Im using Ember Data and Ember CLI. I have a simple one-to-many relationship between two models. I'm trying to create a computed property that returns the number of items that are attached to the current model.
models/account.js
// Account model
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
notes: DS.hasMany('note', { async: true })
});
models/note.js
// Note model
import DS from 'ember-data';
export default DS.Model.extend({
body: DS.attr('string'),
date: DS.attr('number'), // unix timestamp
account: DS.belongsTo('account', { async: true })
});
controllers/account/index.js
// account/index controller
import Ember from 'ember';
export default Ember.ObjectController.extend({
oldNotesCount: function() {
var notes = this.get('notes');
console.log('=-=', notes.length); // undefined *****
return notes.length;
}.property('notes.#each')
});
How come notes.length is undefined?
I've simplified this example... I can't use {{notes.length}} in my situation as there will be more calculations going on—this is just the first step.
You marked notes association as async so this.get('notes') returns a promise. Promises do not have length property hence getting undefined.
To get data in an async association call then on returned promise with a function as argument. Association data will be passed to that function as first argument.
export default Ember.ObjectController.extend({
oldNotesCount: function() {
var _this = this;
this.get('notes').then(function(notes){
_this.set('oldNotesCount', notes.get('length');
});
return null;
}.property('notes.#each')
});
I'm pretty new to Ember.js and am building an app to pick up some Ember chops. I wanted to use a computed property in one of my models as a route but it seems something isn't working correctly. I'm using FIXTURES by the way.
What I'm trying to achieve is /peeps/john-smith instead of /peeps/1
I've got my model setup like this:
App.Peep = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
slug: function(){
this.get('firstName').toLowerCase() + '-' + this.get('lastName').toLowerCase();
}.property('firstName', 'lastName')
});
My router setup is like this:
App.Router.map(function(){
this.resource('peep', { path: '/peeps/:peep_slug'});
});
App.PeepRoute = Ember.Route.extend({
model: function(params){
return this.store.find('peep', params.peep_slug);
},
serialize: function(model){
return { peep_slug: model.get('slug') };
}
});
When I navigate to /peeps/john-smith in the browser, I get this warning in my console You made a request for a peep with id john-smith.
Is there something I'm missing?
By default it searches by id param, so you could either change the adapter to make it search by slug or try to add id as Ember.computed.alias('slug').
I am new to EmberJs and I don't clearly understand in Ember's Adapter .I just try the ember adapter in my App.Js like that and I got this error ( Assertion failed: You tried to set adapter property to an instance of DS.Adapter, where it should be a name or a factory ) . My ember's code in App.js is :
//Store
App.Adapter = DS.RESTAdapter.extend();
App.Store = DS.Store.extend({
revision: 12,
adapter: App.Adapter.create()
});
//Models
App.Product = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
price: DS.attr('number')
});
// Products Route
App.ProductsRoute = Ember.Route.extend({
model: (function() {
return this.store.find('Product');
})
});
return App;
I think you misunderstand the way you setup and configure adapters.
//
// Application-wide adapter, everything will use this unless you override it
//
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'https://api.example.com'
});
//
// Product model, will use ApplicationAdapter
//
App.Product = DS.Model.extend({
name : DS.attr('string'),
description : DS.attr('string'),
price : DS.attr('number')
});
//
// Invoice model, will use fixtures, so specify a different adapter
//
App.InvoiceAdapter = DS.FixtureAdapter.extend({ /* options */ });
App.Invoice = DS.Model.extend({
name : DS.attr('string'),
amount : DS.attr('number')
});
//
// Routes, these should work as expected
//
App.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.id);
}
});
App.ProductsRoute = Ember.Route.extend({
model: function() {
return this.store.find('product');
}
});
App.InvoicesRoute = Ember.Route.extend({
model: function() {
return this.store.find('invoice');
}
});
return App;
Ember will know which models/routes/etc to use based on their names - see http://emberjs.com/guides/concepts/naming-conventions/ for the details.
Define the store in this way
App.Store = DS.Store.extend({
revision: 12,
adapter: App.Adapter
});
Without the create().
The main use of the adapter is to do the serialization and deserailzation of the data according to some conventions like constructing the url to post or get data from and then constructing the actual objects from the response. The Default adapter used by ember data models is the Rest adapter.
see
http://emberjs.com/guides/models/the-rest-adapter/
for more details
To use a different adapter other than the rest adapter you can specify its name like
Storm.Store = DS.Store.extend({
adapter: '_ams',
});
Try:
App.ApplicationAdapter = DS.RESTAdapter.extend();
This works for me
So, I'm trying to build routes in my Ember application dynamically with data from an API endpoint, /categories, with Ember Data. In order to do this, I'm adding a didLoad method to my model, which is called by the controller and set to a property of that controller. I map the route to my router, and all that works fine. The real trouble starts when I try to set up a controller with a content property set by data from the server retrieved by findQuery.
This is the error:
TypeError {} "Object /categories/548/feeds has no method 'eachRelationship'"
This is the code:
window.categoryRoutes = [];
App.Categories = DS.Model.extend({
CATEGORYAFFINITY: DS.attr('boolean'),
CATEGORYID: DS.attr('number'),
CATEGORYNAME: DS.attr('string'),
CATEGORYLINK: function () {
var safeUrl = urlsafe(this.get('CATEGORYNAME'));
categoryRoutes.push(safeUrl);
return safeUrl;
}.property('CATEGORYNAME'),
didLoad: function () {
var categoryLink = this.get('CATEGORYLINK');
var categoryId = this.get('CATEGORYID');
App.Router.map(function () {
this.resource(categoryLink, function () {
// some routes
});
});
App[Ember.String.classify(categoryLink) + 'Route'] = Ember.Route.extend({
setupController: function(controller, model) {
// source of error
this.controllerFor(categoryLink).set(
'content',
this.store.findQuery('/categories/' + categoryId + '/feeds', {
appid: 'abc123def456',
lat: 39.75,
long: -105
})
);
}
});
}
});
Any 'halp' is appreciated!
Also, if I'm doing this completely wrong, and there's a more Ember-like way to do this, I'd like to know.
I figured this out. I got this error because I was passing in a string instead of a real 'type' from the App.Helpers object to an extract method in some custom RESTAdapter code I had overridden.
The solution is to pass in the corresponding model helper in App.Helpers using my custom type name.
Something like this in the overridden RESTAdapter.serializer.extractMany method:
var reference = this.extractRecordRepresentation(loader, App.Helpers[root], objects[i]);