ExtJS 4.1 stop grid.Panel from closing - extjs

I have I view that extends Ext.grid.Panel and I want to be able to ask the user if he really wants to close the panel after he clicks [X]. I tried with
listeners: {
beforedestroy: function() {
//console.log('In');
return false;
}
},
but obviously it's not that simple. Any ideas on how to prevent the closing of the panel?
Thanks
Leron
P.S.
This is what I get from sencha forums, haven't test it yet:
Ext.create( 'Ext.window.Window', {
title: 'test',
width: 200,
height: 200,
listeners: {
beforeclose: function( window ) {
Ext.Msg.confirm( 'Hey', 'Are you sure you want to close?', function( answer ) {
if( answer == "yes" ) {
window.destroy();
}
} );
return false;
}
}
} ).show();

beforeclose event should work. No?
Update:
If you want to have some user interaction (i.e. confirmation question or saving data or something like that) it will be a bit tricky...
First, in the constructor of the view do something like this:
this.on('beforeclose', function() {
return this.myCloseHandler(function() { this.close(); }, this);
});
this.alreadyAsked = false;
Than create handler:
myCloseHandler: function(callback, scope) {
if (this.alreadyAsked === false) {
this.alreadyAsked = true;
Ext.MessageBox.show({
msg: 'Are you sure?',
fn: function(btn) {
if (btn == 'yes')
Ext.callback(callback, scope);
else
this.alreadyAsked = false;
}
});
return false;
}
return true;
}
Idea is - you return false immediately but have some flag and condition to go through the same logic without confirmation.

The technique I use is simply to do a window hide rather than the default destroy of the window and add a beforehide event listener. This prevents that all the components in your window that you want to prevent to destroy, are destroyed anyway. The hide event is a quite innocent event to this with. Then the Ext.msg comes, maybe even only on a certain condition. And your response on the break message finished the job. Otherwise no harm done, because false is returned.
var win = Ext.create('Ext.window.Window', {
.... your window specs ...
closeAction : 'hide',
buttons : [{
text : 'Close',
scope : me,
handler : function() {
win.hide(); // not destroy !!! that comes later !!!
}
}],
listeners : {
scope : me,
'beforehide' : function(window) {
if (some_condition == true) {
Ext.Msg.confirm( 'Confirm close of window', 'You really wanna close this window ?', function( answer ) {
if( answer == "yes" ) {
window.destroy();
}
});
return false;
}
},
'destroy' : function(window) {
// do something after the window destruction //
alert('Another window smashed');
}
}
... rest of your window specs
});

Maybe there is no need in heavy constructions. The following works perfect for me:
beforeclose: function(window) {
Ext.Msg.confirm("Hey", "Are you sure you want to close?", function(answer) {
if (answer == "yes") {
window.events.beforeclose.clearListeners();
window.close();
}
});
return false;
}

Related

Stop program flow with Ext.Msg Extjs 4.1.1

As the title says, I need to capture the change event of a tab and show to the user a confirm message box. I achieved this but using the confirm JS native function. I'd like to perform this using ExtJS's Ext.Msg.show(), but the program flow does not stop with this way, as it does with confirm function. See below the two ways:
'Ext.Msg.show()' way:
onBeforeTabChange: function(panel, nextTab, oldTab)
{
var bReturn = true;
if (null != oldTab)
{
if(AppGlobals.isEditing=='si')
{
Ext.Msg.show(
{
title: 'Warning',
msg: 'Leave without saving changes?',
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.WARNING,
closable: false,
buttonText:
{
yes : 'Yes, sure',
no : 'No, will save changes first'
},
fn: function (buttonId)
{
if(buttonId=="yes")
{
AppGlobals.isEditing = 'no';
bReturn = true;
}
else
{
bReturn = false;
}
}
});
}
else
{
bReturn = true;
}
}
return bReturn;
}
As I said before, the code above does not stop the program flow. The alert appears but the tab changes anyway.
'confirm' way:
onBeforeTabChange: function(panel, nextTab, oldTab)
{
var bReturn = true;
if (null != oldTab)
{
if(AppGlobals.isEditing=='si')
{
bReturn = confirm('Leave without saving changes?');
if(bReturn==true)
{
AppGlobals.isEditing = 'no';
}
}
else
{
bReturn = true;
}
}
return bReturn;
}
The code above do work, and the tab does not change until user clicks on "Yes".
Any help? Thanks in advance.
Ext.Msg.show() is asynchronous and doesn't stop execution of the rest of program. The solution would be always return false from beforetabchange listener and programmatically change the tab when user press Yes.
A Sample Code: Here i have used allowChange as flag to prevent showing of message box when tab is changed programmatically. You can use you own flag here which i suppose is AppGlobals.isEditing
Ext.application({
launch: function() {
var allowChange = false;
Ext.create('Ext.tab.Panel', {
width: 300,
height: 200,
activeTab: 0,
items: [{
title: 'Tab 1',
bodyPadding: 10,
html: 'A simple tab'
},
{
title: 'Tab 2',
html: 'Another one'
}
],
renderTo: Ext.getBody(),
listeners: {
beforetabchange: function(tabPanel, nextTab, oldTab) {
var bReturn = true;
if (null != oldTab && !allowChange) {
bReturn = false;
Ext.Msg.show({
title: 'Warning',
msg: 'Leave without saving changes?',
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.WARNING,
closable: false,
buttonText: {
yes: 'Yes, sure',
no: 'No, will save changes first'
},
fn: function(buttonId) {
if (buttonId == "yes") {
allowChange = true; // to stop showing the message box again when tab is changed programmaticaly
tabPanel.setActiveTab(nextTab);
}
}
});
}
allowChange = false;
return bReturn; // always return false
}
}
});
}
});
<link rel="stylesheet" href="https://cdn.sencha.com/ext/gpl/4.1.1/resources/css/ext-all.css">
<script type="text/javascript" src="https://cdn.sencha.com/ext/gpl/4.1.1/ext-all-debug.js"></script>

