I need to access JSON data from model, i used "this.model" in controller. From what i see in console log "this.model" is returning array of data arrays.
App.CardsRoute = Ember.Route.extend({
model: function() {
return Ember.$.getJSON('/cards');
}
});
This is what is server on path /cards returning :
[[1317888000000,372.5101],[1317888060000,372.4]]
I want to use that data in my ember HighStock (from HighCharts) implementation. It's drawing chart with this manually entered data:
App.CardsController = Ember.ArrayController.extend({
series: [{
name : 'test',
type: 'area',
data :[[1317888000000,372.5101],[1317888060000,372.4]],
...
But not drawing with this:
App.CardsController = Ember.ArrayController.extend({
series: [{
name : 'test',
type: 'area',
data : this.model,
...
From what i see in console, this.model is returning not only array with arrays of data but other ember specific objects too, is that the problem? if yes then how to access only JSON returned data so i can use it in controller?
You can directly format the data in your router itself, after the promise is successful.
When the controller is initialized, this method also will run once and will intialise.
To setup the data from the controller itself, format the data after the json promise is successful.
Ex:
App.CardsRoute = Ember.Route.extend({
model: function() {
return Ember.$.getJSON('/cards');
}.then(function(data){
return [{
name : 'test',
type: 'area',
data : data,
...
}]
});
After this in controller do this
The code is pasted in the jsbin http://jsbin.com/vekacayirugu/16/edit
This kind of formatting will work for you.
reference: http://emberjs.com/guides/object-model/computed-properties-and-aggregate-data/
Related
So I'm struggling to get this to work. Maybe my approach is not good. I'm quite a noob at using a Frontend framework like ember.js.
So, I've got a $.getJSON request obtaining a JSON data from a local file. The problem is that I need to pass this data, not to the template but to another object inside one ember controller.
I'm trying to use ember-CLI-charts to I need to return the object in the last lines of the property.
diffData: Ember.computed('model', function(){
let url = "log_hr24_diff.json";
let diff_data = Ember.$.getJSON(url);
return {
labels: ['Difficulty', 'Date'],
datasets: [
{
label: "Difficulty",
data: diff_data
},
{
label: "Date",
data: date_data
}
]
}
})
So that is not working. Either do this:
let diff_data = Ember.$.getJSON(url).then(function(data){
return Ember.Object.create(data);
});
So how do I get the JSON object from the diff_data JSON response to pass it to the return object?
Tried and search it a lot, but couldn't find an answer.
Thanks in advance!
It makes more sense to create a service, that way you can consume(in simpler words "use") your getJson call inside many controllers (or components and models), and change the url each time if you wish.
It makes sense when looking at making your code reusable.
To do this, you'll want to make a service through the CLI.
Ember g service someServiceName
Then your service might look a little like this:
import Ember from 'ember';
export default Ember.Service.extend({
getUrlData(url){
let data = Ember.$.getJSON(url);
return data.then((json) => {
let records = [];
json.forEach(function(item){
records.push(item);
});
return records;
});
}
});
For any advanced readers, i've avoided destructuring(ie - using a const) to avoid confusion for the OP.
And back in your controller, you may write something similar to:
import Ember from 'ember';
export default Ember.Controller.extend({
serviceToUse: Ember.inject.service('some-service-name'),
diffData: Ember.computed('model', function(){
let url = "log_hr24_diff.json";
let diff_data = this.get('serviceToUse').getUrlData(url);
//parse returnedData or put it in a new variable to use as you see fit.
return {
labels: ['Difficulty', 'Date'],
datasets: [
{
label: "Difficulty",
data: diff_data
},
{
label: "Date",
data: date_data
}
]
}
})
Now in the handlebar file for this controller, you can access the data from your controller like so:
{{diffData.labels}} //outputs "Difficulty,Date". You can loop through the datasets property yourself.
Beginner's hint - file names should match each other, that's how Ember knows how to link files. This does not always have to be true, but for now stick to that rule.
This should get you where you want to go. It works on my machine.
So finally I found the correct way its mean to be coded in ember (or a way to do it).
I realized that I need to return the diff and date data into the model. So i've done this.
routes/index.js
url = "log_hr24_diff.json";
var diff_data = Ember.$.getJSON(url, function(data){
return Ember.Object.create(data);
});
url = "log_hr24_dates.json"
var dates_data = Ember.$.getJSON(url, function(data){
return Ember.Object.create(data);
});
export default Ember.Route.extend({
model(){
return Ember.RSVP.hash({
price: price_data,
chart_diff: diff_data,
chart_dates: dates_data
});
},
});
Then in the main index controller file, just use this model data to pass the json data to the correct final object:
controllers/index.js
export default Ember.Controller.extend({
applicationController: Ember.inject.controller('application'),
diffData: Ember.computed('model', function(){
return {
labels: this.get('model.chart_dates'),
datasets: [
{
label: "Difficulty",
data: this.get('model.chart_diff')
}
]
}
})
});
So that's for me a correct way of doing things out on ember. Getting data in the model, passing data into the controller for logic workarround and finally pass the resulting object to the view.
Also asked on Sencha's site here
My data model's "serialize" function is not called when I call
model.set("<fieldName>", <newValue>);
Here's a fiddle
I'm pretty unclear on why the serialize function isn't called...am I missing something, or is this a bug?
(And here's the code from the fiddle)
Ext.application({
name : 'Fiddle',
requires: [
"Ext.data.Store"
],
launch : function() {
var store = Ext.create("Ext.data.Store", {
data: [{Id: 0, Name: "Bill", Props: "{foo: 2, bar:{pan:5}}"}],
fields:[
{name: "Id", type: "int"},
{name: "Name", type: "string"},
{name: "Props",
convert: function(value, record){
console.log("called convert");
return Ext.JSON.decode(value);
},
serialize: function(value, record){
alert("never getting called!! :(");
console.log("sure, i'll put log here too..not getting called though");
return Ext.JSON.encode(value);
}
}
]
});
console.log(store.getAt(0));
var rec = store.getAt(0);
var newProp = {rec:"junk", foo: "orange"};
console.log(newProp);
rec.set("Props",newProp);
}
});
Mappings from source content (JSON/XML) to business model (Ext.data.Model) are not automatically created in ExtJS's data model system. As such, another step is needed to produce this relationship using mapping/associationsor something similar.
I.e. The data model doesn't store the original JSON to read/write from, which is fine for most cases. When a JSON string needs to be updated via ExtJS, one solution is to, on the model, set
convertOnSet
to false, allowing for custom manipulation of the JSON string via extract/update functions on the data model.
I am using extjs sencha store for storing data. I make a proxy call to a web-service to get data. I refresh the data using store.load() function.
I am looking to edit the data that is received before it is given to the grid.
I know about the load event, but this function is executed after the load is completed and data is populated with the current data.
listeners : {
'load' : function(store,records, options) {
}
},
I am looking to see how I can edit the returned data from web-service before it is assigned to the store. Basically data returned from my webservice is in different format than the format we give to extjs datagrid. So, want to do a data operation before we give to the grid. Hope we can do this.
Thx
Model mappings can help you do this. There is a conversion function that can be supplied as well. Here is the example from the docs:
Ext.define('User', {
extend: 'Ext.data.Model',
fields: [
{
name: 'firstName',
convert: function(value, record) {
var fullName = record.get('name'),
splits = fullName.split(" "),
firstName = splits[0];
return firstName;
}
},
'name', 'email',
{name: 'age', type: 'int'},
{name: 'gender', type: 'string', defaultValue: 'Unknown'}
]
});
I have two backbone models, loaded from server:
var Model = Backbone.Model.extend({});
var SubModel = Backbone.Model.extend({});
var SubCollection = Backbone.Collection.extend({
model: SubModel
});
var m = new Model();
m.fetch({success: function(model)
{
model.submodels = new SubCollection();
model.submodels.url = "/sub/" + model.get("id");
model.submodels.fetch();
}});
So, the server has to send two separate responses. For example:
{ name: "Model1", id: 1 } // For Model fetch
and
[{ name: "Submodel1", id: 1 }, { name: "Submodel2", id: 2 }] // For Submodel collection fetch
Is there a way to fetch a Model instance with Submodel collection at once, like:
{
name: "Model1",
id: 1,
submodels: [{ name: "Submodel1", id: 2 }, { name: "Submodel1", id: 2 }]
}
To be able to do that is up to your back-end - it doesn't really have anything to do with Backbone.
Can you configure your back-end technology to return related models as nested resources?
If your back-end is Rails, for instance, and your models are related in ActiveRecord, one way of doing this is something like
respond_to do |format|
format.json { render :json => #model.to_json(:include => [:submodels])}
end
What back-end technology are you using?
Edit:
Sorry, misunderstood the gist of your question, once you've got your back-end returning the JSON in the proper format, yeah, there are things you need to do in Backbone to be able to handle it.
Backbone-Relational
One way to deal with it is to use Backbone-Relational, a plugin for handling related models.
You define related models through a 'relations' property:
SubModel = Backbone.RelationalModel.extend({});
SubCollection = Backbone.Collection.extend({
model: SubModel
});
Model = Backbone.RelationalModel.extend({
relations: [
{
type: 'HasMany',
key: 'submodels',
relatedModel: 'SubModel',
collectionType: 'SubCollection'
}
]
});
When your Model fetches the JSON, it will automatically create a SubCollection under the 'submodels' property and populate it with SubModels - one for each JSON object in the array.
jsfiddle for backbone-relational: http://jsfiddle.net/4Zx5X/12/
By Hand
You can do this by hand if you want as well. In involves overriding the parse function for your Model class (forgive me if my JS is not 100% correct - been doing CoffeeScript so much lately its hardwired in my brain)
var Model = Backbone.Model.extend({
parse: function(response) {
this.submodels = new SubCollection();
// Populate your submodels with the data from the response.
// Could also use .add() if you wanted events for each one.
this.submodels.reset(response.submodels);
// now that we've handled that data, delete it
delete response.submodels;
// return the rest of the data to be handled by Backbone normally.
return response;
}
});
parse() runs before initialize() and before the attributes hash is set up, so you can't access model.attributes, and model.set() fails, so we have to set the collection as a direct property of the model, and not as a "property" that you would access with get/set.
Depending on what you want to happen on "save()" you may have to override `toJSON' to get your serialized version of the model to look like what your API expects.
jsfiddle:
http://jsfiddle.net/QEdmB/44/
Im stack with ext js 4 at the very beginning. Im trying to get the current user data when starting the application using store. But Im not getting any data from the store, even the store.count return 0.
I found many description how to create store, but not how to access the data in it. I managed to get the data using Ext ajax request, but i think would be better using store and i cant avoid them..
My model:
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: [
'id',
'username',
'email'
]
});
My store looks like:
Ext.define('MyApp.store.User.CurrentUser', {
extend: 'Ext.data.Store',
requires: 'MyApp.model.User',
model: 'MyApp.model.User',
autoLoad: true,
proxy: {
type: 'ajax',
method: 'POST',
url: Routing.generate('admin_profile'),
reader: {
type: 'json',
root: 'user'
}
}
});
The returned json:
{
"success":true,
"user":[{
"id":1,
"username":"r00t",
"email":"root#root.root"
}]
}
And the application:
Ext.application({
name: 'MyApp',
appFolder: '/bundles/myadmin/js/app',
models: ['MyApp.model.User'],
stores: ['MyApp.store.User.CurrentUser'],
//autoCreateViewport: true,
launch: function() {
var currentUser=Ext.create('MyApp.store.User.CurrentUser',{});
/*
Ext.Ajax.request({
url : Routing.generate('admin_profile'),
method: 'POST',
success: function(resp) {
var options = Ext.decode(resp.responseText).user;
Ext.each(options, function(op) {
var user = Ext.create('MyApp.model.User',{id: op.id,username:op.username,email:op.email});
setUser(user);
}
)}
});
*/
currentUser.load();
alert(currentUser.count());
}
});
The problem itself isn't that the store does not contain data, the problem is that the store load is asyncronous therefore when you count the store records, the store is actualy empty.
To 'fix' this, use the callback method of the store load.
currentUser.load({
scope : this,
callback: function(records, operation, success) {
//here the store has been loaded so you can use what functions you like
currentUser.count();
}
});
All the sencha examples have the proxies in the store, but you should actually put the proxy in the model, so that you can use the model.load method. the store inherits the model's proxy, and it all works as expected.
it looks like model.load hardcodes the id though (instead of using idProperty), and it always has to be an int, as far as I can tell.
good luck!