How to wait until all stores are Sync in ExtJs? - javascript

I have a list of grids that can change their data in form by end-user.
Finally, I want to sync all the grids by clicking the button, then an operation is performed.
I wrote the code below:
$.when.apply(
Ext.ComponentQuery.query('grid')
.forEach(function(item) {
if (item.getXType() == "grid") {
if (item.store.getNewRecords().length > 0 || item.store.getUpdatedRecords().length > 0 || item.store.getRemovedRecords().length > 0) {
item.store.sync();
}
}
})).then(function (results) {
//do something
});
Problem is here that store.sync() not waiting for callback.
What is the recommended way of doing this?

I do it with Promise like this:
// Sync grid data if exist dirty data
Promise.all(
Ext.ComponentQuery.query('grid')
.map(grid => grid.getStore())
.filter(s => (s.getNewRecords().length + s.getUpdatedRecords().length + s.getRemovedRecords().length) > 0)
.map(s => new Promise((resolve, reject) => {
s.sync({
success: () => { resolve(); },
failure: () => { reject(); }
});
}))
).then(() => {
//do something
});

You could use callback for your store.sync() method.
The callback function to be called upon completion of the sync. The callback is called regardless of success or failure and is passed the following parameters: (batch, options).
You could achieve your requirement like this
Take a blank array name before loop. like this var gridIds=[].
In side of loop before store.sync() push grid id in above array.
Now in callback function remove that grid id from above array and check condition array is blank then your all store sync response has came.
You can check here with working Fiddle
Note I have used dummy api. Please use your actual api.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('MyStore', {
extend: 'Ext.data.Store',
alias: 'store.mystore',
fields: ['name'],
autoLoad: true,
pageSize: 25,
remoteSort: true,
proxy: {
type: 'ajax',
method: 'POST',
api: {
read: 'data.json',
update: 'your_update_api',
create: 'your_create_api',
destroy: 'your_delete_api'
},
reader: {
type: 'json'
},
writer: {
type: 'json',
encode: true,
root: 'data'
}
},
});
Ext.define('MyGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.mygrid',
store: {
type: 'mystore'
},
height: 200,
border: true,
tools: [{
xtype: 'button',
iconCls: 'fa fa-plus-circle',
tooltip: 'Add New Record',
handler: function () {
let grid = this.up('grid'),
store = grid.getStore();
store.insert(0, {
name: 'Test ' + (store.getCount() + 1)
});
}
}],
columns: [{
text: 'Name',
dataIndex: 'name',
flex: 1
}]
});
Ext.create({
xtype: 'panel',
// title: 'Store sync example',
items: [{
xtype: 'mygrid',
title: 'Grid 1'
}, {
xtype: 'mygrid',
title: 'Grid 2'
}, {
xtype: 'mygrid',
title: 'Grid 3'
}, {
xtype: 'mygrid',
title: 'Grid 4'
}],
bbar: ['->', {
text: 'Submit Changes',
handler: function (btn) {
var panel = btn.up('panel'),
grids = panel.query('grid'),
gtidIds = [],
lenthCheck = function (arr) {
return arr.length > 0;
};
grids.forEach(function (grid) {
let store = grid.getStore();
if (lenthCheck(store.getNewRecords()) || lenthCheck(store.getUpdatedRecords()) || lenthCheck(store.getRemovedRecords())) {
panel.mask('Please wait...');
gtidIds.push(grid.getId());
store.sync({
callback: function () {
Ext.Array.remove(gtidIds, grid.getId());
if (gtidIds.length == 0) {
panel.unmask();
Ext.Msg.alert('Info', 'All grid store sync success.');
}
}
}, grid);
}
});
}
}],
renderTo: Ext.getBody(),
})
}
});

Related

ExtJS: How to access Ajax request's value from any other proxy?