disable row select extjs mvc

i am using checkboxmodel to select rows but i want to make some rows to be selection disabled based on some logic...
here is my what i am trying but 'beforeselect' function doesn't even fires
selModel: Ext.create('Ext.selection.CheckboxModel', {
checkOnly: true,
mode:'multi',
listeners: {
beforeselect:function(grid){
var grid=Ext.getCmp('mylist');
var selectionModel=grid.getSelectionModel();
var selectedRecords=selectionModel.getSelection();
var myValue=selectedRecords[0].get('nowreceive');
var myvalue1=selectedRecords[0].get('received');
if(myValue>myvalue1)
{return false;}
else
return true;
}} }
),
beforecellmousedown event in the view config works for me.This is done in the viewconfig of the grid...
viewConfig: {
listeners: {
beforecellmousedown: function(view, cell, cellIdx, record, row, rowIdx, eOpts){
var myvalue=record.get('quantity_ordered');
var myvalue1=record.get('quantity_received')
if(myvalue==myvalue1)
{
return false;
}
else {
return true;
}
}
}
},
How do you know the event is not firing? It should be, but my guess is that selectedRecords[0] is not defined and that crashes your execution, because getSelection() probably returns an empty array, before any selection has occurred.
What you should do is to use the second argument of beforeselect, which is the record that's going to be added to the selection.
So you can implement your listener in a much simpler way:
beforeselect: function (selModel, record) {
if (record.get('nowreceive') > record.get('received')) {
return false;
}
}

extjs4.1 textfield dblclick event not work in mvc

I work with mvc. When i double click on a textfield it not listening.
But specialkey that means enter work perfectly. where is my fault.
Here is my text field
{
xtype : 'textfield',
name : 'articleName',
fieldLabel : 'Article',
allowBlank : false,
readOnly : true,
width : 253,
enableKeyEvents : true
}
and here is my controller
sv01t01000102 textfield[name=articleName]':{
specialkey: function (field, el) {
if (el.getKey() == Ext.EventObject.ENTER || el.getKey()==el.TAB){
console.log('World')
}
},
dblclick : function(field, el){
console.log('Hello')
}
}
Can you help me?
Field doesn't have a double click event. Typically you'll do something like:
textfield[name=articleName]': {
afterrender: function(c) {
c.inputEl.on('dblclick', function() {
console.log('double');
});
}
}
'textfield[name = articleName]':{
render: function (component) {
component.getEl().on('dblclick', function(event, el) {
alert('You dblclicked on textfield!');
})
}
}
Just in case somebody stumbles over this and want's to solve it in the MVVM way.
View
{
xtype: 'textfield',
listeners: {
afterrender: view => {
view.getTargetEl().on('dblclick', 'onDblclick');
}
}
}
Controller
onDblclick() {
console.log(arguments) // Pick what you need
}

Migration from Sencha ExtJS 4.0 to ExtJS 4.1

