Ext JS LoadMask does't cover the whole target - extjs

const store = Ext.create('Ext.data.Store', {
data: [{
firstname: "Michael",
lastname: "Scott"
}, {
firstname: "Dwight",
lastname: "Schrute"
}, {
firstname: "Jim",
lastname: "Halpert"
}, {
firstname: "Kevin",
lastname: "Malone"
}, {
firstname: "Angela",
lastname: "Martin"
}]
});
const grid = Ext.create('Ext.grid.Panel', {
title: 'Action Column Demo',
store: store,
columns: [{
text: 'First Name',
dataIndex: 'firstname',
width: 150,
locked: true, // locked column will trigger the LoadMask bug.
}, {
text: 'Last Name',
dataIndex: 'lastname',
width: 200,
}, ],
width: 300,
renderTo: Ext.getBody()
});
new Ext.LoadMask({
target: grid,
}).show();
If grid has locked column, LoadMask does't cover the whole grid, some one can help me to fix this issue?
If the grid has no locked column, everything is ok, but once to set any column to locked, this bug will happen.
Here is the demo: https://fiddle.sencha.com/#view/editor&fiddle/3kr3
Thanks!

This is done on purpose by the framework (not sure why). Check the afterInjectLockable method in Ext.grid.locking.Lockable. It goes like this:
afterInjectLockable: function() {
var me = this;
// Here we should set the maskElement to scrollContainer so the loadMask cover both views
// but not the headers and grid title bar.
me.maskElement = 'scrollContainer';
if (me.disableOnRender) {
me.on('afterrender', function() {
me.unmask();
}, { single: true });
}
delete me.lockedGrid.$initParent;
delete me.normalGrid.$initParent;
},
You can see that maskElement is set to "scrollContainer".
You could create an override to set it back to "el".
Something like this:
Ext.define(null, {
override: 'Ext.grid.locking.Lockable',
afterInjectLockable: function () {
this.callParent(arguments);
this.maskElement = 'el';
},
});
Fiddle: https://fiddle.sencha.com/#view/editor&fiddle/3krr

Try this :
var myPanel = new Ext.panel.Panel({
renderTo : document.body,
height : 100,
width : 200,
title : 'Foo'
});
var myMask = new Ext.LoadMask({
msg : 'Please wait...',
target : myPanel
});
myMask.show();
myMask.stop();
Hope this is helpful for you.

Related

Add record to the store and display on the grid

I have AddRecord method, that should add the record to the store and display on the grid that record.
I've put the form inside the window, and that is fine.
I was looking at the documentation but I got lost a bit.
There is a fiddle created.
Here is the fiddle: https://fiddle.sencha.com/#view/editor&fiddle/2tuf
AddRecord: function (grid, rowId, record) {
Ext.create('Ext.window.Window', {
title: "Add Person",
height: 200,
width: 400,
closeAction: 'hide',
closable: true,
items: [{
xtype:'form',
defaultType: 'textfield',
layout: 'anchor',
items: [{
fieldLabel: 'First Name',
name: 'First Name',
type: 'String',
allowBlank: false
}, {
fieldLabel: 'Last Name',
name: 'Last Name',
type: 'String',
allowBlank: false
}, ],
buttons: [{
text: 'Add',
formBind: true,
disabled: true,
handler: function () {
var record = Ext.getStore().getAt(rowId);
var store = grid.getStore('store.Personal')
var form = this.up('form').grid.getStore();
if (form.isValid()) {
form.add({
success: function (record) {
var store = grid.getStore('store.Personal')
store.add(record);
},
})
}
},
}, {
text: 'Close', handler: function () {
this.up('window').close();
}
}],
}]
}).show();
}
});
You were almost there, You made a little confusion about grid.getStore(), as it just
Returns the store associated with this Panel.
and how you are getting your form values, I think you were trying to do something like this:
buttons: [{
text: 'Add',
formBind: true,
disabled: true,
handler: function(button) {
let formValues = this.up('form').getForm().getValues(); //get the form Values
let form = this.up('form').getForm(); //get the form itself
var store = grid.getStore(); //get Store of your grid
if (form.isValid()) {
//add the formvalues to store
store.add(formValues);
}
},
}]
I also made a Fiddle

