Extjs Restful Store, Sending request in Batch? - javascript

I created a Grid component with the store configuration like this:
//Create the store
config.store = new Ext.data.Store({
restful: true,
autoSave: false,
batch: true,
writer: new Ext.data.JsonWriter({
encode: false
}),
reader: new Ext.data.JsonReader({
totalProperty: 'total',
root: 'data',
fields: cfg.fields
}),
proxy: new Ext.data.HttpProxy({
url:cfg.rest,
listeners:{
exception: {
fn: function(proxy, type, action, options, response, arg) {
this.fireEvent('exception', proxy, type, action, options, response, arg);
},
scope: this
}
}
}),
remoteSort: true,
successProperty: 'success',
baseParams: {
start: 0,
limit: cfg.pageSize || 15
},
autoLoad: true,
listeners: {
load: {
fn: function() {
this.el.unmask();
},
scope: this
},
beforeload: {
fn: function() {
this.el.mask("Working");
},
scope: this
},
save: {
fn: function(store, batch, data) {
this.el.unmask();
this.fireEvent('save', store, batch, data);
},
scope: this
},
beforewrite: {
fn: function(){
this.el.mask("Working...");
},
scope: this
}
}
});
Note: Ignore the fireEvents. This store is being configured in a shared custom Grid Component.
However, I have one problem here: Whatever CRUD actions I did, I always come out with N requests to the server which is equal to N rows I selected. i.e., if I select 10 rows and hit Delete, 10 DELETE requests will be made to the server.
For example, this is how I delete records:
/**
* Call this to delete selected items. No confirmation needed
*/
_deleteSelectedItems: function() {
var selections = this.getSelectionModel().getSelections();
if (selections.length > 0) {
this.store.remove(selections);
}
this.store.save();
this.store.reload();
},
Note: The scope of "this" is a Grid Component.
So, is it suppose to be like that? Or my configuration problem?
I'm using Extjs 3.3.1, and according to the documentation of batch under Ext.data.Store,
If Store is RESTful, the DataProxy is also RESTful, and a unique transaction is generated for each record.
I wish this is my configuration problem.
Note: I tried with listful, encode, writeAllFields, encodeDelete in Ext.data.JsonWriter... with no hope

Just for those who might wonder why it's not batch:
As for the documentation stated,
If Store is RESTful, the DataProxy is also RESTful, and a unique transaction is generated for each record.
Which is true if you look into the source code of Ext.data.Store in /src/data/Store.js
Line 309, in #constructor
// If Store is RESTful, so too is the DataProxy
if (this.restful === true && this.proxy) {
// When operating RESTfully, a unique transaction is generated for each record.
// TODO might want to allow implemention of faux REST where batch is possible using RESTful routes only.
this.batch = false;
Ext.data.Api.restify(this.proxy);
}
And so this is why I realize when I use restful, my batch will never get changed to true.

You read the docs correctly; it is supposed to work that way. It's something to consider whenever choosing whether to use RESTful stores on your grids. If you're going to need batch operations, RESTful stores are not your friends. Sorry.

Related

ExtJS Store Destroy event commit

