ExtJS 4.2.1 resetting Stores on ViewChange - javascript

in my ExtJS application I want to reset the stores when I change the page.
Which means I don't want any filters, groupings or listener from any old view/page.
Currentyl I am setting the store of my view like this:
{
xtype: 'admingrid',
...
columns: [
...
],
store: 'appname.store.administration.User'
}
I am loading the store like that:
onAfterRender: function() {
//load all users
this.setUserStore(this.getUserGrid().getStore());
this.getUserStore().load();
},
and in some cases like this:
onAfterRender: function() {
//load all users
this.setUserStore(Ext.StoreManager.lookup('appname.store.administration.User'));
this.getUserStore().load();
},
all my my pages extends my Base view and so I thought I just do something like this:
Ext.define("appname.view.Base", {
extend: 'Ext.panel.Panel',
ui: 'basepanel',
padding: 15,
contentPaddingProperty: 'padding',
listeners: {
beforedestroy: function() {
Ext.StoreManager.each(function (item, index, len) {
item.clearFilter(true); // param: suppressEvent
item.clearGrouping();
item.clearListeners(); // this will also remove managed listeners
});
}
}
});
this will cause that the grid is sometimes empty when I am entering the view the first time... I don't understand why.. when I am entering the view the second or sometimes the third time it does show the grid with the entries..
Is there a common way to accomplish such a thing? What I am doing wrong? I don't understand why this is happening.

Just clear the store if it's present in your afterrender event. That way, you'll re-use the store and just clear it.
So in your afterrender, use StoreManager to lookup the store. If its present, it's been created before and you can clear it.
var store = Ext.StoreManager.lookup('storeid');
if(store) {
store.clearFilter(true);
store.clearGrouping();
}
This will clear the store whenever it's present.

Related

Ext JS: How to reload multiple stores?

