ExtJs 6 - change in ajax update requests - extjs

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

Related

ExtJS TreePanel / TreeStore remoteSort property does not override frontend sorting

The remoteSort option does not seem to work in terms of respecting the network call returned data order. The frontend will override whatever the order is and resort based on how it "should" be sorted.
Is this a bug, or is there something else that should be implemented that I don't know about when using remoteSort on a treepanel?
Here is a snippet of the remote sort code:
Ext.define('MyApp.stores.MyStore', {
extend: 'Ext.data.TreeStore',
alias: 'store.myStore',
storeId: 'myStoreID',
remoteSort: true,
remoteFilter: true,
simpleSortMode: true,
sortOnLoad: false,
autoLoad: true,
pageSize: 20,
proxy: {
type: 'ajax',
filterParam: 'query',
url: 'myEndpoint',
reader: {
type: 'json',
...
The treepanel loads correctly (no errors), the remote call IS MADE. When selecting a column to sort by it DOES send the correct data to the backend. The data DOES return. It even displays fine. But the ORDER IS WRONG.
The order is being sorted by the FE, rather than using the order of array elements returned by the backend.
The ONLY thing I have found so far is disabling the sort from the front end entirely when the grid is rendered using the afterrender property, but this disables the ability to send ASC and DESC, and the sort gets stuck in the ASC mode. This also does not seem like the correct way to make this work for obvious reasons.
The Sencha docs do not offer enough guidance around this for me to debug it properly

How to add value to compare it in xtype

Some help please.
I'm trying to display a xtype depending on value that i get from database.
I have created the store to fetch data from my server side, and it receives only boolean value true or false nothing else.
var hidden= Ext.create('Ext.data.Store',
{
fields: ['hidden'],
autoLoad: true,
proxy:
{
type: 'ajax',
url: 'hidden/compare',
reader:
{
type: 'json',
root: 'data'
}
}
});
Here is the example what i want, but i don't know what to add instead value_from_the_store
text: 'Now you see me, now you don't',
xtype: value_from_the_store == false ? 'hidden' : 'textfield',
If you look at the docs for Ext.data.Store, you'll see several functions that allow you to access the data in the store.
Ext.data.Store
I'm not sure which record you want to access, or if there is only one record, but you can get records by index using getAt, or by ID using getById. You can get the first record using first. There are also several find functions, which allow you to search for a specific record.
Since you said there is only one record, you could just use first. You'll also need to get the specific field in the record using get('hidden').
xtype: hidden.first().get('hidden') ? 'hidden' : 'textfield',
Here, you can try this fiddle - https://fiddle.sencha.com/#fiddle/lho
I've created this fiddle in Ext 5 but you can still make it work in 4. Hope this helps.
Here is the same fiddle for Ext 4.2 - https://fiddle.sencha.com/#fiddle/lji
And in the fiddle, instead of calling the function, you can even do this -
xtype: store.getAt([0]).get('hidden')? 'hidden' : 'textfield'
Another way of fetching the value from the store is by -
store.findRecord('hidden', 'true').get('hidden')
store.findRecord('fieldName', 'Either a string that the field value should begin with, or a RegExp to test against the field.')
Here's your link to the API doc

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

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.

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