I have an issue when I want to delete multiple items from a store without having to refresh my page. The first time I delete an event, all is well as you can see from this Fiddle snippet:
551 200 HTTP localhost:52543 /api/Appointments/Destroy?_dc=1442940419083 140 no-cache; Expires: -1 application/json; charset=utf-8 chrome:157528
Data:
{ "Id":1749644,"StartDate":"2015-09-22T01:00:00+02:00","EndDate":"2015-09-22T03:00:00+02:00","ResourceId":9,"PreviousResourceId":0,"Name":"","Cls":""}
However, if I want to remove additional items subsequently (without refreshing the page), it is as though the event store does not accept or understand that the previously removed record is already processed:
[
{ Id":1749644,"StartDate":"2015-09-22T01:00:00+02:00","EndDate":"2015-09-22T03:00:00+02:00","ResourceId":9,"PreviousResourceId":0,"Name":"","Cls":""},
{"Id":1749656,"StartDate":"2015-09-22T10:45:00+02:00","EndDate":"2015-09-23T16:00:00+02:00","ResourceId":20,"PreviousResourceId":0,"Name":"test","Cls":""}
]
If you look closely, you'll see the same event appears too in the second call whereas this shouldn't! Apart from this, everything goes perfectly: the Web API is called after every 1 destroy call (thus first time after every page request). After the first call, the Web API is still called but the binding is now corrupted due to unexpected input: it receives a collection whereas it expects only 1 item.
Here is the tore:
Ext.define('SchedulerApp.store.EventStore', {
extend: "Sch.data.EventStore",
autosync: true,
batch: false,
proxy: {
type: 'ajax',
api: {
create: '/api/Appointments/Add',
update: '/api/Appointments/Update',
destroy: '/api/Appointments/Destroy'
},
reader: {
type: 'json'
},
writer: {
type: 'json',
writeAllFields: true
}
},
listeners: {
load: {
fn: function (store, records, successfull) {
}
},
create: {
fn: function (store, records, successfull) {
}
},
add: {
fn: function (store, records, successfull) {
//store.sync();
}
},
update: {
fn: function (store, records, successfull) {
var previousResource = records.previous.ResourceId;
records.data.PreviousResourceId = previousResource;
records.store.sync();
}
},
destroy: {
fn: function (store, records, successfull) {
}
},
remove: {
fn: function (store, records, successfull) {
store.sync();
}
}
}
});
I need to figure out how to 'accept' an updated/inserted/removed record. This is a fairly standalone issue, so every other code than posted here will be useless information.
Turns out I indeed missed the store's commitment function. In the callback's success method, I added the commit and the issue disappeared!

Why does ViewModel.getStore("Key") return null?

The previous version was incorrect. My apologies.
I'm trying to load a store from the server with some parameters.
onSave: function (cmp) {
var vm = cmp.up('stageform').getViewModel();
vm.set("extraParams", {applicationFormId: 1});
var store = vm.getStore("applicationForms");
console.log(store);
}
vm.getStore("applicationForms"); returns null when the event is fired the first time, after that it returns the actual instance of the store.
Why do I get such a strange behavior? And is this the proper way of loading data from the server?
ViewModel Code:
Ext.define('CPCApplication.view.cases.ApplicationFormModel', {
.....
stores: {
applicationForms: {
model: 'CPCApplication.model.ApplicationForm',
autoLoad: true,
proxy: {
type: 'ajax',
extraParams: '{extraParams}',
autoload: true,
url: ...,
reader: {
type: 'json'
}
},
}
}
});
There is no obvious error in the code you posted. I only not quite sure when you call getStore. That can be important because view model exists only together with its view, binding is asynchronous, etc. Thus, it may be (theoretically) that the store really does not yet exist the first time.
Ideally, prepare a showcase and post it to https://fiddle.sencha.com. Then it would be possible to sort out if it is a problem in your app or in Ext. (Btw, which version?)

How to access store from other controller in ExtJS 4.2.2

I'm developing an application which is build in ExtJS 4.2.2 with symfony2 backend. Now I have following problem :
Lets say that I have 2 mvc's in my frontend - One for managing users and other for managing their data.
Now when user want to delete row of data I have to set his name in that deleted record so it can be archived and other users would know who made the deletion.
The question is how can I access to currently logged in user data from my DataController.
I've tried this:
This is part of code in my DataController, it's responsible for archiving deleted record
//sel[0] is selected record
//console.log({{ app.user.username }}); //I tought it could work somehow :) but it did not
sel[0].set('deleted_at', new Date()); //setting date of deletion
//get user store
//var usrStore = Ext.getStore('common_user.user_store');
var usrStore = Ext.data.StoreManager.lookup('common_user.user_store')
console.log(usrStore); //in both cases ruterns undefined
//sel[0].set('deleted_by', ); //here i want to save user name in column named "deleted_by"
sel[0].save();
sel[0].commit();
grid.getStore().sync();
grid.getStore().reload(); //reload grid
grid.getStore().remove(sel[0]); //remove from grid
This is how I've configured User store proxy
proxy: {
type: 'rest',
url: Routing.generate('webit_sencha_get',{store: 'common_user.user_store'}),
appendId: false,
batchActions: true,
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json',
root: 'data',
encode: true,
writeAllFields: true
}
}
Maybe I should load User grid on init of my data controller ? But still, I don't know how to.
Ext.define('Data.controller', {
extend: Ext.app.Controller,
init: function() {
this.control({
...
'data_grid': {
afterrender: this.onDataGridRender
},
'archive_grid': {
afterrender: this.onDataArchiveGridRender
},
'common_user_grid': {
afterrender: this.onUserGridRender // ????
}
});
},
...
So the question is how can I access (if it's possible) name of currently logged in user from other controller
I'll be thankfull for any guidance.
Problem fixed, I just had to pass parameter to my backend save option and then get current user there

Sencha touch store - phantom data

I created a model like
Ext.define('MyApp.model.ContainerDetailsModel', {
extend: 'Ext.data.Model',
alias: 'model.ContainerDetailsModel',
config: {
fields: [
{
name: 'id',
allowNull: false,
type: 'string'
},
{
name: 'container_types_id',
type: 'string'
}
]
}
});
and a store like this
Ext.define('MyApp.store.ContainerDetailsStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.ContainerDetailsModel'
],
config: {
model: 'MyApp.model.ContainerDetailsModel',
storeId: 'ContainerDetailsStore',
proxy: {
type: 'ajax',
enablePagingParams: false,
url: 'hereIsServiceUrl',
reader: {
type: 'json'
}
}
}
});
Now somewhere in application I tried to get one record like:
var detailsStore = Ext.getStore("ContainerDetailsStore");
detailsStore.load();
var detailsRecord = detailsStore.last();
But it gaves me undefined. The json returned by service is ok, it use it in different place as source for list. I already tried to change allowNull to true, but there is no null id in source. I tried set types to 'int' with the same result.
So I have tried
console.log(detailsStore);
Result is like this (just important values):
Class {
...
loaded: true,
data: Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
...
},
...
}
In the same place
console.log(detailsStore.data);
returns (as it should):
Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
but (next line)
console.log(detailsStore.data.all);
returns
[]
And it's empty array. When i try any methods from the store it says the store is empty.
I wrote console.log() lines one after another - so for sure it doesn't change between them (I try it also in different order or combinations).
My browser is Google Chrome 23.0.1271.97 m
I use Sencha from https://extjs.cachefly.net/touch/sencha-touch-2.0.1.1/sencha-touch-all-debug.js
How can I take a record from that store?
store.load() Loads data into the Store via the configured proxy. This uses the Proxy to make an asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved instances into the Store and calling an optional callback if required. The method, however, returns before the datais fetched. Hence the callback function, to execute logic which manipulates the new data in the store.
Try,
detailsStore.load({
callback: function(records, operation, success) {
var detailsRecord = detailsStore.last();
},
scope: this
});