ExtJS - Grid multiple value filter in same column

Needed help in filtering grid with multiple values.
I am trying to create a menucheckitem with many phone value.
And filter the grid based on the phone Checked.
By using below code, i am able to filter grid based on single value.
store.filter([{
property: 'type',
value: value
}]);
Now i wanted to filter grid, even if i select many phone checkBoxs.
I tried using store.filterBy(). But, not working properly, i do not know what i am doing wrong.
var test = ["111-222-333","111-222-334","111-222-335"]
store.filterBy(function(record, val){
return test.indexOf(record.get('phone')) != -1
}
});
This filters the first value only i.e. "111-222-333" value only.. Not filtering all other value in test.
find sample code in here -
https://fiddle.sencha.com/#view/editor&fiddle/2ll7
So i forked your fiddle, remade it and i think i have achieved what you wanted. First of all your definition of menucheckitem in bbar was kind of strange. I think you needed a list of phones which would be checkboxes, but the list is depends on the store records, so it needs to be build dynamically (as i did it in afterrender). Actually this must be inside of store's load event, but in example it didn't fire(maybe bcz it is a memory type of store). Anyway when you copy the code you'll need to put all of the afterrender content inside the store load event.
FIDDLE
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: {
fields: ['name', 'email', 'phone', 'type'],
data: [{
name: 'Marge',
email: 'marge#simpsons.com',
phone: '111-222-334',
type: 'Foo'
}, {
name: 'Homer',
email: 'homer#simpsons.com',
phone: '111-222-333',
type: 'Foo'
}, {
name: 'Marge',
email: 'marge#simpsons.com',
phone: '111-222-334',
type: 'Foo'
}, {
name: 'Bart',
email: 'bart#simpsons.com',
phone: '111-222-335',
type: 'Bar'
}, {
name: 'Bart',
email: 'bart#simpsons.com',
phone: '111-222-335',
type: 'Bar'
}, {
name: 'Lisa',
email: 'lisa#simpsons.com',
phone: '111-222-336',
type: 'Bar'
}]
},
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email'
}, {
text: 'Phone',
dataIndex: 'phone'
}, {
text: 'Type',
dataIndex: 'type'
}],
listeners: {
afterrender: function (grid) {
var store = grid.store;
var phones = store.getData().items.map(function (r) { //get the phones
return r.get('phone');
});
var phonesFiltered = [];
phones.forEach(function (p) { //filter them to make records unique
if (!phonesFiltered.includes(p)) {
phonesFiltered.push(p);
}
});
var items = [];
phonesFiltered.forEach(function (p) { //create `menucheckitem` items with phone names and attaching `checkchange` event
items.push({
xtype: 'menucheckitem',
text: p,
listeners: {
checkchange: function (checkbox, checked, eOpts) {
var menu = checkbox.up('menu');
var filterPhones = [];
menu.items.items.forEach(function (c) { //get all checked `menucheckitem`-s
if (c.checked) {
filterPhones.push(c.text);
}
});
var store = checkbox.up('grid').store;
store.clearFilter();
if (filterPhones.length > 0) {
store.filterBy(function (record) {
return this.filterPhones.indexOf(record.get('phone')) !== -1;
}, {
filterPhones: filterPhones
});
}
}
}
});
});
//
Ext.getCmp('toolbarId').add({
xtype: 'menu',
// height: 120,
floating: false,
items: items
});
}
},
bbar: {
xtype: 'toolbar',
height: 200,
id: 'toolbarId'
},
renderTo: Ext.getBody()
});
}
});

In ExtJS 6, How to Get ViewModel data to work before panel loads

