Trying to get json data with Ember - javascript

Here what my json data look like:
[{"id":1,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"Lorem ipsum lorem ipsum lorem ipsum"}]
Here's my Ember code:
window.Messages = Ember.Application.create();
Messages.Store = DS.Store.extend({
revision: 11
});
Messages.MessagesRoute = Ember.Route.extend({
setupControllers: function(controller) {
controller.set('content', Messages.Message.find());
}
});
Messages.Message = DS.Model.extend({
msgbody: DS.attr('string')
});
Messages.MessagesController = Ember.ArrayController.extend({
content: []
});
The thing is my json data live in /app_dev.php/messages not in /messages/ ...
I am just trying to do just a successful get request but I can't manage... Could you tell what I am doing wrong so I can get some grasp of the Ember syntax?
EDIT Thanks for your answers.Just to inform that after lots of effort to make something trivial, I tried Angular and it seems to do the job better,faster and easier. So I'm switching frameworks.

You'll want to use the namespace option on the adapter. This can be specified as followed and then when you create the store use the MyApp adapter.
MyApp.Adapter = DS.RESTAdapter.extend({
namespace: 'app_dev.php'
});

I think that it is better to specify file names via the url option:
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.RESTAdapter.create({
url: "/app_dev.php"
})
});
The structure of your JSON should be as follows:
{
messages: [
{"id":1,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"ipsum "},
{"id":2,"iam":1,"youare":2,"lat":50.8275853,"lng":4.3809764,"msgbody":"Lorem "}
]
}
See ember guide for further reference.

