I have a tab panel, and I perform a server request in it's initComponent method to add tabs according to the result. This process can take a long time, and I would like to display a progress bar during the begining of initComponent, till the end (before the callParent call method for example).
Is it possible to achieve this behaviour ?
Thanks a lot !
You can use a LoadMask on any pretty much any component, here is an example, there is also a fiddle:
Ext.application({
name: 'Fiddle',
launch: function() {
var store = Ext.create('Ext.data.JsonStore', {
storeId: 'simpsonsStore',
fields: ['name', 'email', 'phone'],
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json',
rootProperty: 'characters'
}
},
listeners: {
load: function() {
console.log(this);
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: store,
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
height: 200,
width: 400,
renderTo: Ext.getBody()
});
var myMask = new Ext.LoadMask(grid, {msg:"Please wait..."});
myMask.show();
var timeout = setTimeout(function() {
myMask.hide();
}, 5000);
}
});
I've added a setTimeout to replicate a long loading request, you do not need to use this.
You do not need to rely on "callParent" method. You have two options:
Make your server request synchronously. (by setting async:false for your ext.ajax call or for the related operation) It causes your code to be waited till the response comes.it blocks UI interaction but makes you sure having response immediately in line after server call
Another way is calling this.setLoading(true) before calling ajax call and setting this.setLoading(false) in your ajax/operation callback method. Note that this should refer to your main component. So it is bettor to save it in a variable at initComponent first line. For example by a line like var me= this;. After that refer to current main component bymeinstead ofthis`
var progressBar = Ext.create('Ext.ProgressBar');
progressBar.wait({
interval: 1000,
duration: 10000,
increment: 10,
text: 'Adding tabs...',
scope: this,
fn: function() {
var tabPanel = Ext.create('Ext.tab.Panel');
me.add(tabPanel);
tabPanel.add({
xtype: 'panel',
title: 'Main tab'
});
tabPanel.add({
xtype: 'panel',
title: 'Chunk'
});
tabPanel.add({
xtype: 'panel',
title: 'My girl'
});
progressBar.hide();
}
});
Fiddle
Related
I have an ExtJS 6.5.1 app and I am just now starting to migrate our app from MVC to MVVM, so I am pretty clueless about VM and VC.
I have a viewModel with an inline store like so:
Ext.define("MYAPP.view.ViewportViewModel",{
extend:"Ext.app.ViewModel",
alias: 'viewmodel.viewport',
constructor: function(config) {
var me = this;
this.callParent(arguments);
me.setStores({
info: {
autoLoad:true,
fields:["TEST"],
proxy:{
type:"ajax",
url:"blah.html",
reader:{
type:"json"
}
}
}
});
}
});
From inside my controller, how can I "get" the store so I can change the URL, reload, pass extraParams etc?
Thanks
You can get your store using this.getViewModel().getStore('info') inside of ViewController.
After getting store you can set another url using store.getProxy().setUrl(), load using store.load() and for sending extra params store.getProxy().extraParams.
Here is example
//this one way
store.load({
url: '{your url here}',
params: {
userid: 22216
}
});
//this another way
store.getProxy().setUrl('{your url here}');
store.getProxy().extraParams = {
userid: 22216
};
store.load();
In this FIDDLE, I have created a demo using view model and view controller. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('MyViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.myview',
onRefreshButtonTap: function () {
var info = this.getViewModel().getStore('info');
info.getProxy().setUrl('data2.json');
info.load();
}
});
Ext.define("ViewportViewModel", {
extend: "Ext.app.ViewModel",
alias: 'viewmodel.myvm',
constructor: function (config) {
var me = this;
this.callParent(arguments);
me.setStores({
info: {
autoLoad: true,
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: 'Binding Example',
renderTo: Ext.getBody(),
viewModel: {
type: 'myvm'
},
layout: 'vbox',
items: [{
xtype: 'grid',
flex: 1,
width: '100%',
bind: '{info}',
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
listeners: {
itemclick: 'onGridItemClick'
}
}],
tbar:[{
text:'Refresh',
handler:'onRefreshButtonTap'
}]
});
}
});
i have a grid panel (store and models are associated with it) where i am displaying all the data in row wise manner.The column of grid panel consist of action column where if person clicks, it opens a new form in tab style and user fills the data and it got saved in db. i want is, how the store should be refreshed every few second so that this data should also be displayed in the grid panel automatically. How should I do it?
There are a number of ways you could handle this, personally I would just reload the store when the form has closed to reload any updates rather than just reloading constantly.
The code below shows how you could use a TaskRunner in ExtJs to reload the store every x seconds, You could also add a setTimeout in the load event of the store so that every time the store loads you schedule it to load again in x seconds.
Ext.application({
name: 'Fiddle',
launch: function() {
var store = Ext.create('Ext.data.JsonStore', {
storeId: 'simpsonsStore',
fields: ['name', 'email', 'phone'],
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json',
rootProperty: 'characters'
}
},
listeners: {
load: function() {
console.log(this);
}
}
});
Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: store,
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
height: 200,
width: 400,
renderTo: Ext.getBody()
});
var runner = new Ext.util.TaskRunner(),
task = runner.start({
run: function() {
store.reload();
},
interval: 3000
});
// IMPORTANT: Dont forget to call stop at a logical point.
runner.stop();
}
});
There is also a fiddle containing this code that you can play around with.
If I had to go with the SetTimeout or TaskRunner options for this I would likely initialize them in the render event of the parent panel/container and listen for the beforeDestroy event to stop them running.
I have this very basic example where I use a memoryproxy and pagingmemory toolbar to paginate through data (ideally).
This is extjs working with meteor which sends data directly without the need of a res/ajax/jsonp proxy so I must use memory since the data is already in the client long before extjs has even managed to render it's views.
My problem is that I cannot make the pagination to show a real overview of what's in the store. The refresh is not working and the paginate icons are dead since the pagination sees no items in the store after I load them.
I have a working code example up on jsfiddle: http://jsfiddle.net/rXsVG/5/
Full code example:
Ext.onReady(function(){
Ext.define('User', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type: 'int'},
{name: 'name', type: 'string'}
]
});
var store = new Ext.data.Store({
model: 'User',
autoLoad: true,
proxy: {
type: 'pagingmemory',
reader: {
type: 'json'
}
}
});
Ext.create('Ext.grid.Panel', {
height: 500,
width: '100%',
renderTo: 'example-grid',
store: store,
columns: [{
header: 'Name',
dataIndex: 'name',
flex: 1
}],
bbar: {
xtype: 'pagingtoolbar',
pageSize: 10,
store: store,
displayInfo: true
},
listeners: {
afterrender: function(grid, evt) {
console.log('Loading data');
var data = [];
for(var i = 1; i < 20; i++) {
data.push({
id: i,
name: 'Ed Spencer '+i
});
}
// Simulate a really busy server call
setTimeout(function(){
grid.getStore().loadData(data);
}, 500);
}
}
});
});
Also if you hit refresh on the paging toolbar all data will be gone. Any ideas?
I have a controller and a view and want to push a line from a controller when item is selected.
Where it says onItemSelect: that's where I need to make a call, and don't know how...
Thank you.
controller is this:
Ext.define('Application.controller.ItemController', {
// Extend basic controller object
extend: 'Ext.app.Controller',
// Attach store classes to this controller
stores: ['Items'],
// Attach model classes to this controller
models: ['Item'],
// ..and last but not least - the view classes
views: ['item.List', 'item.Show'],
// Refs parameter defines references to certain
// instances of components pointed by selector
refs: [
{
// Ref determines the name of the automagic
// this.get[ref-goes-here] method that returns
// instance of certain component
ref : 'itemShowDesc',
// Select #item-description component in
// item.Show view
selector: 'itemShow > #item-description'
}
],
// when including the controllers in your application,
// the framework will automatically load the controller
// and call the init method on it
init: function() {
this.control({
'itemList' : {
// Action to be performed on select
select: this.onItemSelect
}
});
},
onItemSelect: function (selModel, selection) {
// Executed only when selection is a leaf
(selection.data.leaf) ? this.getItemShowDesc().addRow(selection.raw.description,'','','','','','') : null;
}
});
and the view is this:
Ext.define('Application.view.item.Show', {
extend: 'Ext.grid.Panel',
alias : 'widget.itemShow',
requires: [
'Ext.selection.CellModel',
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.form.*',
'Application.model.Item'
],
xtype: 'cell-editing',
title: 'Favorite Books',
frame: true,
initComponent: function() {
this.cellEditing = new Ext.grid.plugin.CellEditing({
clicksToEdit: 1
});
Ext.apply(this, {
width: 680,
height: 350,
plugins: [this.cellEditing],
store: new Ext.data.Store({
// destroy the store if the grid is destroyed
autoDestroy: true,
model: Application.model.Item,
proxy: {
type: 'ajax',
// load remote data using HTTP
url: 'resources/data/grid/books.xml',
// specify a XmlReader (coincides with the XML format of the returned data)
reader: {
type: 'xml',
// records will have a 'plant' tag
record: 'book'
}
},
sorters: [{
property: 'common',
direction:'ASC'
}]
}),
columns: [{
header: 'Book Id',
dataIndex: 'item_id',
width: 100
}, {
header: 'Author',
dataIndex: 'author',
width: 100
}, {
header: 'Title',
dataIndex: 'title',
width: 250
},{
header: 'Description',
dataIndex: 'description',
width: 495
},{
header: 'Price',
dataIndex: 'price',
width: 70,
align: 'right',
renderer: 'usMoney'
},{
xtype: 'actioncolumn',
width: 30,
sortable: false,
menuDisabled: true,
items: [{
icon: 'resources/images/icons/delete.gif',
tooltip: 'Delete Plant',
scope: this,
handler: this.onRemoveClick
}]
}],
selModel: {
selType: 'cellmodel'
}
});
this.callParent();
this.on('afterlayout', this.loadStore, this, {
delay: 1,
single: true
})
},
addRow: function(inItemID,inDisplay,inSex,inAuthor,inTitle,inDescription,inPrice){
// Create a record instance through the ModelManager
var r = Ext.ModelManager.create({
item_id: inItemID,
display: inDisplay,
sex: inSex,
author: inAuthor,
title: inTitle,
description: inDescription,
price: inPrice
}, 'Item');
store.insert(0, r);
cellEditing.startEditByPosition({row: 0, column: 0});
}
,
loadStore: function() {
this.getStore().load({
// store loading is asynchronous, use a load listener or callback to handle results
callback: this.onStoreLoad
});
},
onStoreLoad: function(){
Ext.Msg.show({
title: 'Store Load Callback',
msg: 'Favorites were loaded, data available for processing',
icon: Ext.Msg.INFO,
buttons: Ext.Msg.OK
});
},
onRemoveClick: function(grid, rowIndex){
this.getStore().removeAt(rowIndex);
}
})
Your ref for itemShowDesc is selecting a child component of itemShow. So when you do this.getItemShowDesc().addRow(), you're calling a method on whatever #item-description is, not on the Application.view.item.Show class.
I read in Ext JS in Action ( by J. Garcia) that if we have an instance of Ext.data.Record, we can use the form's loadRecord method to set the form's values. However, he does not give a working example of this (in the example that he uses data is loaded into a form through a file called data.php). I have searched many forums and found the following entry helpful as it gave me an idea on how to solve my problem by using form's loadRecord method:
load data from grid to form
Now the code for my store and grid is as follows:
var userstore = Ext.create('Ext.data.Store', {
storeId: 'viewUsersStore',
model: 'Configs',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/user/getuserviewdata.castle',
reader: {
type: 'json',
root: 'users'
},
listeners: {
exception: function (proxy, response, operation, eOpts) {
Ext.MessageBox.alert("Error", "Session has timed-out. Please re-login and try again.");
}
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
id: 'viewUsersGrid',
title: 'List of all users',
store: Ext.data.StoreManager.lookup('viewUsersStore'),
columns: [
{ header: 'Username', dataIndex: 'username' },
{ header: 'Full Name', dataIndex: 'fullName' },
{ header: 'Company', dataIndex: 'companyName' },
{ header: 'Latest Time Login', dataIndex: 'lastLogin' },
{ header: 'Current Status', dataIndex: 'status' },
{ header: 'Edit',
menuDisabled: true,
sortable: false,
xtype: 'actioncolumn',
width: 50,
items: [{
icon: '../../../Content/ext/img/icons/fam/user_edit.png',
tooltip: 'Edit user',
handler: function (grid, rowIndex, colIndex) {
var rec = userstore.getAt(rowIndex);
alert("Edit " + rec.get('username')+ "?");
EditUser(rec.get('id'));
}
}]
},
]
});
function EditUser(id) {
//I think I need to have this code here - I don't think it's complete/correct though
var formpanel = Ext.getCmp('CreateUserForm');
formpanel.getForm().loadRecord(rec);
}
'CreateUserForm' is the ID of a form that already exists and which should appear when user clicks on Edit icon. That pop-up form should then automatically be populated with the correct data from the grid row.
However my code is not working. I get an error at the line 'formpanel.getForm().loadRecord(rec)' - it says 'Microsoft JScript runtime error: 'undefined' is null or not an object'.
Any tips on how to solve this?
Rec is undefined in your EditUser function. You give an ID as parameter to your EditUser, you need to give the record to it as a parameter instead.
//The call
EditUser(rec);
function EditUser(rec) {
var formpanel = Ext.getCmp('CreateUserForm');
formpanel.getForm().loadRecord(rec);
}