ExtJS 3 multiple stateful grids (but with different stateIds) - extjs

I have my grid, which overwrites Ext.grid.GridPanel
I use this grid in 2 places on my site. I generate 2 different stateIds for them:
constructor:
TasksGrid.superclass.constructor.call(this, {
id: genId,
cls: 'tasks-grid',
border: false,
loadMask: {msg: 'Loading...'},
sm: sm,
stateful: true,
stateId: 'tasks-grid'+(config.booClientTab ? '-clients-tab' : ''), // depending on config.booClientTab I setup one or other stateId
...
this code I call in 2 places on site to create 2 grids:
this.TasksGrid = new TasksGrid(this, {
region: 'west',
split: true,
width: tasksGridWidth ? tasksGridWidth : defaultWidth,
booShowToolbar: true,
booClientTab: !empty(config.clientId) // if true, 1 stateId will be setup, false - other
});
But, when I test, state is applied only to first of 2 generated grids!! I checked cookies: seems, that all works fine: 2 cookies with 2 different names are created. But... State applies only to first call of "this.TasksGrid = new TasksGrid"!!!
ExtJS version: 3.0
Any thoughts?

I had the same problem. State can be applied to the component only during initialization not after initialization. Therefore it works for the first time but not after. Luckily you are using EextJs 3 and following piece of code worked for me in ExtJS 3 but not in 4. Basically when you apply new/other state to the grid just call
MyGrid = Ext.extend(Ext.grid.GridPanel,
{
/* #private */
constructor: function(config)
{
MyGrid.superclass.constructor.call(this, config);
},
initComponent: function()
{
var cfg =
{
border: true,
bodyBorder: false,
stateful: true,
stateId: 'grid',
tbar:
[{
text: 'View name'
},{
xtype: 'combo',
width: 80,
typeAhead: true,
triggerAction: 'all',
mode: 'local',
forceSelection: true,
hiddenName: 'stateId',
selectOnFocus:true,
displayField:'name',
ref: '../stateCombo',
valueField: 'id',
listeners:
{
scope: this,
change: function(combo, newValue, oldValue)
{
newValue = parseInt(newValue, 10); var grd = this;
grd.el.mask('Applying the view please wait');
var data = combo.store.data.items;
Ext.each(data, function(d)
{
d.data.id = parseInt(d.data.id, 10);
if(d.data.id === newValue)
{
Ext.util.Cookies.set('reportStateName', d.data.machineName);
grd.applyState(MyStateProvider.decodeState(d.data.value));
var conf = grd.getColumnModel().config;
grd.getColumnModel().setConfig(conf);
grd.doLayout();
grd.getView().updateAllColumnWidths();
grd.getView().refresh(true);
return;
}
});
grd.el.unmask();
grd = null;
}
},
store: new Ext.data.JsonStore
({
fields:
[{
name: 'id',
type: 'int'
}],
proxy : new Ext.data.HttpProxy
({
method: 'GET',
url: BASEURL + 'getsavedstate'
}),
idProperty: 'id'
})
}]
};
//we use applyIf for configuration attributes that should be left configurable
Ext.applyIf(this, cfg);
//ensure that any extra configurations that are set in initComponent method are applied to initialConfig:
Ext.applyIf(this.initialConfig, cfg);
/*
* Properties specified here are safe/protected from being overridden
* by an instance, so any 'private' default properties might be specified here.
*/
//some attributes we may want to keep unaltered, so we use Ext.apply non-alterable configurables
cfg =
{
sm: new Ext.grid.RowSelectionModel({singleSelect:true}),
stripeRows: true,
loadMask: true
};
Ext.apply(this, cfg);
//need this to work sometimes:
Ext.apply(this.initialConfig, cfg);
MyGrid.superclass.initComponent.apply(this, arguments);
this.on
({
afterrender: function(grid)
{
var grd = this;
this.stateCombo.getStore().load
({
callback: function(data, options, success)
{
grd.saveAsStateBtn.enable();
var applied = false;
var setStateValue = Ext.util.Cookies.get('reportStateName');
Ext.each(data, function(d)
{
//meaning no cookie was set so first time.
if(setStateValue === null)
{
if(d.data.machineName === 'default')
{
if(d.data.value !== '')
{
grd.applyState(MyStateProvider.decodeState(d.data.value));
applied = true;
grd.stateCombo.setValue(d.data.id);
return;
}
applied = true;
grd.stateCombo.setValue(d.data.id);//Here value should be fetched from cookie
return;
}
}
else//Cookie was set
{
if(d.data.machineName === setStateValue)
{
if(d.data.value !== '')
{
var s = MyStateProvider.decodeState(d.data.value);
grd.applyState(s);
applied = true;
grd.stateCombo.setValue(d.data.id);//Here value should be fetched from cookie
return;
}
else
{
return;
}
}
}
});
//grd.doLayout();
if(data.length !== 0)
{
grd.stateCombo.enable();
grd.saveStateBtn.enable();
}
var conf = grd.getColumnModel().config;
grd.getColumnModel().setConfig(conf);
grd.doLayout();
grd.getView().updateAllColumnWidths();
grd.getView().refresh(true);
grd.doLayout();
grd.el.unmask();
}
});
this.el.mask('Applying the saved view please wait');
},
scope: this
});
},
onRender: function (container, position)
{
MyGrid.superclass.onRender.apply(this, arguments);
var el = this.el;
var grd = this;
this.saveStateWindow = new MySaveStateWindow
({
grid: grd,
renderTo: el
});
},
// template method
/* #private */
initEvents: function()
{
MyGrid.superclass.initEvents.apply(this, arguments);
},
afterRender: function()
{
MyGrid.superclass.afterRender.apply(this, arguments);
},
// template method
/* #private */
beforeDestroy: function()
{
//Call parent
MyGrid.superclass.beforeDestroy.apply(this, arguments);
},
onDestroy: function()
{
this.saveStateWindow.destroy();
MyGrid.superclass.onDestroy.apply(this, arguments);
}
});

Related

ExtJS 5.x How to change grid view (viewConfig) after store load?

I have a store in ViewModel like:
Ext.define('MyApp.page.PageModel', {
extend: 'Ext.app.ViewModel',
//...
stores: {
Posts: {
model: //...
}
}
});
And a grid like:
Ext.define('MyApp.page.MainView', {
extend: 'Ext.panel.Panel',
//...
initComponent: function () {
var me = this;
//...
me.items = [
{
xtype: 'grid',
bind: {
store: '{Posts}'
},
columns: [ /* ... */ ],
viewConfig: {
getRowClass: function (record) {
//...
}
}
}
];
me.callParent(arguments);
}
});
How can I change grid view AFTER store load (in my case)?
I tried to use mon and addManagedListener methods in grid events (beforerender and viewready) and I tried to use on and addListener methods to store inside those grid events, but this solution is not working.
Does someone have any ideas?
I'm using override for Ext.view.AbstractView, just to clear emptyEl and viewEl before store load event
store.on('beforeload', function() {
me.clearEmptyEl();
me.clearViewEl();
});
Here is my complete override
Ext.define('Ext.overrides.view.AbstractView', {
override: 'Ext.view.AbstractView',
onBindStore: function(store, initial, propName) {
var me = this;
me.setMaskBind(store);
// After the oldStore (.store) has been unbound/bound,
// do the same for the old data source (.dataSource).
if (!initial && propName === 'store') {
// Block any refresh, since this means we're binding the store, which will kick off
// a refresh.
me.preventRefresh = true;
// Ensure we have the this.store reference set correctly.
me.store = store;
me.bindStore(store, false, 'dataSource');
me.preventRefresh = false;
}
store.on('beforeload', function() {
me.clearEmptyEl();
me.clearViewEl();
});
}
});
In ExtJS 6, a function setEmptyText is available on the grid that will do this for you:
initComponent: function () {
var me = this;
//...
me.callParent(arguments);
me.getStore().on('load', function() {
me.setEmptyText(...);
})
}
In ExtJS 5, you have to do on your own:
me.getStore().on('load', function() {
var emptyText = 'Test empty text';
me.getView().emptyText = '<div class="' + me.emptyCls + '">' + emptyText + '</div>';
me.getView().refresh();
})
Relevant fiddle, will load its store 3 seconds after rendering.

How to initialize a combo value in viewController init() without firing its change event

I have a Sencha Fiddle that describes the problem:
https://fiddle.sencha.com/#fiddle/13ol
I want to initialize the combo, but avoid firing its change event (until after init() is complete). The value for the combo is first available in the viewController init() method.
I don't know how you can defer it until after init function, but you can at least defer it until directly before init function ends:
init: function() {
var combo = this.lookupReference('MyCombo');
combo.suspendEvent("change");
combo.setValue('Week');
// do everything else you want to do in init.
combo.resumeEvent("change");
}
I have tested in your fiddle that this code:
init: function() {
var combo = this.lookupReference('MyCombo');
combo.suspendEvent("change");
combo.setValue('Week');
console.log('testfirst');
combo.resumeEvent("change");
},
onMyComboChange: function() {
console.log('testsecond')
// Need to avoid firing this method during init
}
produces this console.log:
run?_dc=1452632485198:60 testfirst
run?_dc=1452632485198:65 testsecond
Use value config to create combobox with an initial value.
Ext.define('MyApp.view.TestViewControler', {
...
init: function() {
// Do something
var newValue = 'Week'; // Get new value
this.getView().addCombo(newValue);
}
...
});
Ext.define('MyApp.view.TestView', {
...
addCombo: function(value) {
this.add({
xtype: 'combo',
reference: 'MyCombo',
editable: false,
hidden: false,
fieldLabel: 'My Combo',
bind: {
store: '{comboStore}'
},
displayField: 'name',
valueField: 'key',
listeners: {
change: 'onMyComboChange'
},
value: value
});
}
});

Applying loadMask() to only grid pannel in extjs is not working

I want to apply load mask to only my grid pannel using id of it,
var myMask = new Ext.LoadMask({msg:"Please wait...",target:Ext.ComponentQuery.query('#grid')[0]});
myMask.show();
But this doesn't seems to work.The same code is working for tab pannel. Please suggest the necessary changes in order to achieve load mask only for grid pannel.
//View code
Ext.define("DummyApp.view.grid.GenericGrid",{
extend: "Ext.panel.Panel",
requires: ['DummyApp.view.toolBar','DummyApp.view.formPanel','Ext.state.*','Ext.data.*'],
controller: "genericGrid",
alias:"widget.genericgrid",
initComponent: function(){
Ext.apply(this, {
items: [this.createToolbar(),this.createGrid()]
});
this.callParent(arguments);
},
createToolbar: function(){
this.toolbar = Ext.create('DummyApp.view.toolBar');
return this.toolbar;
},
createGrid: function(){
this.grid = Ext.create('Ext.grid.Panel',{
itemId: 'batchGrid',
columnLines : true,
selType: 'cellmodel',
autoScroll :true,
maxHeight:535,
stateId: 'GridPanel',
loadMask: true,
stateful: true,
bind:{
store:'{genericGrid}'
}
});
return this.grid;
}
//Controller code
renderData: function(genericGrid) {
var store = Ext.create("DummyApp.store.GenericGrid"),
gridId = genericGrid.up().gridId,
serviceInput = Util.createServiceResponse(gridId);
var myMask = new Ext.LoadMask({msg:"Please wait...",target: Ext.ComponentQuery.query('#grid')[0]});
myMask.show();
Ext.Ajax.request({
url: Util.localGridService,
method: 'POST',
headers: Util.createRequestHeaders(),
jsonData: {
getConfigurationAndDataRequestType: serviceInput
},
success: function(conn, response, options, eOpts) {
myMask.hide();
var data = Util.decodeJSON(conn.responseText);
store.setData(Util.formatGridData(data));
genericGrid.reconfigure(store, Util.formatGridMetaData(data));
},
failure: function(conn, response, options, eOpts) {
myMask.hide();
Util.showErrorMsg(conn.responseText);
},
scope: this
});
store.load();
}
Look at this, in your code grid have itemId is "batchGrid"(find by "#batchGrid"), your grid panel have alias is "genericgrid"(find by "genericgrid" because it is alias of component). Then just correct it, replace your itemId on correct name, but better for this using needed component for target
var myMask = new Ext.LoadMask({msg:"Please wait...",target: Ext.ComponentQuery.query('#batchGrid')[0]});
better
renderData: function(genericGrid) {
var store = Ext.create("DummyApp.store.GenericGrid"),
grid = genericGrid.down('#batchGrid') // get grid
...
var myMask = new Ext.LoadMask({msg:"Please wait...", target: grid /*or genericGrid for gridpanel*/ });
Fiddle

create/update user story using rally app sdk

Until now, I have been querying the data stores using Rally App SDK, however, this time I have to update a story using the js sdk. I tried looking up for examples for some sample code that demonstrates how the App SDK can be used to update/add values in Rally. I have been doing CRUD operations using Ruby Rally API but never really did it with the app sdk.
Can anyone provide some sample code or any link to where I could check it out?
Thanks
See this help document on updating and creating reocrds. Below are examples - one updates a story, the other creates a story. There is not much going on in terms of UI: please enable DevTools console to see console.log output.
Here is an example of updating a Defect Collection on a User Story:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch: function() {
console.log("launch");
Rally.data.ModelFactory.getModel({
type: 'User Story',
success: this._onModelRetrieved,
scope: this
});
},
_onModelRetrieved: function(model) {
console.log("_onModelRetrieved");
this.model = model;
this._readRecord(model);
},
_readRecord: function(model) {
var id = 13888228557;
console.log("_readRecord");
this.model.load(id, {
fetch: ['Name', 'Defects'],
callback: this._onRecordRead,
scope: this
});
},
_onRecordRead: function(record, operation) {
console.log('name...', record.get('Name'));
console.log('defects...', record.get('Defects'));
if(operation.wasSuccessful()) {
//load store first by passing additional config to getCollection method
var defectStore = record.getCollection('Defects', {
autoLoad: true,
listeners: { load: function() {
//once loaded now do the add and sync
defectStore.add({'_ref':'/defect/13303315495'});
defectStore.sync({
callback: function() {
console.log('success');
}
});
}}
});
}
},
});
Here is an example of creating a user story, setting a project and scheduling for an iteration:
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select an Iteration:',
labelWidth: 100,
width: 300
},
addContent: function() {
this._getIteration();
},
onScopeChange: function() {
this._getIteration();
},
_getIteration: function() {
var iteration = this.getContext().getTimeboxScope().record.get('_ref');
console.log('iteration',iteration);
if (!this.down('#b2')) {
var that = this;
var cb = Ext.create('Ext.Container', {
items: [
{
xtype : 'rallybutton',
text : 'create',
id: 'b2',
handler: function() {
that._getModel(iteration);
}
}
]
});
this.add(cb);
}
},
_getModel: function(iteration){
var that = this;
Rally.data.ModelFactory.getModel({
type: 'UserStory',
context: {
workspace: '/workspace/12352608129'
},
success: function(model) { //success on model retrieved
that._model = model;
var story = Ext.create(model, {
Name: 'story 777',
Description: 'created via appsdk2'
});
story.save({
callback: function(result, operation) {
if(operation.wasSuccessful()) {
console.log("_ref",result.get('_ref'), ' ', result.get('Name'));
that._record = result;
that._readAndUpdate(iteration);
}
else{
console.log("?");
}
}
});
}
});
},
_readAndUpdate:function(iteration){
var id = this._record.get('ObjectID');
console.log('OID', id);
this._model.load(id,{
fetch: ['Name', 'FormattedID', 'ScheduleState', 'Iteration'],
callback: function(record, operation){
console.log('ScheduleState prior to update:', record.get('ScheduleState'));
console.log('Iteration prior to update:', record.get('Iteration'));
record.set('ScheduleState','In-Progress');
record.set('Iteration', iteration);
record.set('Project', '/project/12352608219')
record.save({
callback: function(record, operation) {
if(operation.wasSuccessful()) {
console.log('ScheduleState after update..', record.get('ScheduleState'));
console.log('Iteration after update..', record.get('Iteration'));
}
else{
console.log("?");
}
}
});
}
})
}
});