I'm having trouble with timing. I understand why in my example below and on fiddle that the page shows, then disappears. That is because the model data changes the hidden property after the panel has displayed, then it hides the panel. I want to figure out how to have the panel know about the model data before it loads.
https://fiddle.sencha.com/#fiddle/19m1
Ext.application({
name : 'MyApp',
launch : function() {
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
viewModel: {
people: [],
data: {
hidePanel: true
}
},
bind: {
data: '{people}',
hidden: '{hidePanel}',
},
border: 3,
width: 300,
height: 150,
title: 'XTemplate Data Binding Example',
tpl: [
'<tpl for=".">',
'First Name: {fName} <br>',
'Last Name: {lName}',
'<hr>',
'</tpl>'
],
autoScroll: true, // add scroll bar if necessary
title: 'Details'
});
var pnl = Ext.create('MyApp.view.MyPanel', {
renderTo: Ext.getBody()
});
pnl.getViewModel().set('people',[
{fName: 'Steve', lName: 'Drucker', bonus: 5},
{fName: 'Jason', lName: 'Perry', bonus: 7},
{fName: 'Tracey',lName: 'Dunn', bonus: 8},
]);
}
});
*** Proposed answer by Robert Watkins?
I believe below is what Robert Watkins is proposing. That is, not using bind with the hidden property but looking at the hidden property in the afterrender event.
https://fiddle.sencha.com/#fiddle/19m7 (updated fiddle)
Ext.application({
name : 'MyApp',
launch : function() {
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
viewModel: {
people: [],
data: {
hidePanel: true
}
},
listeners: {
afterrender: function(sender) {
if (this.getViewModel().data.hidePanel != true) {
this.show();
}
}
},
hidden: true,
bind: {
data: '{people}'
//hidden: '{hidePanel}',
},
border: 3,
width: 300,
height: 150,
title: 'XTemplate Data Binding Example',
tpl: [
'<tpl for=".">',
'First Name: {fName} <br>',
'Last Name: {lName}',
'<hr>',
'</tpl>'
],
autoScroll: true, // add scroll bar if necessary
title: 'Details'
});
var pnl = Ext.create('MyApp.view.MyPanel', {
renderTo: Ext.getBody()
});
pnl.getViewModel().set('people',[
{fName: 'Steve', lName: 'Drucker', bonus: 5},
{fName: 'Jason', lName: 'Perry', bonus: 7},
{fName: 'Tracey',lName: 'Dunn', bonus: 8},
]);
}
});
The actual problem is that panel will get rendered and made visible before the view model data is bound to the panel. That's why you get the beat - panel is made, shown, and then hidden.
ViewModel data is applied to the bound values in as close to a background thread as you can get in JavaScript - in a scheduled task set to happen ASAP, or as soon as the browser is idle. This will be after the panel is rendered.
The simplest solution is to hide by default. That way, if it's meant to stay invisible, it will, and if it's meant to become visible, it will be shown on the beat.
Example:
Ext.define('MyApp.view.MyPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
viewModel: {
people: [],
data: {
hidePanel: true // determine if the panel should be hidden or not.
}
},
bind: {
data: '{people}',
hidden: '{hidePanel}', // add the binding to make the panel visible or not.
},
hidden: true, // make it hidden by default.
....
}
You can use a formula for hidePanel, like:
viewModel: {
formulas: {
hidePanel: function(getter){
var people = getter('people');
return !people;
}
}
}
Working example: https://fiddle.sencha.com/#fiddle/19mb

two window objects in extjs

