I have a rest adapter:
App.Adapter = DS.RESTAdapter.extend({
bulkCommit: true,
url: 'http://10.0.0.106/bank',
ajax: function (url, type, hash) {
hash.url = url;
hash.type = type;
hash.context = this;
hash.headers = {
'Session-Token': '65f1b8925f8eb2780730a4a2993693699e9a98dad5d2995452c24758d2c59706'
};
if (hash.data && type !== 'GET') {
hash.data = JSON.stringify(hash.data);
}
$.ajax(hash);
}
});
App.Store = DS.Store.extend({
revision: 13,
adapter: App.Adapter
});
A route :
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
A model :
App.User = DS.Model.extend({
firstname: DS.attr("string"),
lastname: DS.attr("string"),
email: DS.attr("string"),
user_id: DS.attr("string"),
role: DS.attr("string"),
phone: DS.attr("string")
});
The request work well and give me that :
{
"error": null,
"payload": {
"bank_users": [{
"firstname": "Ugo",
"lastname": "Doe",
"email": "ugo#doe.com",
"user_id": 1,
"role": "BANK_USER",
"phone": null
}, {
"firstname": "Ugo Clone",
"lastname": "Doe",
"email": "ugo-clone#doe.com",
"user_id": 2,
"role": "BANK_USER",
"phone": null
}
]
}
}
In my template; I've just that :
<h2>this is users !!</h2>
{{#each model}}
{{firstname}}
{{/each}}
And the error is : Uncaught TypeError: Cannot call method 'then' of undefined
This happen in ember-data, here :
findAll: function(store, type, since) {
var root, adapter;
root = this.rootForType(type);
adapter = this;
return this.ajax(this.buildURL(root), "GET",{
data: this.sinceQuery(since)
}).then(function(json) {
adapter.didFindAll(store, type, json);
}).then(null, rejectionHandler);
}
I appears that since is undefined ; What I am doing wrong ? :)
I guess, since you are overriding the RESTAdapter ajax method should the last line
$.ajax(hash);
not rather be?
return $.ajax(hash);
Hope it helps.
Related
new here to ember, and very much trying to learn - and learn where I'm going wrong.
I'm being fed json that looks like this:
"status": "success",
"data": {
"groups": [
{
"id": 2,
"name": "Test1234",
"kind": "Happy",
"parent_group_id": 1,
"children_count": {
"boy": 10,
"girl": 4,
"pets": 2
},
"is_top_level": true
},
The path to get this info would be /api/groups/top.
I have a (what I believe would be) simple app.js:
App = Ember.Application.create();
App.Router.map(function() {
this.route("login", {path: "/"});
this.route("groups");
this.resource('about');
});
App.GroupsRoute = Ember.Route.extend({
model: function() {
return App.Group.find('top');
}
});
App.LoginController = Ember.Controller.extend({
actions: {
login: function(username, password){
jQuery.ajax({
url: "/api/auth",
type: 'post',
data: JSON.stringify( { "username": "user", "password": "pass" } ),
contentType: 'application/json',
dataType: 'json',
async: false,
success: function(result) {
if (result.status === 'success') {
user = result.data.user;
App.User.id = user.id;
App.User.name = user.name;
App.User.isAuthenticated = true;
App.User.displayUnits = "F";
} else {
//debugger;
throw "The! username and/or password you have entered is incorrect, please try again ";
return false;
}
},
error: function(xhr, status, errorOut) {
throw "The? username and/or password you have entered is incorrect, please try again ";
return false;
}
});
if (App.User.isAuthenticated)
this.transitionToRoute('groups');
}}
});
App.RESTAdapter = RL.RESTAdapter.create({
host: 'http://localhost:3000',
namespace: 'api/'
});
App.Client = RL.Client.create({
adapter: App.RESTAdapter
});
App.User = RL.Model.extend({
username: RL.attr('string'),
id: RL.attr('string'),
isAuthenticated: RL.attr('boolean'),
});
App.Group = RL.Model.extend({
id: RL.attr('string'),
name: RL.attr('string'),
kind: RL.attr('string')
});
App.RESTAdapter = RL.RESTAdapter.create({
defaultData: { cookie: "data"}
});
I'm trying to display each "group" in my template. For example {{#each groups}} {{name}} {{/each}}, but no luck - I can see the JSON data in the response in inspector, and no errors - but still, nothing coming trough.
Any help?
Thanks!
Ptep
edit - template:
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" id="groups">
<h3>Hello,
{{#each groups}}
{{name}}! <br>
{{kind}}, {{id}}
{{/each}}
</h3>
</script>
The array itself would be the context of your template, so you would either use
{{#each}}{{name}}{{/each}}
or
{{#each model}}{{name}}{{/each}}
or
{{#each controller}}{{name}}{{/each}}
or
{{#each item in controller}}{{item.name}}{{/each}}
When I save a User all current dirty Users are commited. What do I have to change that a save only commits the transaction for that specific User?
app.js
App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 12,
adapter: 'DS.FixtureAdapter'
})
App.Router.map(function() {
this.resource('users', function() {
this.resource('user', { path: ':user_id' })
})
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UserController = Ember.ObjectController.extend({
startEditing: function() {
this.transaction = this.get('store').transaction();
this.transaction.add(this.get('content'));
},
save: function( user ) {
user.transaction.commit();
}
})
App.User = DS.Model.extend({
lastName: DS.attr('string')
})
App.User.FIXTURES = [{
id: 1,
lastName: "Clinton"
}, {
id: 2,
lastName: "Obama"
}]
My guess is that startEditing is never called, otherwise this would probably be ok.
The other option is that you save multiple times the record. Once a record is saved, it is moved back to the store's default transaction. Any subsequential call to save would actually commit the store's transaction.
I'm trying to render mediaitems in my post template, but I'm getting this nasty console error:
Uncaught TypeError: Object photo has no method '_create'
These are my models & fixture data:
/**************************
* Models
**************************/
App.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.FixtureAdapter'
});
App.Mediaitem = DS.Model.extend({
type: DS.attr('string'),
url: DS.attr('string'),
post: DS.belongsTo('App.Post')
});
App.Post = DS.Model.extend({
type: DS.attr('string'),
title: DS.attr('string'),
summary: DS.attr('string'),
body: DS.attr('string'),
date: DS.attr('date'),
mediaitems: DS.hasMany('App.Mediaitem', {embedded:true})
});
App.Post.FIXTURES = [
{
id:"post-one",
type:"news",
title:"First Post",
summary:"Ipsum Lorem",
date:"2013-02-07T16:44:57",
mediaitems:[{
id:593,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
},
{
id:789,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
}]
},
{
id:"post-two",
type:"gallery",
title:"Second Post",
summary:"Lorem ipsum",
date:"2013-02-07T16:44:57",
mediaitems:[{
id:342,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
},
{
id:231,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
}]
}
];
This is my template code:
<script type="text/x-handlebars" data-template-name="post">
<div class="detail">
{{#linkTo posts}}close{{/linkTo}}<br/>
<h2>{{id}} - {{title}}</h2>
<br/>
{{#each mediaitem in mediaitems}}
print something
{{/each}}
</div>
</script>
Can someone help me out?
The FIXTURE adapter does not support embedded relationships, at least not in rev 11.
You need each model to have its own FIXTURE definition with the record and the relationships to have the id/s of the proper child/parent.
App.Post.FIXTURES = [
{
id:"post-one",
type:"news",
title:"First Post",
summary:"Ipsum Lorem",
date:"2013-02-07T16:44:57",
mediaitems:['593','789']
},
{
id:"post-two",
type:"gallery",
title:"Second Post",
summary:"Lorem ipsum",
date:"2013-02-07T16:44:57",
mediaitems:['342','231']
}];
App.Mediaitems.FIXTURES = [{
id:342,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
},
{
id:231,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
},
{
id:593,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
},
{
id:789,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
}];
I get this assertion when run the code below:
Emptying a view in the inBuffer state is not allowed and should not
happen under normal circumstances. Most likely there is a bug in your
application. This may be due to excessive property change
notifications.
Link to demo:
http://plnkr.co/edit/s3bUw4JFrJvsL690QUMi
var App = Ember.Application.create({
Store: DS.Store.extend({
revision: 4,
adapter: DS.FixtureAdapter.create()
}),
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router){
var person;
person = App.Person.find(657);
person.addObserver("isLoaded", function() {
return router.get('router.applicationController').connectOutlet("things", person.get("things"));
});
}
})
})
}),
ApplicationController: Em.Controller.extend(),
ApplicationView: Em.View.extend({
template: Em.Handlebars.compile("{{outlet}}")
}),
ThingsController: Em.ArrayController.extend({
thingTypes: (function() {
return App.ThingType.find();
}).property()
}),
ThingsView: Em.View.extend({
template: Em.Handlebars.compile([
'{{#each controller.thingTypes}}',
'{{this.name}}',
'{{/each}}',
'{{#each controller.content}}',
'{{this.title}}',
'{{/each}}'].join(""))
}),
//MODELS
Person: DS.Model.extend({
things: DS.hasMany('App.Thing', {
embedded: true
})
}),
Thing: DS.Model.extend({
description: DS.attr('string'),
thingType: DS.belongsTo("App.ThingType", {
embedded: true
}),
title: (function() {
return this.get("thingType.name");
}).property("description")
}),
ThingType: DS.Model.extend({
name: DS.attr("string")
})
});
App.Person.FIXTURES = [
{
id: 657,
things: [
{
id: 1,
description: "Some text",
thing_type: {
id: 1,
name: "type 1"
}
}, {
id: 2,
description: "Some text",
thing_type: {
id: 2,
name: "type 2"
}
}
]
}
];
App.ThingType.FIXTURES = [
{
id: 1,
name: "type 1"
}, {
id: 2,
name: "type 2"
}, {
id: 3,
name: "type 3"
}
];
Why is this happening?
I was having the same error while trying to load a list of dropdown values from fixtures. What resolved it was overriding queryFixtures on the fixture adapter:
App.FixtureAdapter = DS.FixtureAdapter.extend
latency: 200
queryFixtures: (records, query, type) ->
records.filter (record) ->
for key of query
continue unless query.hasOwnProperty(key)
value = query[key]
return false if record[key] isnt value
true
I probably wouldn't have figured it out had I not set the latency first. Then the error was a bit more descriptive.
a bit late I guess... but I got it to work here:
http://plnkr.co/edit/hDCT4Qy1h5aE6GjM76qp
Didn't change the logic but where its called
I modified your router like this:
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router) {
var person;
router.set('router.applicationController.currentPerson', App.Person.find(657));
}
})
})
})
And created an ApplicationController:
ApplicationController: Em.Controller.extend({
currentPerson: null,
currentPersonLoaded: function() {
this.connectOutlet("things", this.get("currentPerson.things"));
}.observes("currentPerson.isLoaded"),
})
I dont know if this is the output you wished but the bug vanished!
I have these two resources:
App.Users = DS.Model.extend({
first_name: DS.attr('string'),
last_name: DS.attr('string'),
email: DS.attr('string'),
userprofile: DS.belongsTo('App.Userprofiles', {embedded:true}),
fullName: function() {
return this.get('first_name') + ' ' + this.get('last_name');
}.property('first_name', 'last_name'),
didLoad: function() {
console.log('Developer model loaded', this);
}
});
App.Userprofiles = DS.Model.extend({
company: DS.attr('string'),
user: DS.belongsTo('App.Developers'),
didLoad: function() {
console.log('Developer Profile model loaded', this);
}
})
These are my view and controller:
App.UserInfoController = Ember.ObjectController.extend({
content: App.store.find(App.Users, 1),
}).create();
App.UserInfoView = Ember.View.extend({
controller: App.UserInfoController,
contentBinding: 'controller.content'
});
This a sample response for a user from my API
{
"email": "foo#gmail.com",
"first_name": "George",
"id": "1",
"last_name": "Eracleous",
"resource_uri": "/api/v1/users/1/",
"userprofile": {
"company": "bar",
"id": "1",
"resource_uri": "/api/v1/userprofiles/1/",
"user": "/api/v1/users/1/"
}
}
The user object is loaded correctly but when I try to do get("userprofile") I get null. Does anybody know what I am doing wrong?
In order to load embedded related objects you have to configure the serializer used by the adapter, by calling its 'map' function. The only way I know to do this is by subclassing the serializer and add an 'init' function to it, where you make the necessary calls to map. For every embedded relationship of every model class you will have to do a call to 'map'. This applies to to-one and to-many relationships. Make sure to configure your adapter to use this serializer.
For an example see my answer to a previous question.
You can also check out this example online.
As mentioned in the comment, instead of subclassing the serializer and calling its map() function in the initialiser you can directly call map() on the adapter class. As an example, here is an excerpt of my own code doing this.
WO.RESTAdapter.map(App.Category, {
resourceTypes: {
embedded: 'load'
}
});
WO.RESTAdapter.map(App.Resource, {
resourceType: {
embedded: 'load'
}
});
WO.RESTAdapter.map(App.Reservation, {
resource: {
embedded: 'load'
},
user: {
embedded: 'load'
}
});
App.serializer = App.WOSerializer.create();
App.store = DS.Store.create({
revision: 10,
adapter: WO.RESTAdapter.create({
namespace: "cgi-bin/WebObjects/Reserve.woa/ra",
serializer: App.serializer
}),
serializer: App.serializer,
adapterForType: function(type){
return this.get('adapter');
}
});