ExtJs - Filter a grid with a search field in the column header

In ExtJs, there are many options to filter a grid. There are two nice examples in the documentation, like referenced in this question.
Remote filtering
Local filtering
However, having the filter hidden in the default dropdown menu of Ext.ux.grid.FiltersFeature looks really awkward for me. A good ergonomic choice would to create search fields in the column headers, like #Ctacus shows in his question.
How can this be achieved ?
After quite much research through the sparse documentation, and thanks to great questions and answers in SO, I came up with a simple class, that adds this functionality and and allows for configurations.
It looks like this:
You add this field in your grid like this:
Ext.define('Sandbox.view.OwnersGrid', {
extend: 'Ext.grid.Panel',
requires: ['Sandbox.view.SearchTrigger'],
alias: 'widget.ownersGrid',
store: 'Owners',
columns: [{
dataIndex: 'id',
width: 50,
text: 'ID'
}, {
dataIndex: 'name',
text: 'Name',
items:[{
xtype: 'searchtrigger',
autoSearch: true
}]
},
The following configs are possible, and work like described in the doc for Ext.util.Filter:
anyMatch
caseSensitive
exactMatch
operator
additionnaly you can use autoSearch. If true, the filter searches as you type, if false or not set, one has to click on the search icon to apply the filter.
ExtJs 5 / 6 Source:
Ext.define('Sandbox.view.SearchTrigger', {
extend: 'Ext.form.field.Text',
alias: 'widget.searchtrigger',
triggers:{
search: {
cls: 'x-form-search-trigger',
handler: function() {
this.setFilter(this.up().dataIndex, this.getValue())
}
},
clear: {
cls: 'x-form-clear-trigger',
handler: function() {
this.setValue('')
if(!this.autoSearch) this.setFilter(this.up().dataIndex, '')
}
}
},
setFilter: function(filterId, value){
var store = this.up('grid').getStore();
if(value){
store.removeFilter(filterId, false)
var filter = {id: filterId, property: filterId, value: value};
if(this.anyMatch) filter.anyMatch = this.anyMatch
if(this.caseSensitive) filter.caseSensitive = this.caseSensitive
if(this.exactMatch) filter.exactMatch = this.exactMatch
if(this.operator) filter.operator = this.operator
console.log(this.anyMatch, filter)
store.addFilter(filter)
} else {
store.filters.removeAtKey(filterId)
store.reload()
}
},
listeners: {
render: function(){
var me = this;
me.ownerCt.on('resize', function(){
me.setWidth(this.getEl().getWidth())
})
},
change: function() {
if(this.autoSearch) this.setFilter(this.up().dataIndex, this.getValue())
}
}
})
For ExtJs 6.2.0, the following bug and its workaround is relevant to this, else the column cannot be flexed.
ExtJs 4 Source:
Ext.define('Sandbox.view.SearchTrigger', {
extend: 'Ext.form.field.Trigger',
alias: 'widget.searchtrigger',
triggerCls: 'x-form-clear-trigger',
trigger2Cls: 'x-form-search-trigger',
onTriggerClick: function() {
this.setValue('')
this.setFilter(this.up().dataIndex, '')
},
onTrigger2Click: function() {
this.setFilter(this.up().dataIndex, this.getValue())
},
setFilter: function(filterId, value){
var store = this.up('grid').getStore();
if(value){
store.removeFilter(filterId, false)
var filter = {id: filterId, property: filterId, value: value};
if(this.anyMatch) filter.anyMatch = this.anyMatch
if(this.caseSensitive) filter.caseSensitive = this.caseSensitive
if(this.exactMatch) filter.exactMatch = this.exactMatch
if(this.operator) filter.operator = this.operator
console.log(this.anyMatch, filter)
store.addFilter(filter)
} else {
store.filters.removeAtKey(filterId)
store.reload()
}
},
listeners: {
render: function(){
var me = this;
me.ownerCt.on('resize', function(){
me.setWidth(this.getEl().getWidth())
})
},
change: function() {
if(this.autoSearch) this.setFilter(this.up().dataIndex, this.getValue())
}
}
})

Resources