Ember requires that you use what they call "type keys" in order to successfully read JSON, in other words you need to put the name of a model prior to the object itself for Ember to recognize that is of that type.
In my case, I had made a Java/Spring Backend and did not want to add this to my objects, to get around this in ember you can create a Serializer file, documentation for Ember Serializers, specifically the RESTSerializer can be found here.
To add the typeKey to incoming JSON overide the normalizePayload hook. Here is an example of how I did that:
normalizePayload: function(type, payload) {
var json = {};
json[type.typeKey] = payload;
return json;
}
If you hadn't put your typeKey's on the JSON on the way out, you'll probably experience similar problems when you PUT or POST data, so you will probably need to overload the serializeIntoHash hook to remove the typeKey's on outgoing data. Here is an example of what worked for me on that:
serializeIntoHash: function(hash, type, record, options){
Ember.merge(hash, this.serialize(record, options));
}
Hope that helps! I see you are switching to Angular (Great decision, I prefer Angular 100x over Ember but my work requires I use Ember currently, so I'm fighting through it.) But hopefully this can help someone else who is having similar issues and either wants or is forced to use Ember.

Related

How I do a search with POST in Ember 2 and Ember Data

I'm make a search for a application in Ember 2 which my backend only accept a POST for this search, so Im trying send data through customize createRecord, but the behavior is completely different from I'm expected, two points I believe be a problem.
After several console.log(), I see my actions don't work, even action setted in route.
Inside Ember Inspector the route for this search haven't a model related
Anyone have a hint about why my route don't have a model related, follow the model declaration for this specific route.
model() {
return {
data: this.store.findAll('booking'),
booking: {}
};
}
PS: I edited the title, to be more clear about I need.
I believe you need to use Ember.RSVP.hash for that:
model() {
return Ember.RSVP.hash({
data: this.store.findAll('booking'),
booking: {}
});
}

Searching Ember data async hasMany ids without loading all the id records

I am trying to search through several thousand records for a particular record. I have loaded a User model and it has several thousand Shipments that are async. In other words I have the serializer send down shipment_ids with the user model.
App.User = DS.Model.extend({
shipments: DS.hasMany('shipment', { async: true })
});
I want to search through all those ids to see if a particular record's id is among them. However I don't want to go to the api and load each and every single record. I just want to be able to search through the shipment_ids.
I have a jsbin that showcases it loading all the records. How do I change this so it doesn't make any api calls for a shipment and still finds the specific record?
Instead of doing
this.get('shipments').any(function(shipment){
return shipment.get('id') === "10124";
there has to be a way to go through only the ids, no?
Thanks!
The solution described in "Get belongsTo ID without fetching record"
seems to work as of Ember Data 1.0.0-beta.10. Briefly, you can do the following to access the underlying
modelInstance.get('data.belongsToRelation.id');
Presumably you can also do this (though I have not tested it):
modelInstance.get('data.hasManyRelation');
Original Answer (DO NOT USE):
I have accomplished this on a belongsTo by adding a second model field for the id. My example:
App.User = DS.Model.extend({
group: DS.belongsTo('group', { async: true }),
groupId: DS.attr('number')
});
So maybe you can do this?
App.User = DS.Model.extend({
shipments: DS.hasMany('shipment', { async: true }),
shipmentIds: DS.attr('array')
});
You will need to add an array transform in app/transforms/array.js (assuming you use ember-cli)
import DS from 'ember-data';
var ArrayTransform = DS.Transform.extend({
deserialize: function(serialized) {
return serialized;
},
serialize: function(deserialized) {
return deserialized;
}
});
export default ArrayTransform;
Let me know if it works as I probably will need to something similar in my app soon.
This hack is very smelly but it's the only way I have found. And it is to search with _data
this.get('content._data.shipments').any(function(shipment){
return shipment.get('id') === "10124";
});
It won't make any api calls. But there has to be a more acceptable method that won't be prone to breakage when updating Ember.
Here is an updated jsbin to show this. Does anyone have a better solution?
Thanks!
Since Ember Data 2.3 you can use this code:
// get all ids without triggering a request
var commentIds = post.hasMany('comments').ids();
See http://emberjs.com/blog/2016/01/12/ember-data-2-3-released.html for details.

Ember Data not serializing record id on save(), resulting in PUT with no id?

I have a route that creates a new record like so:
App.ServicesNewRoute = Ember.Route.extend({
model : function() {
return this.store.createRecord('service');
},
setupController: function(controller, model) {
controller.set('model', model);
},
});
Then I bind that model's properties to the route's template using {{input type="text" value=model.serviceId ... }} which works great, the model gets populated as I fill up the form.
Then I save record:
App.ServicesNewController = Ember.ObjectController.extend({
actions : {
saveService : function() {
this.get('model').save(); // => POST to '/services'
}
}
});
Which works too.
Then I click the save button again, now the save method does a PUT as expected since the model has an id set (id: 102):
But then when I look at the PUT request in Dev Tools, I see that the id attribute was not serialized:
As a result, a new instance is created in the backend instead of updating the existing one.
Please ignore the serviceId property, it is just a regular string property unrelated to the record id which should be named just id.
I don't know why the id is not being serialized... I cannot define an id property on the model of course since Ember Data will not allow it, it is implicit. So I don't know what I am missing...
Any help is greatly appreciated!
The base JSONSerializer in Ember-Data only includes id in the payload when creating records. See DS.JSONAdapter.serialize docs.
The URL the RestAdapter generates for PUTting the update includes the ID in the path. In your case I believe it would be: PUT '/services/102'.
You can either extract it from the path in your backend service. Or you should be able to override the behavior of your serializer to add the id like this:
App.ServiceSerializer = DS.JSONSerializer.extend({
serialize: function(record, options) {
var json = this._super.apply(this, arguments); // Get default serialization
json.id = record.id; // tack on the id
return json;
}
});
There's plenty of additional info on serialization customization in the docs.
Hope that helps!
Initially I used ronco's answer and it worked well.
But when I looked at ember data's source code I noticed that this option is supported natively. You just need to pass the includeId option to the serializer.
Example code:
App.ApplicationSerializer = DS.RESTSerializer.extend({
serialize: function(record, options) {
options = options ? options : {}; // handle the case where options is undefined
options.includeId = true;
return this._super.apply(this, [record, options]); // Call the parent serializer
}
});
This will also handle custom primary key definitions nicely.
Well, as far as I know it's a sync issue. After first request you do the post request and then, it has been saved in the server, when you click next time the store haven't got enough time to refresh itself. I've got similar issue when I've created something and immediately after that (without any transition or actions) I've tried to delete it - the error appears, in your case there's a little bit another story but with the same source. I think the solution is to refresh state after promise resolving.

Ember without Ember Data

Ember data is still not at version 1.0 and thus I decided to use Ember without Data models.
I have my own models, and those are created by the route model function.
However maintaining state between the frontend objects and the backend objects is a nightmare.
Especially when one route uses another routes models.
How can this be achieved, should I write my own store and model find method?
Should I use Ember Data (even though it's not at version 1.0 ?) perhaps an ETA on Ember Data 1.0 ?
write code to update the models on the frontend each time I change a model?
Another method?
Is what I'm doing best practices or should I be doing it differently?
My gut feeling is that without using Ember Data I should write my own store. I'd love to get feedback from some of you guys.
Example of a model:
App.Person = Ember.Object.extend(App.Serializable,Em.Copyable,{
user_email : null //used in routing dynamic segements and as old email when making changes to email
,first_name: null
, last_name: null
, fullname : function () {
return this.first_name + ' ' + this.last_name;
}.property('first_name','last_name').cacheable()
};
App.Person.reopenClass({
createRecord: function(data) {
return App.Person.create({
user_email : data.email
, first_name: data.first_name
, last_name : data.last_name
}});
Example of how I load the class models:
App.UsersRoute = App.AuthenticatedRoute.extend( {
model : function () {
return new Ember.RSVP.Promise(function(resolve, reject) {
$.getJSON('/users').then(function(usersData) {
var userObjects = [];
usersData.forEach(function (data) {
userObjects.pushObject(App.Person.createRecord(data));
});
resolve( userObjects);
},function(error) {
reject(error);
});
})
},
Subroutes use the model:
App.UsersAvailableRoute = App.AuthenticatedRoute.extend( {
model : function () {
return {
allUsers : Ember.ArrayController.create({
content : this.modelFor('users').filter( function (user) {
return user.availablity === 100
}),
Example of how I update the model in a controller:
App.UsersAvailableController = Ember.ArrayController.extend({
needs : ['users']
,applyPersonAssign : function (person,need,project) {
need.set('allocated',person);
var updateObject = Ember.copy(project,true);
if (Ember.isEmpty(need.get('inProject'))) {
updateObject.projectNeeds.pushObject(need);
}
return $.ajax({
url: '/projects/' + updateObject.get('codename'),
"type": "PUT",
"dataType": "json",
data: updateObject.serialize()
})
You don't necessarily need to recreate the Ember Data store. Ember works just fine with POJOs, you can also wrap your POJOs in an Ember Object to give you some fun built in features.
That being said creating a custom adapter which caches results could be convenient.
Here's an example where I create an adapter that supports caching. You can slowly build on the concept for all of the basic things you need.
App.FooAdapter = Ember.Object.extend({
cache:{},
find: function(id){
var self = this,
record;
if(record = this.cache[id]){
return Ember.RSVP.cast(record);
}
else
{
return new Ember.RSVP.Promise(function(resolve){
resolve($.getJSON('http://www.foolandia.com/foooo/' + id));
}).then(function(result){
record = self.cache[id] = App.Foo.create(result);
return record;
});
}
}
});
In the examples below, I use the container to register the adapter on all of my routes/controllers so I had lazy easy access to it.
http://emberjs.jsbin.com/OxIDiVU/742/edit
If you always want it to be a promise:
http://emberjs.jsbin.com/OxIDiVU/740/edit
Reusability
The example above may make it look like you'd have to do a ton of work, but don't forget, Ember is super reusable, take advantage of the magic.
App.MyRestAdapter = Em.Object.extend({
type: undefined,
find: function(id){
$.getJSON('http://www.foolandia.com/' + this.get('type') + '/' + id
}
});
App.FooAdapter = App.MyRestAdapter.extend({
type: 'foo' // this would create calls to: http://www.foolandia.com/foo/1
});
App.BarAdapter = App.MyRestAdapter.extend({
type: 'bar' // this would create calls to: http://www.foolandia.com/bar/1
});
This is the basic idea of what Ember Data/Ember Model is. They've tried to create a ton of defaults and built in coolness, but sometimes it's overkill, especially if you are just consuming data and not doing CRUD.
Example: http://emberjs.jsbin.com/OxIDiVU/744/edit
Also you can read this (says the same stuff):
How do you create a custom adapter for ember.js?
Where I work we are using Ember Data and Ember CLI despite them being rather unstable. So far Ember Data hasn't caused too much pain and suffering here. The store is pretty easy to understand, and the documentation on Ember for that facet of the framework is rather good. The one issue that I have been having has to do with dynamically sorting models, and as I modify the content of them, they reshuffle according to the changes I make, and somewhere along the road some really weird stuff happens, not sure if that's Ember Data's fault though.
In short, we've found some success using Ember Data, and can't complain about it if that's the route you wish to go.
If you're familiar with Ruby, Rails is a great solution for a backend.
The ember community has support for rails with the ember-rails gem which lets you use rails as a means to serve JSON.
Getting started
Add the gem to your application Gemfile:
gem 'ember-rails'
gem 'ember-source', '~> 1.9.0' # or the version you need
Run bundle install
Next, generate the application structure:
rails generate ember:bootstrap
Restart your server (if it's running)
Building a new project from scratch
Rails supports the ability to build projects from a template source ruby file.
To build an Ember centric Rails project you can simply type the following into your command line:
rails new my_app -m http://emberjs.com/edge_template.rb
To install the latest builds of ember and ember-data. It should be noted that the
examples in the getting started guide
have been designed to use the released version of ember:
rails generate ember:install
Then all you need to do is render json in your controllers, like this
class ProjectsController < ApplicationController
def index
respond_to do |format|
format.json { render json: Project.all }
end
end
def show
respond_to do |format|
format.json { render json: Project.where(name: params[:name])}
end
end
end
make sure to update your serializers
class ProjectSerializer < ApplicationSerializer
attributes :id, :name, :description, :imgUrl, :deployUrl
end
setup your routes
EmberRailsBlog.ProjectsRoute = Ember.Route.extend({
model: function(){
return this.store.find('project');
}
});
and finally your model
var attr = DS.attr;
EmberRailsBlog.Project = DS.Model.extend({
name: attr(),
description: attr(),
imgUrl: attr(),
deployUrl: attr()
});

Ember.js createRecord possibly not firing

I have an application that saves a user's search criteria in localStorage, where each saved search is represented as an instance of an Ember.js model:
Checklist.SavedSearch = DS.Model.extend({
id: DS.attr('string'),
filters: DS.attr('string')
});
When the "save" button is pressed, the controller creates a model instanced and creates a record for it:
Checklist.savedSearchController = Ember.ArrayController.create({
[..]
save: function(view) {
var saved_seach = Checklist.SavedSearch.createRecord({
id: 'abcd',
filters: '<json>'
});
Checklist.local_store.commit();
}
});
Checklist.local_store is an adapter I created (this is unsurprisingly where the problem probably begins) that has a basic interface that maps createRecord, updateRecord, etc. to a bunch of get/set methods that work with localStorage (loosely based on a github fork of ember-data). The adapter appears to work fine for some basic tests, particularly as findAll has no issues and returns values added manually to localStorage.
Here is the relevant method within Checklist.local_store:
createRecord: function(store, type, model) {
model.set('id', this.storage.generateId);
var item = model.toJSON({associations: true});
this.storage.setById(this.storage_method, type, id, item);
store.didCreateRecord(model, item);
}
The problem is that when createRecord is called by the controller, absolutely nothing occurs. Running it through the debugger, and logging to console, seems to show that the method isn't called at all. I imagine this is a misunderstanding on my part as to how Ember.js is supposed to work. I'd appreciate help on why this is happening.
I come from a ruby and php background, and have perhaps foolishly dived straight in to a JS framework, so any other comments on code style, structure and anything in general are welcome.
Ember Data doesn't change createRecord on the controller so it shouldn't behave any differently. It's possible that there was something related to this in the past, but it's certainly not the case anymore.

Categories

Resources