EXTJS + Updating a store with the database ID after saving a grid

I'm trying to learn how to use the EXTJS grids for some simple CRUD operations over a table in a admin app.
I have a simple grid that allows someone to edit users, the store is defined as:
var userDataStore = new Ext.data.Store({
id: 'userDataStore',
autoSave: false,
batch: true,
proxy: new Ext.data.HttpProxy({
api: {
read: '/Admin/Users/All',
create: '/Admin/Users/Save',
update: '/Admin/Users/Save'
}
}),
reader: new Ext.data.JsonReader(
{
root: 'Data',
idProperty: 'ID',
totalProperty: 'total',
successProperty: 'success',
messageProperty: 'message'
}, [
{ name: 'ID', type: 'string', allowBlanks: false },
{ name: 'NT_ID', type: 'string', allowBlank: false },
{ name: 'EMail', type: 'string', allowBlank: false },
{ name: 'Name', type: 'string', allowBlank: false },
{ name: 'Enabled', type: 'bool', allowBlank: false },
{ name: 'CurrentRoleCode', type: 'string', allowBlank: false}]
),
writer: new Ext.data.JsonWriter(
{
encode: false,
writeAllFields: true,
listful: true
})
});
This is bound to a grid, and I am able to load and save users without issue. The save button looks like this:
var saveButton = new Ext.Button({
text: 'Save',
disabled: true,
handler: function() {
userDataStore.save();
pageState.ClearDirty();
saveButton.disable();
}
});
However, when creating a new user, the JSON POST for the user is posted to the same REST service end point as "Update", with the only difference being that no ID value is posted (as one is only set in the store when loading from the server).
This works, and I am able to create users.
The save REST service emits back the created row with the new database ID, and I was under the assumption that EXTJS would automatically bind the new generated database ID to the row. This allows the user to further edit that row, and cause an update instead of a insert.
Instead, the row continues to have a blank user ID, so an additional save creates another new user.
So either:
EXTJS is supposed to resolve generated row ID's automatically and I am just doing something wrong.
I am supposed to manually reload the grid after each save with an additional REST call.
I've been looking at EXTJS documentation and forums, but I am unclear on the proper approach.
Can someone clarify?
EDIT: I tried returning Success = True in JSON to match the SuccessProperty, however this still didn't seem to work.
EDIT #2: So far the only thing I've found that works is doing "userDataStore.reload()" after saving, however because I was returning the contents of the store back after saving, I was hoping that EXTJS would understand that and update the row values.
I've got an idea that may help you. Let't suppose that user added a new
record in grid, in that moment add a new property newRecOrderNo to the record to
identify the record after response. When user will post data to server after
inserting you must get a new ID and associate it to newRecOrderNo
(like Map<Integer,Integer>). Then return json object like that :
{
success : true,
newIdes : {
1 : 23,
2 : 34
}
}
Then when you get response do set proper IDs to records:
userDataStore.each(function(rec){
if(rec.data.newRecOrderNo){
rec.data.ID = response.newIdes[rec.data.newRecOrderNo];
delete rec.data.newRedOrderNo;
}
})
})
Yes, it sets id (and also other fields, if server returns modified values of them), if create ajax backend returns record with set id, at least in extjs 4.1. You should return inserted record, with id set, under 'root' key as json dictionary, in this example root is 'Data', i.e.:
{
"Data": {
"ID": 8932,
"NT_ID": 28738273,
...
"CurrentRoleCode": "aaa",
},
"success": true
}
You need reload store with new params in savebtn handler
like
store.reload();
of course you can add more params to load action

Categories

Resources