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.
Related
While using the RESTAdapter, I have an Organization model which is to be embedded in the response. It appears that the default implementation of the Ember.RESTAddapter sends the id, using the same model name, but not as an object (this currently 'works'):
POST/PUT api/v1/item/{id}
{
"item" {
id: "1029383829"
...
organization: "26044097612186763401268824297"
}
}
I have consulted the documentation, and found that the mixin DS.EmbeddedRecordsMixin should do this, coupled with declaring embedded: "always" on the attrs or the Serializer:
models/item.js
var Item = DS.Model.extend({
...,
organization: DS.belongsTo("organization", {embedded: "always"})
});
serializers/item.js:
var ItemSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
organisation: {serialize: "id", embedded: "always"}
}
}
);
However, when deserializing records, Ember Data complains, saying that it expected an object, but just got a string:
Assertion Failed: Expected an object as data in a call to push for
app#model:organization: , but was 26044097612186763401268824297
Ultimately, I would prefer a system, likened to sideloading, wherein an additional attribute, post-fixed "_id", describes the corresponding id of an embedded record:
{
"item": {
id: 1,
name: "name",
organization_id: "26044097612186763401268824297"
...
}
}
How can I allow serializing and deserializing embedded id sideloading for my Organization model?
You aren't actually embedding the record, you're just specifying the id, in that case you should mark it as async.
var Item = DS.Model.extend({
...,
organization: DS.belongsTo("organization", {async: true})
});
And remove your embedded records implementation.
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/
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 store that I would like to initialize from a database but I couldn't find a standard init method for the Ext.data.Store. I found a couple of examples with the StoreManager component, but I think that's not what I'm looking for. I have an MVC structure for my app and I'd like to keep it, I only want to initialize my store's data field using a method I define. Could someone explain how to do so?
I either understand you wrong or your question is straight forward. You configure a store with a model like this. That's all. You may just chose a provider(reader/writer) that fit your needs.
// Set up a model to use in our Store
Ext.define('User', {
extend: 'Ext.data.Model',
fields: [
{name: 'firstName', type: 'string'},
{name: 'lastName', type: 'string'},
{name: 'age', type: 'int'},
{name: 'eyeColor', type: 'string'}
]
});
Ext.define('YourMVCNameSpace.data.UserStore', {
extend: 'Ext.data.Store',
constructor: function (config) {
config = Ext.Object.merge({}, config);
var me = this;
// do what you need with the given config object (even deletes) before passing it to the parent contructor
me.callParent([config]);
// use me forth on cause the config object is now fully applied
},
model: 'User',
proxy: {
type: 'ajax',
url: '/users.json',
reader: {
type: 'json',
root: 'users'
}
},
autoLoad: true
});
Note that the reader will expect a Json result like this:
{"total": 55, "users":["...modeldata.."]}
and is referring to a url like
http://localhost/YourAppDomain//users.json
Place the store as 'User' within the controller store array and retrieve it within the Controller by calling getUserStore() or directly from the Ext.StoreMgr using Ext.StoreMgr.lookup('User');
Note that by convention the Controller (MVC) will override any storeId you set on the store and will just use the name.
I'm trying to create a nested, relational backbone project but I'm really struggling. The rough idea of what I'm trying to do is shown below but I was under the impression upon calling fetch() on Client, a number of bookings would automatically be created based on the bookings being returned as JSON.
The format of my JSON can be seen beneath the outline of the MVC:
/****************************************************
/* CLIENT MODEL - Logically the top of the tree
/* has a BookingsCollection containing numerous Booking(s)
/* Client
/* -Bookings [BookingsCollection]
/* -Booking [Booking]
/* -Booking [Booking]
/*****************************************************/
var Client = Backbone.RelationalModel.extend({
urlRoot: '/URL-THAT-RETURNS-JSON/',
relations: [
{
type: Backbone.HasMany,
key: 'Booking',
relatedModel: 'Booking',
collectionType: 'BookingsCollection'
}
],
parse: function (response) {
},
initialize: function (options) {
console.log(this, 'Initialized');
}
});
var Booking = Backbone.RelationalModel.extend({
initialize: function (options) {
console.log(this, 'Initialized');
}
});
var BookingsCollection = Backbone.Collection.extend({
model: Booking
});
Any help outlining what I'm doing wrong would be massively appreciated.
Thanks
EDIT
Thanks for taking the time to post the feedback, it's exactly what I was hoping for.
Is it the case that the JSON physically defines the actual attributes of models if you don't go to the effort of setting attributes manually?
In other words, if the JSON I get back is as you have suggested above, would Backbone simply create a Client object (with the 4 attributes id, title, firstname & surname) as well as 2 Booking objects (each with 4 attributes and presumably each members of the BookingsCollection)?
If this is the case, what is the format for referencing the attributes of each object? When I set up a non-backbone-relational mini-app, I ended up in a situation whereby I could just reference the attributes using Client.Attribute or Booking[0].EventDate for example. I don't seem to be able to do this with the format you have outlined above.
Thanks again.
The JSON being returned is not what Backbone or Backbone-Relational is expecting by default.
The expectation of Backbone and Backbone-Relational is:
{
"id": "123456",
"Title":"Mr",
"FirstName":"Joe",
"Surname":"Bloggs",
"Bookings": [
{
"id": "585462542",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
},
{
"id": "585462543",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
}
]
}
To use your response, you need to create a parse function on the Client model that returns the structure I've posted above.
A jsFiddle example of your model definitions working with my example JSON: http://jsfiddle.net/edwardmsmith/jVJHq/4/
Other notes
Backbone expects ID fields to be named "id" by default. To use another field as the ID for a model, use Model.idAttribute
The "key" for the Bookings Collection I changed to "Bookings"
Sample Code:
Client = Backbone.RelationalModel.extend({
urlRoot: '/URL-THAT-RETURNS-JSON/',
relations: [
{
type: Backbone.HasMany,
key: 'Bookings',
relatedModel: 'Booking',
collectionType: 'BookingsCollection'
}
],
parse: function (response) {
},
initialize: function (options) {
console.log(this, 'Initialized');
}
});
Booking = Backbone.RelationalModel.extend({
initialize: function (options) {
console.log(this, 'Initialized');
}
});
BookingsCollection = Backbone.Collection.extend({
model: Booking
});
myClient = new Client( {
"id": "123456",
"Title":"Mr",
"FirstName":"Joe",
"Surname":"Bloggs",
"Bookings": [
{
"id": "585462542",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
},
{
"id": "585462543",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
}
]
});
console.log(myClient);
Post Edit
Yes, the JSON pretty much defines the attributes of the model. You can use a combination of parse(), defaults, and validate() to better control what attributes are valid and allowed.
The canonical way of reading and setting properties on a Backbone Model is through the get(), escape(), and set() functions.
set is especially important as this does a bunch of housekeeping, such as validating the attribute and value against your validate function (if any), and triggering change events for the model that your views would be listening for.
In the specific case of the situation in this answer, you might
myClient.get('Title'); // => "Mr"
myClient.get('Bookings'); //=> an instance of a BookingsCollection with 2 models.
myClient.get('Bookings').first().get('Location'); //=> "Dee Bla"
myClient.get('Bookings').last().get('Location'); //=> "Dee Bla"
myClient.get('Bookings').first().set({location:"Bora Bora"});
myClient.get('Bookings').first().get('Location'); //=> "Bora Bora"
myClient.get('Bookings').last().get('Location'); //=> "Dee Bla"