How come store.add() method does not perform mapping? - extjs

I have a nested json data, namely:
{
name: 'alex',
tel: {
personal: '347xxxx',
work: '331xxxx'
}
}
Then the following model:
Ext.define("Employer", {
extend: 'Ext.data.Model',
idProperty: 'personalTel',
fields: [...
{name: 'personalTel', mapping: 'tel.personal'}
Finally the following store:
Ext.create('Ext.data.Store',{
model: 'Employer',
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'root'
}
},
data: myInitialData //an array containing json objects
As long as the data is contained in myInitialData the personalTel field is correctly set.
However, adding a new record to the store does not trigger the mapping and so I find myself with strange personalTel property, that is automatic IDs extjs puts!

ExtJS allows you to load multiple models via nesting when using a reader. It does not allow those models to be created when instantiating the model directly, which is what adding the object to the store does.
The idea is that each model is treated separately with its own store. Want to add a customer with a telephone number? Create the telephone number first, put it in its store, then create the customer with a reference to the telephone number.
This approach is a bit clumsy, though, and only works with models that really are separate entities.
An alternative approach would be to use a custom type, or simply to use the 'auto' type (which treats the data as a blob that you can do what you want with). Both approaches have their drawbacks.

Related

ExtJs 6 - change in ajax update requests

ExtJs does not expect the same response from the server to confirm updating rows than ExtJs 4.
I have a table with a string id:
Ext.define('App.Product', {
extend: 'Ext.data.Model',
fields: [
{name: 'productid', type: 'string'},
{name: 'ord', , type: 'int'},
(...)
],
idProperty: 'nrproduit'
})
Upon saving the changes, the ExtJs client sends the modified data to the server:
[{"ord":1,"productid":"SG30301"},{"ord":3,"productid":"SG30100"}]
In ExtJs 4.2, it expected the server to send the full data of the two products back, like this:
{
"success":true,
"data":[{
"nrproduit":"SG30100",
"ord":3,
"author":"...",
"editor":"...",
(...)
},{
"nrproduit":"SG30301",
"ord":3,
"author":"...",
"editor":"...",
(...)
}]
}
In ExtJs 6.2, this no longer works. I get the error
Uncaught Error: Duplicate newKey "SG30100" for item with oldKey "SG30301"
Apparently, the client does not take into account the idProperty, but seems to expect the order of the row to be the same in the response as in the request.
Is there a way to force the client to take into account the ids sent back from the server ? Or is it necessary to change the server code ? Is there somewhere documentation on what exactly changed between ExtJs 4.2 and 6.2 in respect to data synchronization between client and server, that go into these details ?
ExtJS considers the order because ids can change, e.g. during insert operations (if the id is generated server-side). To allow for that, in the general case, ExtJS expects to receive the results from the server in the same order in which the records were sent.
However, there's more to it. Under certain circumstances, it uses the id, not the order. You can read Operation.doProcess to find how ExtJS does what it does, and possibly override it if you require a different behaviour.
Edit: It uses the id when the model has the property clientIdProperty, else it uses the order. So, it is enough to add it like this:
Ext.define('App.Product', {
extend: 'Ext.data.Model',
fields: [
{name: 'productid', type: 'string'},
{name: 'ord', , type: 'int'},
(...)
],
idProperty: 'nrproduit',
clientIdProperty: 'nrproduit'
})
Another alternative solution, if you don't want to change the server side code to handle the clientIdProperty property is to disable the batch mode (with batchActions: false) and all your requests are handled one by one.
This is prevent the error "extjs Ext.util.Collection.updateKey(): Duplicate newKey for item with oldKey". With his approach, you will loose some efficiency.
You have to add this to your model:
...
proxy: {
type: 'direct',
extraParams: {
defaultTable: '...',
defaultSortColumn: '...',
defaultSordDirection: 'ASC'
},
batchActions: false, // avoid clientIdProperty
api: {
read: 'Server.Util.read',
create: 'Server.Util.create',
update: 'Server.Util.update',
destroy: 'Server.Util.destroy'
},
reader: {
Just adding clientIdProperty on Model definition solved the issue.
Some more info. Same problem has been asked on sencha forum but solution is not mentioned there. Here is the link to that discussion-
https://www.sencha.com/forum/showthread.php?301898-Duplicate-newKey-quot-x-quot-for-item-with-oldKey-quot-xx-quot

Map JSON Object to Model/Store

I'm using Worklight framework to construct a mobile app for IOS, and is using Sencha Touch 2.3 to build the app.
Due to the environment, i cannot use proxy in Sencha Touch Store/Model objects to load data from the server, as i would need to use Worklight's adapter to retrieve the info. I have managed to do that using some boilerplate codes.
However, i wish that i could utilize the Sencha Model more, and as such, am thinking whether it is possible for me to load a JSON object into the Model object automatically, without specifying a proxy.
Currently i'm doing a lot of loop and setter call to load the data from the JSON object to a model, like below:
var profile = Ext.create('Profile', {
Id: rawProfile.Id,
Name: rawProfile.Name
Age: rawProfile.Age
.....
}
where rawProfile is the JSON object i loaded from the server.
Any way i can make this cleaner?
You could create a Model class which would contain the data contained in your rawProfile object.
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [{
name: 'Id',
name: 'Age',
...
}],
proxy: {
type: 'memory',
reader: 'json'
}
});
I've also set an in memory proxy which will read json objects.
You could then create a Store which would use the model you defined and the in memory proxy (meaning you wouldn't be using Ext's build in ajax messaging).
Ext.create('MyStore', {
model: 'MyModel',
autoLoad: false
});
Setting the autoLoad to be false, as you want to get the data from a different source.
Therefore, once you have your json object you can load it into the store by calling store.loadRawData(jsonObject).
In this case, the jsonObject would be the object containing all the json objects returned from the server, meaning that your code doesn't have to handle iterating through the records and you can leave it to the Sencha classes.
However you would need to figure out the writing data back to the server.
I'd recommend running through the Sencha Data Package tutorial as it gives a good intro to the data package
If all the fields map 1:1 with the json object, you can do this:
var profile = Ext.create('Profile', rawProfile);
Alternatively (or to avoid the convert functions for fields to be called), you can directly set the data property on the created model.
var profile = Ext.create('Profile');
profile.data = rawProfile;
Again, this requires a 1:1 on the fields and json object.

Mapping not working when creating a model with Ext.create?

When I create a model using Ext.create() in ExtJs 4.2+, I am expecting the mapping to fill the model but it does not seem to do it. Is it a normal behavior?
If I use a model with mapping in a store, the mapping works fine...
Example not working:
http://jsfiddle.net/B6v6v/
Ext.define('MyApp.model.file', {
extend: 'Ext.data.Model',
fields: [
{
name: 'name',
mapping:'label'
}]
});
var rec = Ext.create("MyApp.model.file",{"label":"TEST"});
console.log(rec.get("name"));
Yes, it's normal. The mapping is for transforming data coming in from the server into something readable in your model. If you already have the data, why not just use the correct key?
If you must, you can do something like:
MyApp.model.File.getProxy().getReader().readRecords([{}, {}, {}]);

How to have several CRUD methods using a proxy with Sencha Touch 2 framework?

I've coded a small mobile application using Sencha Touch 2 framework. For the moment, I manage some articles from a database in localhost. I've written a database management using PHP CRUD methods contained here in ArticleService.php file. My 'read' fonction get back all the articles. But I want to have an other 'read' method to read for exemple a specific article according to its id or the last 5 articles, etc. But the store proxy (I think so) allows 1 methods for each main operation. So in my case, for 'read' operation I just have an only 'read' method.
Here's is my 'store' source code :
Ext.define("MyApp.store.ArticleStore", {
extend: "Ext.data.Store",
requires: ["MyApp.model.ArticleModel"],
config: {
model: "MyApp.model.ArticleModel",
proxy: {
type: "ajax",
api: {
create: "http://localhost/MobileApplication/MyApp/services/ArticleService.php?action=create",
read: "http://localhost/MobileApplication/MyApp/services/ArticleService.php?action=read",
update: "http://localhost/MobileApplication/MyApp/services/ArticleService.php?action=update",
destroy: "http://localhost/MobileApplication/MyApp/services/ArticleService.php?action=destroy"
},
extraParams: {
keyword: ""
},
reader: {
type: "json",
rootProperty: "articles",
totalProperty: "total"
}
},
autoLoad: true
}
});
Is there a possible way to have several methods for each main CRUD operation (for example 3 differents 'read' methods to manage my articles display) ? I'm really lost.
Thanks in advance for your help!
You don't need different methods for read. Once you load the store it will be in the memory and you will be able to find any record you want.
If you're store is too big to be loaded at once - take a look at remoteFilter property: http://docs.sencha.com/touch/2.1.1/#!/api/Ext.data.Store-cfg-remoteFilter This way filters you will set up (like id = 1 or parent_id = 2) will be passed to the server so it can return proper record set.

extjs 4 line chart rendering problems

I am having trouble with extjs rendering the line chart below. Specifically, the last six values are null which are (correctly) not shown on the series line but (incorrectly) have a marker dot displayed for them (see top right of the image below).
I am pulling the graph data from a database as json:
// data store fields
Ext.define('Graphs', {
extend: 'Ext.data.Model',
fields: [
{name: 'the_quota', type: 'int'},
{name: 'count_pt_year', type: 'int'},
{name: 'date_string', type: 'string'}
]
});
// get the graph data
var graphStore = Ext.create('Ext.data.Store', {
model: 'Graphs',
proxy: {
type: 'ajax',
url: 'sqlRequest.jsp?queryName=events_getGraph',
timeout: 160000,
reader: 'json'
},
autoLoad:false
});
If I change the query to return these null values as blanks instead ('') then the json reader converts them to zeros and the values display as zero along the bottom of the graph with a series line, which is worse then having the markers plastered to the ceiling without a series line.
I haven't been able to find any config option in Ext.chart.Series to hide null values on the graph. Nor have I been able to find a config option in Ext.data.Store to return blanks as blanks and not "0".
Looking for some other workaround.
Or has anyone resolved these issues from within the library itself (ext-all.js)?
There's a config option under Ext.data.Field called useNull. If the data received cannot be parsed into a number, null will be used instead. As of right now I can't recall if that alone will fix the problem, and I have a memory of once using a custom convert function that went something like this:
convert: function(value){
if(typeof value !=== 'number') // or other similar conversion
return undefined;
return value;
}
If this doesn't work, you may need to customize your store/reader to completely exclude records containing the undesirable null value.
EDIT - Using useNull looks like this: {name: 'someName', type: 'int', useNull: true}

Resources