I'm getting some specific data from a web-service and need to transfer this data to another web-service's extraParams. How can I achieve to it?
I've created a singleton class which handles information and after fetching those data; another store proxy will use those data.
This is singleton class;
Ext.define('MyApp.MyInfo', {
requires: [] ,
singleton: true,
getMyId: function () {
var me = this;
var request = Ext.Ajax.request({
url: myUrl() + '/info', //Here is web-service url
success: function(response, opts) {
var obj = Ext.decode(response.responseText);
var myId = obj.data[0].id; // Successfully gets required ID
console.log(myId); // Successfully prints ID value
// callback(userGid); //Not sure if callback method will handle ID value to fetch on any other class..
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
}
});
and here is other proxy which needs myId value from Ajax.request above;
stores: {
myFooStore: {
model: 'MyApp.Model',
autoLoad: true,
session: true,
proxy: {
url: myUrl() + '/the/other/service',
type: 'ajax',
extraParams: {
id: // HERE! I need to get myId value on here. And couldn't get it.
},
reader: {
type: 'json',
rootProperty: 'data'
}
}
},
Instead of store auto load you need to call store.load() method to load your particular store. And you can pass your params using store.getProxy() like below example:
//you can set using get proxy
store.getProxy().setExtraParams({
id: id
});
store.load()
//or you can direcly pass inside of store.load method like this
store.load({
params: {
id: 'value' //whatever your extraparms you can pass like this
}
});
In this Fiddle, I have created a demo based on your requirement.
Code snippet:
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('MyInfo', {
alternateClassName: "myinfo",
singleton: true,
getMyId: function (callback) {
var me = this;
Ext.Ajax.request({
url: 'id.json', //Here is web-service url
success: function (response, opts) {
var obj = Ext.decode(response.responseText),
myId = obj.data[0].id; // Successfully gets required ID
console.log(myId); // Successfully prints ID value
callback(myId);
},
failure: function (response, opts) {
callback('');
console.log('server-side failure with status code ' + response.status);
}
});
}
});
Ext.define('MyViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.myview',
onLoadButtonTap: function () {
var view = this.getView(),
myFooStore = this.getViewModel().getStore('myFooStore');
view.mask('Please wait..');
myinfo.getMyId(function (id) {
view.unmask();
if (id) {
myFooStore.getProxy().setExtraParams({
id: id
});
myFooStore.load();
/*
You can also do like this
myFooStore.load({
url:'',//If you want to change url dynamically
params:{
id:'value'//whatever your extraparms you can pass like this
}
});
*/
}
});
}
});
Ext.define("ViewportViewModel", {
extend: "Ext.app.ViewModel",
alias: 'viewmodel.myvm',
stores: {
myFooStore: {
fields: ['name', 'email', 'phone'],
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json',
rootProperty: ''
}
}
}
}
});
//creating panel with GRID and FORM
Ext.create({
xtype: 'panel',
controller: 'myview',
title: 'Demo with singletone class',
renderTo: Ext.getBody(),
viewModel: {
type: 'myvm'
},
layout: 'vbox',
items: [{
xtype: 'grid',
flex: 1,
width: '100%',
bind: '{myFooStore}',
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}]
}],
tbar: [{
text: 'Load Data',
handler: 'onLoadButtonTap'
}]
});
}
});

ExtJS: Is possible to state if else condition for bind in grid panel?