I've defined several stores inside ViewModel and I've a button to reload all of them together. Instead of creating multiple var to assing with Ext.getStore('sampleStore'), I want to select all only with one var and using reload() only once.
Here is a not fully working snippet;
refreshPanel: function () {
// This way only one of stores is reloading, its sampleStore1.
var panelStores = Ext.getStore('sampleStore1', 'sampleStore2', 'sampleStore3');
panelStores.reload();
}
and here is stores which defined in ViewModel:
stores: {
// I've tried to give a storeId name but ofcourse did not work!
//storeId: 'adminbonus',
sampleStore1: {
storeId: 'sampleStore1',
...
},
sampleStore2: {
storeId: 'sampleStore2',
...
},
sampleStore3: {
storeId: 'sampleStore3',
...
},
},
//And using several formulas with chainedstore or bindTo configs
formulas: {}
Try something like that:
var panelStores = ['sampleStore1', 'sampleStore2', 'sampleStore3'];
Ext.each(panelStores, function(eachStore) {
var store = Ext.getStore(eachStore);
if(store){
store.reload();
}
}

ReactJS - What is the standard method of initializing jquery plugin in a react class?

I am using this plugin - bootstrap-dropselect
I have written initDropSelect function to initialize this plugin but I am not sure where to call this function as I would like to append some html to the DOM as soon as route is loaded. I am getting data from two different ajax calls. That data has to be compared and manipulated to append that html to the DOM(Code below 'Append to DOM' comment).
let UserPanel = React.createClass({
mixins: [LinkedStateMixin],
getStateFromStores: function() {
var users = UserStore.getAll();
// Some more code
return {
users: users
// Other properties
};
}
componentDidMount: function() {
UserStore.addChangeListener(this._onChange);
},
_onChange: function() {
this.setState(this.getStateFromStores());
},
initDropSelect: function() {
var _self = this;
var dropSelect = $('#dropselect-demo1').dropselect({
filter: {
show: true,
placeholder: 'Search for an item'
},
multiselect: true,
onselect: function(e, item) {
},
onunselect: function(e, item) {
},
onclear: function(e) {
}
});
// Append to DOM
if(this.state.tagsList.length > 0) {
if(this.state.newLoan.data.tags.length > 0) {
// Getting data from two different resources
}
}
}
});
Please help me in deciding where to call initDropSelect to manipulate data from multiple async requests and append that data to DOM.
P.S. I am using react router so there are two scenarios. First I may come to this route from other route or I can straightaway reload the current page.
Thanks in advance.
One way is for your render method to return something like a <div /> that you will then use to mount the jQuery component into. Once mounted, this will point to the DOM element that you would normally pass to jQuery.
Since jQuery will be handling the rendering, you then want to always return false from shouldComponentUpdate(). This will prevent React from thrashing your jQuery component.
You can then use componentDidMount() to initialize your jQuery component and componentWillReceiveProps() to update/re-render it when new data is passed in.

Kendo UI AngularJs grid directive, undefined

In a ticket entry page, I have a main ticketEntry.html page, which contains one grid for the lines and one for the payments.
When ticketEntry.html is loaded, it must first retrieve the ticket view model (via ajax calls to Web API). The line and payment grid cannot retrieve their data until the ticket view model has been received.
In my current solution, I have to use $timeout in the controller for ticketEntry.html for this to work. I am looking for a cleaner way.
Extracts from ticketEntry.html:
<div ng-controller="ticketLineController">
<div id="ticketLineGridDiv" kendo-grid="ticketLineGrid" k-options="ticketLineGridOptions"></div>
</div>
...
<div ng-controller="ticketPaymentController">
<div id="ticketPaymentGridDiv" kendo-grid="ticketPaymentGrid" k-options="ticketPaymentGridOptions"></div>
</div>
In the controller for ticketEntry.html, I have this:
$timeout(function () {
ticketService.getTicket(ticketId).then(
function(ticket) {
$scope.initPos(ticket);
},
...);
}, 500);
$scope.initPos = function(ticket) {
$scope.ticket = ticket; <-- $scope.ticket is used by the line and payment grid
$scope.$broadcast('PosReady'); <-- Tell the payment and line controllers to load their grids
}
As you can see, I am using $timeout to delay for 500ms, then I get the ticket view model and broadcast to the line and payment controller that they now can load their grids.
Here is the listener in the line controller:
$scope.$on('PosReady', function (event) {
$scope.ticketLineGrid.setDataSource(getGridDataSource());
$scope.ticketLineGrid.dataSource.read();
});
The problem is that if I do not use $timeout in the ticket entry controller, $scope.ticketLineGrid is sometimes undefined here (same thing with the payments controller).
I have tried using angular.element(document).ready(function () {...} instead of $timeout in the ticket entry controller, but that did not handle the issue.
How do I know when $scope.ticketLineGrid (for example) has been created/defined?
What is the proper way of handling this kind of scenario?
Update 9/27/2014, to provide more data on how the ticket line grid gets initialized:
In the AngularJs directive in ticketEntry.html, the k-options specifies the definition object for the grid:
<div id="ticketLineGridDiv" kendo-grid="ticketLineGrid" k-options="ticketLineGridOptions"></div>
ticketPaymentGridOptions is just an object with properties that defines the grid:
$scope.ticketPaymentGridOptions = {
autoBind: false,
height: 143,
columns: [
{
field: "payCode", title: "PayCode",
},
{
field: "amount", title: "Amount", format: "{0:n2}", attributes: { style: "text-align:right" },
},
],
pageable: false,
...
};
Update 9/29/2014: This is the solution I went with, based on suggestion by Valentin
I use two watches - one in the child scope where the ticketLineGrid lives:
$scope.$watch('ticketLineGrid', function (newVal) {
if (angular.isDefined(newVal)) {
$scope.ticketControl.lineGridReady = true;
}
});
This watch sets the parent property $scope.ticketControl.lineGridReady = true once the grid has been initialized.
The parent (ticketEntryController) has watches for lineGridReady:
$scope.$watch('ticketControl.lineGridReady', function (gridReady) {
if (gridReady) {
$scope.loadPage();
}
});
$scope.loadPage = function () {
ticketService.getTicket(ticketId).then(
function (ticket) {
$scope.initPos(ticket);
}
...
}
Not as clean as I would have liked it, but certainly better than using $timeout...
How do I know when $scope.ticketLineGrid (for example) has been created/defined?
You could use a $scope.$watch statement :
$scope.$watch('ticketLineGrid', function (newVal, oldVal) {
if(angular.isDefined(newVal)){
// do something with it
}
})
However, in my view the good way to do this is to retrieve the data not from a scope property, but from a promise. I would use only promises and no events at all for this :
var ticketPromise = ticketService.getTicket(ticketId);
ticketPromise.then(function (ticket) {
$scope.ticket = ticket;
});
// you know that part better than I do
var ticketLineGridPromise = ...;
$q.all([ticketPromise, ticketLineGridPromise])
.then(function (realizations) {
var ticket = realizations[0], ticketLineGrid = realizations[1];
$scope.ticketLineGrid.setDataSource(getGridDataSource());
$scope.ticketLineGrid.dataSource.read();
})
I can't be more precise because it's not clear from your code what initializes ticketLineGrid.
Finally, in many cases it's very handy to use resolve clauses in your route declaration.

Remove from a ComboBox a parameter in extjs 3.4

I want to remove a parameter from the store of a comboBox before it shows to the user, I know more or less how to do it but it´s not working properly, any one could give some solution? Maybe I need to select an specific event, but I tried with all the events that make sense and didn´t work, Here is the code:
var combo = fwk.ctrl.form.ComboBox({
storeConfig: {
url: app.bo.type.type_find
,fields: ['id', 'code']
}
,comboBoxConfig:{
triggerAction: 'all'
,allowBlank:false
}
});
combo.on('beforeshow', function() {
combo.store.removeAt(2);
});
Thank you very much!!!
Try removing it inside 'afterRender' event,
sample code:
listeners: {
'afterrender': function(comboRef) {
comboRef.store.removeAt(2);
}
}
Here you have the solution,
combo.getStore().load({
callback: function (r, options, success) {
if (success) {
combo.store.removeAt(2);
}
}
});
Is necessary to change it before the load of the store because first is painted the combobox and then is charged with the store data I was erasing data in a empty store.

ExtJs: determine grid that fires the update event on a store

i use a livegrid in ExtJs 3.3.1 but believe this question is global to ExtJs.
How does a listener on a store know which grid the event comes from ?
Here why and some code.
I have a listener on a store and on update i would like to know which rows were selected in the grid and also suspend the events. This all so that i can make a selection in the grid, update a field in that range and update that field in the whole selection. Selection is done without a checkbox, just by highlighting the rows. Since this listener is used by many grids i need a way to get it froml what the gridlistener gets as parameters but that is only store, record and action
Ext.override(Ext.ux.grid.livegrid.Store, {
listeners: {
'update': function(store, record, action) {
if (action=='commit'){ //each update has 2 actions, an edit and a commit
var selected = grid.getSelectionModel().getSelections(); //need to know which grid
if (selected.length>1){ //if more than one row selected
grid.suspendEvents();
store.writer.autoSave = false;
for(var i=0; i < selected.length; i++){
if (this.fieldChanged) {
for (var name in this.fieldChanged) {
//get the field changed and update the selection with the value
if (selected[i].get(name)!=this.fieldChanged[name]){
selected[i].set(name, this.fieldChanged[name]);
}
}
}
}
grid.resumeEvents();
store.fireEvent("datachanged", store);
store.writer.autoSave = true;
}
}
if (action=='edit'){
this.fieldChanged = record.getChanges()
}
}
}
});
It would be easier in an extension but it can be done in an override as well.
MyGridPanel = Ext.extend(Ext.ux.grid.livegrid.EditorGridPanel, {
initComponent: function(){
MyGridPanel.superclass.initComponent.call(this);
this.store.grid = this;
}
});
edit --- Showing how to do it in an override, it isn't pretty but it is useful.
var oldInit = Ext.ux.grid.livegrid.EditorGridPanel.prototype.initComponent;
Ext.override(Ext.ux.grid.livegrid.EditorGridPanel, {
initComponent: function(){
oldInit.call(this);
this.store.grid = this;
}
});
There may be more grids using the store. Preferably in Ext Js 4 you observe the Gridpanel class like so:
//Associate all rendered grids to the store, so that we know which grids use a store.
Ext.util.Observable.observe(Ext.grid.Panel);
Ext.grid.Panel.on('render', function(grid){
if (!grid.store.associatedGrids){
grid.store.associatedGrids=[];
}
grid.store.associatedGrids.push(grid);
});
Found a solution myself, i override the livegrid to include a reference to itself in its store like so
Ext.override(Ext.ux.grid.livegrid.EditorGridPanel, {
listeners: {
'afterrender': function(self) {
this.store.grid = this.id;
}
}
});
Then in my store listener i can refer to store.grid

Categories