I have these two windows defined as shown below. The functionality that I desire is that initially the grid window should be hidden and the login window should be shown. After the user logs in, the login window should be hidden and the grid window should be shown.
var store = new Ext.data.Store({
url: 'sheldon.xml',
reader: new Ext.data.XmlReader({
record: 'Item',
fields: [
{name: 'Title'},
{name: 'Author'},
{name: 'Manufacturer'},
{name: 'ProductGroup'}
]
})
});
LoginWindow = {};
gridWindow = {};
gridWindow.grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header: "Title", width: 120, dataIndex: 'Title', sortable:true},
{header: "Author", width: 180, dataIndex: 'Author', sortable: true},
],
height:200,
viewConfig: {
forceFit:true
}
});
gridWindow = {
xtype: 'window',
id: 'grid',
title: 'Grid',
anchor: '30% 25%',
items:[gridWindow.grid],
frame:true,
layout:'card',
};
LoginWindow.loginForm = {
xtype:'form',
// url:'check.php',
frame: true,
labelAlign:'right',
labelWidth: 70,
items:[
{
xtype:'textfield',
fieldLabel:'Username',
anchor: '100%'
},
{
xtype:'textfield',
fieldLabel:'Password',
inputType:'password',
anchor: '100%',
}
],
buttons:[
{
text:'Login',
handler:
// Dummy function
function(btn, objc) {
Ext.getCmp('loginwindow').hide();
Ext.getCmp('grid').show();
store.load();
},
},
{
text:'Cancel',
handler:function(btn, objc) {
btn.findParentByType('form').getForm().reset();
}
}
]
};
LoginWindow = {
xtype: 'window',
id: 'loginwindow',
title: 'Please Log In',
anchor: '30% 25%',
activeItem: 0,
items:[LoginWindow.loginForm],
frame:true,
layout:'card',
bodyStyle:{}
};
Ext.onReady(function() {
var viewport = new Ext.Viewport({
layout: 'anchor',
items:[
LoginWindow
]
});
Ext.getCmp('loginwindow').show();
Ext.getCmp('grid').hide();
});
When I load the page, I get the error Ext.getcmp('grid') is undefined in firefox.
Could someone please help me out here...
Your gridWindow only exists as an object literal (aka xtype config object) and is never 'instantiated' (created). Therefore Ext.getCmp cannot find it, because it doesn't 'exist' yet and hasn't been registered with Ext.ComponentManager.
You could add it to the Viewport and add hidden:true to its config definition so it doesn't show up.
gridWindow = {
xtype: 'window',
id: 'grid',
title: 'Grid',
anchor: '30% 25%',
items:[gridWindow.grid],
frame:true,
layout:'card',
};
Ext.onReady(function() {
var viewport = new Ext.Viewport({
layout: 'anchor',
items:[
LoginWindow, gridWindow
]
});
// no need
//Ext.getCmp('loginwindow').show();
//Ext.getCmp('grid').hide();
});
Note: you might also need to call doLayout() on your viewport in your login handler after showing/hiding the components.
Looks like you first define LoginWindow.loginForm, but then redefine LoginWindow with a new object.
LoginWindow.loginForm = {
xtype:'form',
// url:'check.php',
LoginWindow is now set to an object literal with one property loginForm.
{
loginForm: [object]
}
Followed by
LoginWindow = {
xtype: 'window',
id: 'loginwindow',
This will create a completely new object and assign it to LoginWindow. The loginForm property is nowhere to be seen anymore ;)

extjs remove/readd textfield to form bug?

I have a form where i have a radiogroup 'yes', 'no'.
When i click on 'yes' i got a textfield added to a fieldset on the form with the config option: allowBlank: false. So there is validation on the field. When I click on 'no' all fields are removed from the fieldset that is present on the form.
The problem is when the validation is active, so when you go inside the textfield and you click away from it without entering any characters into it and i click on the radiobutton 'no' the textfield disappears and gives me the following error when i catch it:
Element.alignToXY with an element that doesn't exist
When i click afterwards on the radiobutton 'yes', the textfield is shown again BUT i get an error:
TypeError: dom is undefined
I could catch these errors and do nothing with it because in fact the form seems to be working, the textfields got added and removed like it should, there are only errors present and i don't like the concept of it. Does anyone has a clue why this error occurs and how to get rid of it so it's working 100% properly?
Here is an example of the code:
var radiogroup = new Ext.form.RadioGroup({
fieldLabel: 'Radio group test',
allowBlank: false,
anchor: '85%',
items: [{
boxLabel: 'Yes',
name: 'radio',
inputValue: 1
}, {
boxLabel: 'No',
name: 'radio',
inputValue: 2
}],
listeners: {
change: function (rg, radio) {
if (radio.inputValue == 1) {
var textfield_test = new Ext.form.TextField({
fieldLabel: 'Test',
allowBlank: false,
id: 'test',
name: 'test',
anchor: '85%',
width: 320,
helpText: 'test'
});
textfield_fieldset.insert(textfield_fieldset.items.length, textfield_test);
} else {
try {
txt_test = Ext.getCmp('test');
if (txt_test) {
textfield_fieldset.remove(txt_test);
}
textfield_fieldset.doLayout();
} catch (err) {
alert(err);
}
}
}
}
});
I've done this successfully not just for one textbox, but for an entire panel, and it works pretty well. In my case, any number of panel can be added and removed dynamically and it works pretty well. The relevant code that I used were:
panel.insert(medIndex,getNewPanel());
panel.doLayout();
And for remove i used,
var cmp = Ext.getCmp('Panel-' + Id);
if (cmp) {
treatment.remove(cmp, true); // True is the autoDestroy option.
}
These two in combination works for me. Though I would suggest that if you're doing this only for one textbox, then convert it into a hidden field and disable it. When you disable a field, it does not get submitted in a post, or ajax post request.
Hope this helps.
first, why did you re-add/re-remove a component like that?,..
if i was you... i will use the hide / show method of textfield class..
after read your code, i assuming that you are make a formPanel with 2 items (radiogroup and fieldset) where in the fieldset, there is a textfield... so, guestly.. mybe like this ??
var radiogroup = new Ext.form.RadioGroup({
fieldLabel: 'Radio group test',
allowBlank: false,
anchor: '85%',
items: [
{
boxLabel: 'Yes',
name: 'radio',
inputValue: 1},
{
boxLabel: 'No',
name: 'radio',
inputValue: 2}
],
listeners: {
change : function(a,b){
if (b.inputValue==1){
Ext.getCmp("textfield").enable();
Ext.getCmp("textfield").show();
}else{
Ext.getCmp("textfield").disable(); // set disable to prevent send empty data
Ext.getCmp("textfield").hide();
}
}
}
});
var formPanel = new Ext.form.FormPanel({
url : 'www.google.com',
method : "GET",
layout:'column',
frame :true,
border : false,
items : [
radiogroup,
{
xtype:'fieldset',
id : 'test',
title: 'Fieldset',
collapsible: true,
height : 200,
width : 350,
items :[{
xtype : "textfield",
id : 'textfield',
fieldLabel : "input data",
name : "text",
hidden:true,
disabled:true
}]
}
]
});
var win = new Ext.Window({
title : "holla",
width : 400,
height: 300,
border : false,
layout:'fit',
items : [formPanel]
});
win.show();
I created a jsfiddle to answer this question. The textfield seemed to get added / removed properly there: http://jsfiddle.net/jaycode/PGSb7/4/
Cheers.
Edit: For completeness, I guess I'll just post the code here as well
HTML
<div id="radios"></div>
<div id="textfield_fieldset"></div>
JS
var textfield_fieldset = new Ext.form.FieldSet({
renderTo: 'textfield_fieldset',
});
var radiogroup = new Ext.form.RadioGroup({
renderTo: 'radios',
width: 200,
height: 60,
fieldLabel: 'Radio group test',
allowBlank: false,
layout: {
type: 'vbox'
},
items: [
{
boxLabel: 'Yes',
name: 'radio',
inputValue: 1
},
{
boxLabel: 'No',
name: 'radio',
inputValue: 2
}
],
listeners: {
change: function(rg, radio) {
if (rg.lastValue.radio == 1) {
var textfield_test = new Ext.form.TextField({
fieldLabel: 'Test',
allowBlank: false,
id: 'test',
name: 'test',
anchor: '85%',
width: 320,
helpText: 'test'
});
textfield_fieldset.insert(textfield_fieldset.items.length, textfield_test);
} else {
txt_test = Ext.getCmp('test');
if (txt_test) {
textfield_fieldset.remove(txt_test);
}
textfield_fieldset.doLayout();
}
}
}
});

Resources