How to close modal window extjs when clicking on mask? - extjs

If I create a modal window:
Ext.define('myWindow', {
extend: 'Ext.Container',
alias: 'widget.myWindow',
floating: true,
modal: true,
listeners:
'onMaskClick???': { close the window }
.....
}
How do I know when a user has clicked on the mask outside the window? In Sench Touch, there is a config hideOnMaskTap that lets me specify. What is the event/config for extJS?

Tramway's case (sort of) works on modal or non modal windows. But not in case child components like the boundlist of a combobox float outside the windows boundaries.
However if you use modal windows anyway you can listen for a click event on the mask like this.
Ext.define('myWindow', {
extend: 'Ext.window.Window',
alias: 'widget.myWindow',
floating: true,
modal: true,
initComponent: function () {
var me = this;
me.callParent(arguments);
me.mon(Ext.getBody(), 'click', function(el, e){
me.close(me.closeAction);
}, me, { delegate: '.x-mask' });
}
});

You can listen all click events, then check if click position is out of the window
Ext.define('myWindow', {
extend: 'Ext.Container',
alias: 'widget.myWindow',
floating: true,
modal: true,
initComponent: function () {
this.initEvents();
this.callParent();
},
initEvents: function () {
//make sure your window is rendered and have sizes and position
if(!this.rendered) {
this.on('afterrender', this.initEvents, this, {single: true});
return;
}
this.mon(Ext.getBody(), 'click', this._checkCloseClick, this);
}
_checkCloseClick: function (event) {
var cx = event.getX(), cy = event.getY(),
box = this.getBox();
if (cx < box.x || cx > box.x + box.width || cy < box.y || cy > box.y + box.height) {
//clean up listener listener
this.mun(Ext.getBody(), 'click', this._checkCloseClick, this);
this.close();
}
}
}

You can try this also:
Ext.getBody().on('click', function(e, t){
var el = win.getEl();
if (!(el.dom === t || el.contains(t))) {
win.close();
}
});

I found adding a listener to the body and checking css classes felt a little hackey to me. You can actually override the private method _onMaskClick of Ext.ZIndexManager (see, completely not hackey). Which allows you to add your own configuration parameter (and even event) to all windows.
Ext.define('MyApp.ux.ZIndexManager_maskClick', {
override: 'Ext.ZIndexManager',
_onMaskClick: function ()
{
if (this.front)
{
var allowed = this.front.fireEvent('maskclick', this.front, this.mask);
if (allowed !== false && this.front.closeOnMaskClick)
this.front.close();
}
return this.callParent(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.

Ext JS add listener to button dynamically added

I have added buttons to a toolbar dynamically and now I am trying to add a listener that will replace the center window panel. I am having trouble hooking up the listener in viewcontroller.
This is how I have done it so far.
Can someone point me in the direction of the proper way to do this?
init: function () {
var dynamicMenu = [];
var me = this;
console.log(me);
console.log(this.view);
var myToolbar = this.view.down('toolbar');
console.log(myToolbar);
this.getViewModel().data.mainmenuv4store.load(function (records) {
console.log('hit load section');
Ext.each(records, function (record) {
//add individual button
var myButton = Ext.create('Ext.Button', {
text: record.get('text'),
iconCls: record.get('iconCls'),
iconAlign: 'left',
listeners: {
click: {
fn: function (event, target) {
me.selectMenuButton(event, target);
}
}
}
});
myButton.on({
click:
});
//add button to menu array
dynamicMenu.push(myButton);
});
//put this in storeLoad otherwise this section will be hit before loading everything
myToolbar.add(dynamicMenu);
});
},
selectMenuButton: function (event, target) {
Ext.Msg.alert('hi');
var targetCmp = Ext.get(target);
var id = targetCmp.getAttribute('text');
}
I changed my code to the below. Did I set this up efficiently?
Ext.define('ExtApplication1.controller.MainMenuV4ViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.mainmenuv4vc',
views: [
'ExtApplication1.view.main.MainMenuV4View'
],
init: function () {
var dynamicMenu = [];
var me = this;
console.log(me);
console.log(this.view);
var myToolbar = this.view.down('toolbar');
console.log(myToolbar);
this.getViewModel().data.mainmenuv4store.load(function (records) {
console.log('hit load section');
Ext.each(records, function (record) {
//add individual button
var myButton = Ext.create('Ext.Button', {
text: record.get('text'),
iconCls: record.get('iconCls'),
iconAlign: 'left',
handler: me.selectMenuButton, scope: me
});
//add button to menu array
dynamicMenu.push(myButton);
});
//put this in storeLoad otherwise this section will be hit before loading everything
myToolbar.add(dynamicMenu);
});
//listeners: {
// click: 'onProjectSelect'
// //click: {
// // fn: function (event, target) {
// // me.selectMenuButton(event, target);
// // }
// //}
//}
},
selectMenuButton: function (event, target) {
//Ext.Msg.alert('select menu button method hit');
console.log('select menu button section was hit')
console.log(event);
console.log(target);
}
Based on your comment on the question, it looks like you want a cleaner way to establish the listener. This is slightly cleaner:
Instead of listeners: {...}, use
handler: Ext.Function.bind(me.selectMenuButton, me)

Extjs: override specific listeners

I have a window component which I'm extending to create different windows. Now, the close() and hide() listener functions are the same across board, but the afterrender() changes with each instance.
So I have something like:
Ext.define('abc.xyz.BaseWindow', {
extend : "Ext.Window",
listeners: {
hide: function(el, eOpts){
console.log('hide');
},
close: function(el, eOpts){
console.log('close');
}
}
});
And:
Ext.define('abc.xyz.MyWindow', {
extend : "abc.xyz.BaseWindow",
listeners: {
afterrender: function(el, eOpts){
console.log('afterrender');
}
}
});
However, the whole listeners object is overridden and hide() and close() are never called. Is there any way around this, except to specify hide() and close() in every extended window?
You can define your functions in the window, call them and override them in the window like this:
Ext.define('abc.xyz.BaseWindow', {
extend : "Ext.Window",
onHide: function(){
console.log('hide');
},
onShow: function(el, eOpts){
console.log('close');
},
onAfterRender: function(el, eOpts){
console.log('first after render');
},
initComponent: function () {
var me = this;
Ext.applyIf(me, {
listeners: {
hide: me.onHide,
show: me.onShow
afterrender: me.onAfterRender
}
});
me.callParent(arguments);
}
});
And:
Ext.define('abc.xyz.MyWindow', {
extend : "abc.xyz.BaseWindow",
onAfterRender: function(el, eOpts){
console.log('second after render');
}
});
Or if you don't have an afterrender in the base class you just add a listener with (on) like Evan Trimboli sais
Ext.define('abc.xyz.MyWindow', {
extend : "abc.xyz.BaseWindow",
initComponent: function () {
var me = this;
me.callParent(arguments);
me.on('afterrender', function(el, eOpts){
console.log('second after render');
});
}
});

Extjs Chart Series ItemClick in Controller

I am creating a itemclick event of chart series items in extjs
"mychart series": {
itemclick: function() {
alert('s');
}
}
The above function does not work.
Chart series is not a Component, and so the selector never matches. You need to relay Series events as if they were fired by the Chart itself, and match against the Chart:
Ext.define('My.Chart', {
extend: 'Ext.chart.Chart',
alias: 'widget.mychart',
initComponent: function() {
var me = this;
me.callParent();
me.series.each(function(s) {
// This will relay Series `itemclick` event
// as `seriesitemclick` fired on the Chart itself
me.relayEvents(s, ['itemclick'], 'series');
});
}
});
Ext.define('My.Controller', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
mychart: {
seriesitemclick: this.onSeriesItemClick
}
});
},
onSeriesItemClick: function(item) {
var sprite = item.sprite,
series = item.series,
record = item.storeItem,
value = item.value;
...
}
});

ExtJS 4.2 resizable, draggable component

In my code I use MVC architecture. My view Component looks like this:
Ext.define('calendar.view.event', {
extend: 'Ext.Component',
alias: 'widget.event',
renderTo: Ext.getBody(),
initComponent:function(){
this.addEvents('eventClick');
this.callParent(arguments);
},
afterRender: function() {
this.mon(this.el, 'click', this.eventClick, this); //mon( item, ename, [fn], [scope], [options] ) - zkratka pro addManagedListener.
this.callParent(arguments);
},
eventClick: function (ev, t) {
var height = this.getHeight();
this.fireEvent('eventClick', this, height, ev);
}
});
Im firing Event on click for controller which is like this:
Ext.define('calendar.controller.eventsChange', {
extend: 'Ext.app.Controller',
views: ['event'],
init: function () {
this.control({
'event': {
eventClick: function (callerObject) {
this.editEvent(callerObject)
}
}
});
},
editEvent: function (callerObject) { //oznaci jako editovatelny
callerObject.get
if(callerObject.hasCls('SpecEv') || callerObject.hasCls('activeEvent'))
{
if (callerObject.hasCls('activeEvent'))
{
callerObject.removeCls('activeEvent');
callerObject.addCls('SpecEv');
this.application.fireEvent('reRender');
}
else
{
console.log(callerObject);
callerObject.addCls('activeEvent');
callerObject.removeCls('SpecEv');
Ext.apply(callerObject, {
resizable: {
pinned:true,
dynamic:true
},
draggable: true,
});
callerObject.setLocalX(0);
var parentWidth = Ext.getCmp('SpecEv').getWidth();
callerObject.setWidth(parentWidth);
}
}
}
});
The problem comes when with
Ext.apply(callerObject, {resizable: {
pinned:true,
dynamic:true
},
draggable: true,
});
When console.log shows me the object after my apply, it says draggable:true and resizable:true. Does anyone know where the problem is?
Thanks for reponses.
It can't works, because your code only set configuration properties, which are handled only when component is initializing. So when you set these properties on already constructed object nothing happen. Component resizability and draggability will not be initialized automatically after setting these properties.
You can try use Ext.Component initResizable and initDraggable methods. But these methods are internal and undocumented.
callerObject.initResizable({
pinned:true,
dynamic:true
});
callerObject.initDraggable();
Also you can try setup Ext.util.ComponentDragger and Ext.resizer.Resizer for your existing component manually.

Resources