Inside the ViewModel I've defined 2 stores and I'm using a gridpanel as view. Is there any chance to state if else condition for bind property inside gridpanel?
ViewModel:
stores: {
dataStore: {
model: 'MyApp.first.Model',
autoLoad: true,
session: true
},
listStore: {
model: 'MyApp.second.Model',
autoLoad: true,
session: true,
},
and on grid panel I want to do this condition;
Ext.define('MyApp.base.Grid', {
extend: 'Ext.grid.Panel',
// Currently binds directly to listStore
bind: '{listStore}',
// but I'm trying to implement a proper adjustment such as this;
// bind: function () {
// var username = localStorage.getItem('username');
// if (username === 'sample#adress.com') {'{dataStore}';} else {'{listStore}'}
// },
You can't use conditional expressions with bind, however, you can use ViewModel's formulas to select which store to use with grid. Here is example of such formula:
conditionalStore: function (get) {
var param = get('param');
if (param === 1) {
return get('simpsonsStore');
}
return get('griffinsStore');
}
And here is working fiddle, which you can play with: https://fiddle.sencha.com/#view/editor&fiddle/2eq2
You can use bindStore method of grid.
In this FIDDLE, I have created a demo using grid. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//defining store 1
Ext.define('Store1', {
extend: 'Ext.data.Store',
alias: 'store.store1',
autoLoad: true,
fields: ['name', 'email', 'phone'],
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json',
rootProperty: ''
}
}
});
//defining store 2
Ext.define('Store2', {
extend: 'Ext.data.Store',
alias: 'store.store2',
autoLoad: true,
fields: ['name', 'email', 'phone'],
proxy: {
type: 'ajax',
url: 'data2.json',
reader: {
type: 'json',
rootProperty: ''
}
}
});
//defining view model
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myvm',
stores: {
gridStore1: {
type: 'store1'
},
gridStore2: {
type: 'store2'
}
}
});
//creating grid
Ext.create({
xtype: 'grid',
title: 'Example of bind the store',
renderTo: Ext.getBody(),
viewModel: {
type: 'myvm'
},
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
tbar: [{
text: 'Load Store1',
handler: function (btn) {
var grid = this.up('grid');
grid.bindStore(grid.getViewModel().getStore('gridStore1'))
}
}, {
text: 'Load Store2',
handler: function (btn) {
var grid = this.up('grid');
grid.bindStore(grid.getViewModel().getStore('gridStore2'))
}
}]
});
}
});

Extjs Catch pick event (combobox)

Using ExtJS 4.2.3. I have FORM with combobox field and some values inside on choose. I need to catch event when user pick 1 of the value in combobox.
Asking for help with syntax, as example to get ALERT on picking DATA3 value.
Name of combobox field - "document_type".
Example of code on ExtJS:
documentForm_window = Ext.create("Ext.window.Window", {
title: (document_GUID == null) ? "[Create]" : "[Edit]",
width: 500,
modal: true,
layout: "fit",
items: [{
xtype: "form",
frame: true,
waitMsgTarget: true,
listeners: {
afterrender: function (form) {
if (document_GUID != null) {
form.getForm().load({
url: Ext.state.Manager.get("MVC_url") + "/Document/Get",
method: "GET",
params: { document_GUID: document_GUID },
waitMsg: "[loading]",
timeout: 300,
failure: function (form, action) {
if (action.result) Ext.Msg.alert("[Error1]!", action.result.errorMessage);
else Ext.Msg.alert("[Error2]!", "[Error3]!");
}
});
}
}
},
defaults: {
anchor: "100%",
msgTarget: "side",
labelWidth: 145,
allowBlank: false
},
items: [{
xtype: "combo",
name: "document_type",
fieldLabel: "<b>[Type]<font color='Red'>*</font></b>",
displayField: "document_type_name",
valueField: "document_type",
queryMode: "local",
triggerAction: "all",
editable: false,
store: document_store
}, {
xtype: "textfield",
name: "contract_number",
fieldLabel: "<b>[TestData]</b>"
}],
formBind: true,
buttons: [{
text: (document_GUID == null) ? "[Create]" : "[Edit]",
handler: function () {
var action = (document_GUID == null) ? "Create" : "Edit";
var form = this.up("form").getForm();
if (form.isValid()) {
form.submit({
url: Ext.state.Manager.get("MVC_url") + "/Document/" + action,
params: { document_GUID: document_GUID, treasury_GUID: tree_value },
waitMsg: "[Loading...]",
success: function (form, action) {
documentForm_window.destroy();
OrderLines_store.load({
scope: this,
callback: function (records, operation, success) {
documents_List.query('*[itemId="DATA1_grid"]')[0].selModel.select(curr_position);
}
});
},
failure: function (form, action) {
if (action.result) Ext.Msg.alert("[Error1]!", action.result.msg);
else Ext.Msg.alert("[Error2]!", "[Error3]!");
}
});
}
}
}]
}]
}).show();
}
//store//
document_store = new Ext.data.ArrayStore({
fields: ["document_type", "document_type_name"],
data: [[0, "data1"], [1, "data2"], [2, "data3"]]
});
Sorry, part of code I add as screen cause of post error "It looks like your post is mostly code".
You have to add a listener for the select event to the combobox:
editable: false,
store: document_store,
listeners: {
select: function(combo, records) {
console.log(combo);
console.log(records);
if(!Ext.isArray(records)) records = [records];
Ext.each(records, function(record) {
if(record.get(combo.valueField)==3) {
Ext.Msg.alert('Value is 3 for' + record.get(combo.displayField));
}
});
}
}