I create a window like this:
_target = new Ext.Window({
layer: 'top',
width: _width,
height: _height,
constrainTo: aBody,
constrain: true,
renderTo: aBody,
autoScroll: true,
flex: 1,
modal: (targetParams.Modal != undefined) ? targetParams.Modal : false,
resizable: (targetParams.Resizable != undefined) ? targetParams.Resizable : true,
minimizable: (targetParams.Minimizable != undefined) ? targetParams.Minimizable : true,
maximizable: (targetParams.Maximizable != undefined) ? targetParams.Maximizable : true,
closable: (targetParams.Closable != undefined) ? targetParams.Closable : true,
maximized: _maximized,
minimzed: _minimized,
isInFront: true
});
and then do this:
_target.on("render", function (items) {
if (items.length > 0) {
this.show();
this.add(items);
this.doLayout();
var buttonText = targetParams.ButtonText || this.title;
createToolbarButton(this.id, buttonText, targetParams.UIConfigurationId);
} else {
_target.destroy();
}
});
The problem is on this line this.show();. On 4.0 this line calls this function
show: function() {
this.callParent(arguments);
this.performDeferredLayouts();
return this;
},
But on the 4.1 the same line calls another function:
show: function(animateTarget, cb, scope) {
var me = this;
if (me.rendered && me.isVisible()) {
if (me.toFrontOnShow && me.floating) {
me.toFront();
}
} else if (me.fireEvent('beforeshow', me) !== false) {
me.hidden = false;
if (!me.rendered && (me.autoRender || me.floating)) {
me.doAutoRender();
}
if (me.rendered) {
me.beforeShow();
me.onShow.apply(me, arguments);
if (me.ownerCt && !me.floating && !(me.ownerCt.suspendLayout || me.ownerCt.layout.layoutBusy)) {
me.ownerCt.doLayout();
}
me.afterShow.apply(me, arguments);
}
}
return me;
},
In which down the line tries to do layout.renderChildren() and then it gives an error.
I think it's obvious that the objects created are different, but i haven't seen this question addressed in the "Upgrade 4.0 to 4.1" document.
So my question is what i have to do to make this work?
Thanks in advance for the help.
UPDATE:
The app structure after adding the window would look something like this:
ViewPort
North
...
West
...
Center
Window
Panel
Panel
Label
...
BorderSplitter
Panel
Label
...
Panel
List
South
...
I've made some changes to the code and it doesn't generated that error anymore.
_target.on("beforeRender", function (items) {
if (items.length > 0) {
_target.add(items);
_target.doLayout();
var buttonText = targetParams.ButtonText || _target.title;
createToolbarButton(_target.id, buttonText, targetParams.UIConfigurationId);
} else {
_target.destroy();
}
});
_target.show();
_target.toFront();
But now it generates another when I call _target.add(items);.
The error is "Unable to get the value of property 'dom'" on this line
me.container = container.dom ? container : Ext.get(container);
I've tried to analyze the call stack and found out why it give this error. When it calls this function:
renderChildren: function () {
var me = this,
items = me.getLayoutItems(),
target = me.getRenderTarget();
me.renderItems(items, target);
},
where "this" refers to the layout object of the window, to where I'm adding the items, the call "getRenderTarget()" returns undefined. Then tries to access the dom property of undefined, throwing the error I mentioned above.
This is where I'm lost because, as you can see, when I'm creating the window I pass an object (aBody) to the renderTo property.
Any ideas??
It had to do with the layout. With layout 'fit' it seems to work.

ExtJS4: this.ownerCt in initComponent function

Is there any way to access the parent component (via this.ownerCt) in the initComponent function?
While trying to access it via this.ownerCt, i found out that the ownerCt attribute is set after initComponent. So I do not know how i can hook in the initialization process of my component where i can change some parent's attributes.
I know this doesn't answer the question directly. I would have placed this in the comments to your question but I'm not allowed yet it would appear. If you are building breadcrumbs. I would look at extending the tab panel and creating a plugin for the Tab Bar that creates the kinda of navigation you want.
Ext.define('HOD.plugins.Breadcrumbs', {
// private
init : function(tabBar) {
tabBar.on('beforeadd', this.addIcons, this);
tabBar.on('beforeremove', this.handleTabRemove, this);
},
addIcons: function(tabBar, newTab, index, options) {
if (index > 0) {
newTab.iconCls = 'icon-arrow';
tabBar.items.each(function(tab) {
if (tab != newTab) {
tab.overCls = 'breadcrumbs-over'
}
});
}
},
handleTabRemove: function(tabBar, oldTab, options) {
var count = tabBar.items.getCount();
if (count > 1) {
var newTab = tabBar.items.getAt(count-2);
newTab.overCls = '';
newTab.removeCls('x-tab-breadcrumbs-over');
}
}
});
Then extend the tab panel so it uses the above plugin to style the tabs correctly.
Ext.define('HOD.view.GlobalNavigation', {
extend: 'Ext.tab.Panel',
border: false,
alias: 'widget.content',
requires: ['HOD.plugins.Breadcrumbs'],
tabBar: {
cls: 'breadcrumbs',
plugins: ['tabbarbreadcrumbs']
},
initComponent: function() {
this.on('tabchange', this.handleTabChange, this);
this.callParent(arguments);
},
push: function(tab) {
this.add(tab);
this.setActiveTab(tab);
},
pop: function() {
// Get the current cards;
var cards = this.getLayout().getLayoutItems();
if (cards.length > 1) {
this.setActiveTab(cards[cards.length-2]);
}
},
handleTabChange: function (tabPanel, newCard, oldCard, options) {
var cards = tabPanel.getLayout().getLayoutItems();
for (var i = (cards.length - 1); i > 0; i--) {
if (cards[i] !== newCard) {
this.remove(cards[i]);
} else {
break;
}
}
}
});
I've written up post about it here if you need more detail.
I would not recommend changing anything in the container from the inside element functions. Instead I would create an event in the element, fire that event and listen for it in the container.
This way your component will notify the container to do something, and container will do it itself.

Resources