Store loaded, grid rendered with rows but no data shown

Here's a grid:
Ext.define('Customer_Portal_UI.view.BulkUpdateResultWindow.ResultGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.ResultGrid',
itemId: 'ResultGrid',
columns: [
{ text: 'Participant', mapping: 'firstname' },
{ text: 'Success', mapping: 'success' },
{ text: 'Status', mapping: 'statusMessage' }
],
viewConfig: { itemId: 'ResultGridView' },
initComponent: function () {
this.store = Ext.create('Ext.data.ArrayStore', {
storeId: 'ResultGridStore',
idProperty: 'contactid',
fields: [
'firstname',
'success',
'statusMessage',
'contactid'
]
});
this.callParent();
}
});
Here's how I attempt do load it:
var grid = this.Utils.getCmp('gridpanel[itemId=ResultGrid]');
var store = grid.getStore();
var response = Ext.JSON.decode(result.responseText);
for (var i = 0; i < response.length; i++) {
store.add({ firstname: response[i].contact.firstname, success: response[i].success, statusMessage: response[i].statusMessage, contactid: response[i].contact.contactid });
}
If I go in the console after that for loop, the store is loaded. If I call getStore() on the grid, its store contains data as well.
But the grid is rendered with the right number of lines (matching # of records in response) but those lines are empty.
Any ideas ?
Thanks!
Column doesn't have a mapping property. Use dataIndex.

How to add a Release filter on the PortfolioItem/Feature object

Using AppSDK 2.0, how can I see the "Release" field in the PortfolioItem/Feature when I create a store?
Release needs to be among the fetched fields in WsapiDataStore:
fetch: ['FormattedID','Name','UserStories','Release']
But then in a Rally.data.custom.Store, to account for Features that are not assigned to a release, this condition is used:
Release: (release && release.Name) || 'None'
Here is the code:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
Ext.create('Rally.data.WsapiDataStore', {
model: 'PortfolioItem/Feature',
fetch: ['FormattedID','Name','UserStories','Release'],
pageSize: 100,
autoLoad: true,
listeners: {
load: this._onDataLoaded,
scope: this
}
});
},
_createGrid: function(features) {
this.add({
xtype: 'rallygrid',
store: Ext.create('Rally.data.custom.Store', {
data: features,
pageSize: 100
}),
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name', dataIndex: 'Name'
},
{
text: 'Release', dataIndex: 'Release'
},
{
text: 'Story Count', dataIndex: 'StoryCount'
},
{
text: 'User Stories', dataIndex: 'UserStories',
renderer: function(value) {
var html = [];
Ext.Array.each(value, function(userstory){
html.push('' + userstory.FormattedID + '')
});
return html.join(', ');
}
}
]
});
},
_onDataLoaded: function(store, data){
var features = [];
var pendingstories = data.length;
//debugger;
Ext.Array.each(data, function(feature) {
var release = feature.get('Release');
var f = {
FormattedID: feature.get('FormattedID'),
Name: feature.get('Name'),
Release: (release && release.Name) || 'None',
_ref: feature.get("_ref"),
StoryCount: feature.get('UserStories').Count,
UserStories: []
};
var stories = feature.getCollection('UserStories');
stories.load({
fetch: ['FormattedID'],
callback: function(records, operation, success){
Ext.Array.each(records, function(story){
var number = story.get('DirectChildrenCount');
if (number == 0) {
f.UserStories.push({_ref: story.get('_ref'),
FormattedID: story.get('FormattedID')
});}
}, this);
--pendingstories;
if (pendingstories === 0) {
this._createGrid(features);
}
},
scope: this
});
features.push(f);
}, this);
}
});

Categories

Resources