ExtJS 4.1 event delegation not working - extjs

I am using extjs 4.1 and trying to do the event delegation which in my case is to attach a blur event to all the textfields of my form and it is not working and i am not getting any error in firebug too, i don't know where i am going wrong in attaching the event, is it the wrong place where i am putting the code and also i have noticed that as per the docs below link:
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.form.Panel-method-on
the delegate property of the options object no longer exists. Below is my code:
Ext.onReady(function () {
var loadForm = function () {
Ext.getCmp('TestForm').getForm().setValues({ name: 'some text', email: 'first', dob: '12/12/2009' });
}
Ext.define('userForm', {
extend: 'Ext.form.Panel'
, alias: 'widget.userform'
, frame: true
, initComponent: function () {
Ext.apply(this, {
title: 'User Form'
, height: 350
, items: [{
xtype: 'textfield'
, fieldLabel: 'Name'
, name: 'name'
, id: 'nameId'
, enableKeyEvents: true
}, {
xtype: 'textfield'
, fieldLabel: 'Email'
, name: 'email'
, id: 'emailId'
}, {
xtype: 'datefield',
fieldLabel: 'DOB',
id: 'dob',
name: 'dob',
format: 'Y-m-d'
}, {
xtype: 'textfield',
fieldLabel: 'Age',
id: 'age',
name: 'age'
}, {
xtype: 'textfield',
fieldLabel: 'Guardian',
id: 'guardian',
name: 'guardian'
}]
});
this.callParent(arguments);
} //eoinitComponent
});
var userForm = Ext.create('userForm', {
renderTo: 'loadPanel',
id: 'TestForm',
listeners: {
afterrender: function (formCmp, eOpts) {
loadForm();
},
render: function (formCmp, eOpts) {
Ext.getCmp("TestForm").on(
'blur',
function (e, t) {
// handle blur
console.info(t.id);
},
this,
{
// filter the target element to be a descendant with the class '.x-form-field'
delegate: '.x-form-field'
}
);
}
}
});
});

To begin with, the on method does not take delegate as a parameter, so that line is completely unnecessary.
Then, within your render event, you can just use formCmp.on() rather than Ext.getCmp().on().
Lastly, you want blur event on every field, not on the form itself. The following code should work:
render: function (formCmp, eOpts) {
// For each field.
formCmp.getForm().getFields().each( function( aField ) {
// If it's a textfield.
if ( aField.is('textfield') ) {
aField.on( 'blur', this.onFieldBlur, this)
}
}, this ); // notice the this scope for the each method.
}

Related

Not able to access object from data in ViewModel

Am trying to fetch the persondetails details into enableButton method.
Am aware that we can achieve this by simply adding key and value to data object.
But my question here is, is there any way to store data into persondetails and fetch it?
If I specify as below and bind accordingly, then its wok fine.
data: {
firstname: '',
lastname: ''
}
bind: {
value: '{lastname}'
},
Here is the code:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.userinfo',
data: {
persondetails:{
firstname: '',
lastname: ''
}
},
formulas: {
enableButton: function(get){
debugger;
if(get('firstname')!=='' && get('lastname')!=='' ){
return true;
}else{
return false;
}
},
fullName: function(get){
if(get('firstname')!=='' && get('lastname')!=='' ){
return get('firstname') + ' ' + get('lastname');
}
}
}
});
Ext.create('Ext.form.Panel', {
title: 'Contact Info',
width: 500,
bodyPadding: 10,
renderTo: Ext.getBody(),
viewModel:{
type:'userinfo'
},
items: [{
xtype: 'textfield',
name: 'firstname',
emptyText: 'Enter First Name',
bind: {
value: '{persondetails.firstname}'
},
}, {
xtype: 'textfield',
name: 'lastname',
emptyText: 'Enter Last Name',
bind: {
value: '{persondetails.lastname}'
},
}, {
xtype: 'button',
reference: 'clickme',
disabled: true,
bind: {
disabled: '{!enableButton}'
},
text: 'Click',
listeners: {
click: function(){
alert('{fullName}');
}
}
}, {
xtype: 'displayfield',
fieldLabel: 'Full Name',
bind: {
value: '{fullName}'
}
}]
});
}
});
I have created a fiddle Example
According to documentation
When a direct bind is made and the bound property is an object, by
default the binding callback is only called when that reference
changes. This is the most efficient way to understand a bind of this
type, but sometimes you may need to be notified if any of the
properties of that object change.
To do this, we create a "deep bind":
In other words, if a object changes its properties, the viewmodel will not notify these changes (although their properties are changed correctly).
If you need to listen this changes, you need to use deep binding
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.userinfo',
data: {
persondetails: {
firstname: '',
lastname: ''
}
},
formulas: {
enableButton: {
bind: {
bindTo: '{persondetails}',
deep: true // listen to any change in personaldetails
},
get: function (data) {
return data.firstname && data.lastname
}
},
fullName: {
bind: {
bindTo: '{persondetails}',
deep: true // listen to any change in personaldetails
},
get: function (data) {
return data.firstname + ' ' + data.lastname
}
},
}
});
Ext.create('Ext.form.Panel', {
title: 'Contact Info',
width: 500,
bodyPadding: 10,
renderTo: Ext.getBody(),
viewModel:{
type:'userinfo'
},
items: [{
xtype: 'textfield',
name: 'firstname',
emptyText: 'Enter First Name',
bind: {
value: '{persondetails.firstname}'
},
}, {
xtype: 'textfield',
name: 'lastname',
emptyText: 'Enter Last Name',
bind: {
value: '{persondetails.lastname}'
},
}, {
xtype: 'button',
reference: 'clickme',
disabled: true,
bind: {
disabled: '{!enableButton}'
},
text: 'Click',
listeners: {
click: function(){
alert('{fullName}');
}
}
}, {
xtype: 'displayfield',
fieldLabel: 'Full Name',
bind: {
value: '{fullName}'
}
}]
});
}
});

ExtJS: Issue with scope in class

I'm keep facing with a issue to choice exact component with scope. As you'll notice below I've created 2 different functions inside gridpanel. One of those creates a Ext.MessageBox for confirm. And other function creates a Ext.window.Window depends on button click of MessageBox.
The thing here is; It should destroy related component with cancel and no buttons. Both buttons always point to gridpanel because of var me = this state and destroys the gridpanel itself.
How can I point destroy method directly to related component?
Ext.define('MyApp.FooGrid', {
extend: 'Ext.grid.Panel',
reference: 'fooGrid',
getGridMenu: function () {
// Here is the 'Update' function; with right-click user being able to see `contextmenu`
var me = this;
var ret = [
{
text: 'Update',
listeners: {
click: me.onUpdate,
scope: me
}
}
];
return me.callParent().concat(ret);
},
onUpdate: function () {
var me = this,
gridRec = this.getSelectionModel().getSelection(); // Here being able to retrieve row data.
Ext.MessageBox.confirm(translations.confirm, translations.confirmChange, me.change, me);
return gridRec;
},
change: function (button) {
var me = this;
var selectedRec = me.onUpdate();
var selectedRecEmail = selectedRec[0].data.email; //Retrieves selected record's email with right-click action
if (button === "yes") {
return new Ext.window.Window({
alias: 'updateWin',
autoShow: true,
title: translations.update,
modal: true,
width: 350,
height: 200,
items: [
{
xtype: 'container',
height: 10
},
{
xtype: 'textfield',
width: 300,
readOnly: true,
value: selectedRecEmail //Display selected record email
},
{
xtype: 'textfield',
width: 300,
fieldLabel: translations.newPassword
}
],
dockedItems: [
{
xtype: 'toolbar',
dock: 'bottom',
items: [
{
xtype: 'tbfill'
},
{
xtype: 'button',
text: translations.cancel,
listeners: {
click: function () {
me.destroy(); // Here is the bug: When user clicks on this button; should destroy current window but it destroys 'gridpanel' itself
}
}
},
{
xtype: 'button',
text: translations.save,
listeners: {
click: function () {
console.log("I'll save you!");
}
}
}
]
}
]
});
} else {
console.log('this is no!');
me.destroy(); // Another bug raises through here: If user will click on No then 'messagebox' should destroy. This one is destroys the gridpanel as well.
}
}
});
How can I point destroy method directly to related component?
Firstly on confirmation box button's(No) click, you don't need to destroy it will automatically hide the box whenever you click into No.
And for update window instead of using me.destroy() you need to use directly button.up('window').destroy() so it will only destroy your update window not the grid.
And also you don't need to again call me.onUpdate() inside of change function otherwise it will again show the confirmation box. You can directly get selected record on the change function like this me.getSelection().
In this Fiddle, I have created a demo using your code and I have put my efforts to get result.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.create('Ext.data.Store', {
storeId: 'demostore',
fields: ['name', 'email', 'phone'],
data: [{
name: 'Lisa',
email: 'lisa#simpsons.com',
phone: '555-111-1224'
}, {
name: 'Bart',
email: 'bart#simpsons.com',
phone: '555-222-1234'
}, {
name: 'Homer',
email: 'homer#simpsons.com',
phone: '555-222-1244'
}, {
name: 'Marge',
email: 'marge#simpsons.com',
phone: '555-222-1254'
}]
});
Ext.create('Ext.grid.Panel', {
title: 'Demo GRID',
store: 'demostore',
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
height: 200,
listeners: {
itemcontextmenu: function (grid, record, item, index, e, eOpts) {
e.stopEvent();
grid.up('grid').getGridMenu().showAt(e.getXY());
}
},
renderTo: Ext.getBody(),
getGridMenu: function () {
var me = this;
if (!me.contextMenu) {
me.contextMenu = Ext.create('Ext.menu.Menu', {
width: 200,
items: [{
text: 'Update',
handler: me.onUpdate,
scope: me
}]
});
}
return me.contextMenu;
},
onUpdate: function () {
var me = this;
Ext.MessageBox.confirm('Confirmation ', 'Are your sure ?', me.change, me);
},
change: function (button) {
var me = this,
selectedRecEmail = me.getSelection()[0].data.email; //Retrieves selected record's email with right-click action
if (button === "yes") {
return new Ext.window.Window({
autoShow: true,
title: 'Update',
modal: true,
width: 350,
height: 200,
items: [{
xtype: 'tbspacer',
height: 10
}, {
xtype: 'textfield',
width: 300,
readOnly: true,
value: selectedRecEmail //Display selected record email
}, {
xtype: 'textfield',
inputType:'password',
width: 300,
fieldLabel: 'New Password'
}],
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
items: [{
xtype: 'tbfill'
}, {
xtype: 'button',
text: 'cancel',
listeners: {
click: function (btn) {
btn.up('window').destroy(); // Here is the bug: When user clicks on this button; should destroy current window but it destroys 'gridpanel' itself
}
}
}, {
xtype: 'button',
text: 'save',
listeners: {
click: function () {
console.log("I'll save you!");
}
}
}]
}]
});
}
}
});
}
});

extjs6 modern card layut

I am new in Extjs. I have a container with card layout with 3 sub views including a grid, a form for creating and a form for updating using route.
items: [
{xtype: 'feature-grid',id:'feature-grid},
{xtype: 'create-form'},
{xtype: 'update-form'}
],
it works well at the first time but when I change the route and switch to this route again this error appears:
Uncaught Error: DOM element with id feature-grid in Element cache is not the same as element in the DOM. Make sure to clean up Element instances using destroy()
and when I remove the id the save button in my create form doesnt add record to the grid without any error!
my save button is like this:
var form = button.up('formpanel');
var values = form.getValues();
var user = Ext.create('App.model.User',values);
var cntr = this.getView('UserContainer')
var mainpanel = button.up('user-container');
var grid = mainpanel.down('grid');
grid.store.add(user);
form.reset();
this.redirectTo('users')
any idea?
As you are using routes so in this case first you need to check you view is already created or not. If view is already created then you can use that view otherwise you can create view.
In this FIDDLE, I have create a demo using cardlayout, grid and form. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//Define cotroller
Ext.define('MainController', {
extend: 'Ext.app.ViewController',
alias: 'controller.maincontroller',
routes: {
'application/:node': 'onViewChange'
},
//this event will fire whenver routing will be changed
onViewChange: function (xtype) {
var view = this.getView(),
newNode = view.down(xtype);
//if view is not crated then 1st created
if (!newNode) {
newNode = Ext.create({
xtype: xtype
});
}
// is new view is form then first reset the form
if (newNode.isXType('form')) {
newNode.reset();
}
// if new view type is update-form then load the record
if (xtype == 'update-form') {
newNode.setRecord(this.record)
this.record = null;
}
//If view is created then directly set active that view
view.setActiveItem(newNode);
},
//this event will fire when main view render
onMainViewAfterRedner: function () {
this.redirectTo('application/feature-grid');
},
//this event will fire when grid items clicked
onGridItemClick: function (grid, index, target, record, e, eOpts) {
this.record = record;
this.redirectTo('application/update-form');
},
//this event will fire when cancel button clicked
onCancelButtonClick: function () {
this.redirectTo('application/feature-grid');
},
//this event will fire when add new button clicked
onAddNew: function () {
this.redirectTo('application/create-form');
},
//this event will fire when save button clicked
onSaveButtonClick: function (button) {
var me = this,
form = button.up('formpanel'),
store = me.getView().down('grid').getStore(),
values = form.getValues();
if (form.xtype == 'update-form') {
store.findRecord('id', values.id).set(values);
} else {
if (values.name && values.email && values.phone) {
delete values.id;
store.add(values);
} else {
Ext.Msg.alert('Info','Please enter form details');
return false;
}
}
this.onCancelButtonClick();
}
});
Ext.define('AppForm', {
extend: 'Ext.form.Panel',
layout: 'vbox',
bodyPadding: 10,
defaults: {
xtype: 'textfield',
//flex: 1,
width: '100%',
margin: '10 5',
labelAlign: 'top',
allowBlank: false
},
items: [{
name: 'id',
hidden: true
}, {
name: 'name',
label: 'Name'
}, {
name: 'email',
label: 'Email'
}, {
name: 'phone',
label: 'Phone Number'
}, {
xtype: 'toolbar',
defaults: {
xtype: 'button',
ui: 'action',
margin: 5,
flex: 1
},
items: [{
text: 'Save',
formBind: true,
handler: 'onSaveButtonClick'
}, {
text: 'Cancel',
handler: 'onCancelButtonClick'
}]
}]
});
//this create-form.
Ext.define('CreateForm', {
extend: 'AppForm',
alias: 'widget.create-form',
title: 'Create form'
});
//this update-form.
Ext.define('UpdateForm', {
extend: 'AppForm',
alias: 'widget.update-form',
title: 'Update form'
});
//this feature-grid.
Ext.define('fGrid', {
extend: 'Ext.panel.Panel',
alias: 'widget.feature-grid',
title: 'User List grid',
layout: 'vbox',
items: [{
xtype: 'grid',
flex: 1,
store: {
fields: ['name', 'email', 'phone'],
data: [{
name: 'Lisa',
email: 'lisa#simpsons.com',
phone: '555-111-1224'
}, {
name: 'Bart',
email: 'bart#simpsons.com',
phone: '555-222-1234'
}, {
name: 'Homer',
email: 'homer#simpsons.com',
phone: '555-222-1244'
}, {
name: 'Marge',
email: 'marge#simpsons.com',
phone: '555-222-1254'
}]
},
columns: [{
text: 'Name',
dataIndex: 'name',
flex: 1
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone',
flex: 1
}],
listeners: {
itemtap: 'onGridItemClick'
}
}],
tools: [{
type: 'plus',
iconCls: 'x-fa fa-plus',
handler: 'onAddNew'
}],
flex: 1
});
//Define the main view form extending panel
Ext.define('MainView', {
extend: 'Ext.panel.Panel',
controller: 'maincontroller',
alias: 'widget.mainview',
layout: 'card',
listeners: {
painted: 'onMainViewAfterRedner'
}
});
//this will create main view that is card layout
Ext.create({
xtype: 'mainview',
renderTo: Ext.getBody(),
fullscreen: true
});
}
});

Extjs6.2 Modern toolkit- Extend a textbox

I am still learning EXTJs and one of the thing I was trying to to was extend a component. Below is my example:
Ext.define('MyApp.view.CustomTextField',{
extend: 'Ext.field.Text',
xtype: 'customtextfield',
config:
{
fieldID: null,
langID: null
},
initialize: function() {
alert("init"); //1. called before I navigate to view
Call a controller method here
this.callParent(arguments);
},
initComponent: function () {
alert("initComp"); //2. not called at all
Call a controller method here
this.callParent(arguments);
}
I want to call a controller method to validate if user has permission to see this field and accordingly do next actions. I want this validation to happen when I navigate to the view
I used this custom field in my View as:
xtype: 'fieldset',
margin: 10,
bind: '{workOrders}',
title: 'Dispatch Information',
items: [
{
id: 'Tag',
xtype: 'customtextfield',
name: 'Tag',
label: 'Tag',
bind: '{Tag}',
labelAlign: 'top'
},
But the initComponent is never fired.
The initialize is fired to soon ,even before my stores are loaded. How do I properly extend this control?
In ExtJS 6 modern there is no initComponent event for textfield . initComponent event have
in classic for textfield.
For calling events in controller you need to create controller and define to you view.
In this FIDDLE, I have created a demo using form, ViewController, textfield and ViewModel. I hope this will help/guide you to achieve your requirements.
For more details please refer ExtJS Docs.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//Define the cutsometext from extending {Ext.field.Text}
Ext.define('CustomText', {
extend: 'Ext.field.Text',
xtype: 'customtext',
labelAlign: 'top',
listeners: {
initialize: 'onInitializeCutsomText'
}
});
Ext.define('FormModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.formmodel',
data: {
user: {
firstName: 'Narendra',
lastName: 'Jadhav',
email: 'narendrajadhav105#gmail.com'
},
permissionCng: {
firstName: false,
lastName: false,
email: true,
isAdmin: false
}
}
});
//Define the FormController from extending {Ext.app.ViewController}
Ext.define('FormController', {
extend: 'Ext.app.ViewController',
alias: 'controller.formctn',
onInitializeCutsomText: function (textfield) {
var permissionCng = this.getViewModel().get('permissionCng');
// Here is just basic example for disabled textfield on initialize event.
//In your case you can put your requirement.
textfield.setDisabled(permissionCng[textfield.getName()]);
}
});
//Creating form
Ext.create('Ext.form.Panel', {
fullscreen: true,
viewModel: {
type: 'formmodel'
},
controller: 'formctn',
items: [{
xtype: 'fieldset',
title: 'Personal Info',
defaults: {
xtype: 'customtext' //Here I am using {customtext}
},
items: [{
label: 'First Name',
name: 'firstName',
bind: {
value: '{user.firstName}',
//You can also use like property
//hidden:'{permissionCng.firstName}'
}
}, {
label: 'Last Name',
name: 'lastName',
bind: {
value: '{user.lastName}',
//You can also use like property
//hidden:'{permissionCng.firstName}'
}
}, {
label: 'Email Id',
name: 'email',
bind: {
value: '{user.email}',
//You can also use like property
//hidden:'{permissionCng.firstName}'
}
}, {
label: 'Admin Name',
name: 'isAdmin',
bind: {
value: '{user.isAdmin}',
//You can also use like property
hidden: '{!permissionCng.isAdmin}'
}
}]
}]
});
}
});

extract string from a json object

I have an attribute in the extjs code defined as :
datajson: {
'name' : 'Hello',
....
}
Now I need to set the value of a textfield to the name defined inside this attribute.
I have tried the following but its not working:
Ext.getCmp('name').setValue((this.datajson.xyz.name).toString());
The id of the textfield whose value I am trying to set is 'name'
Here is the full code structure.
Ext.define('Test', {
extend : 'Ext.Container',
alias : 'widget.myapp',
datajson:{
'xyz' : {
...
"name" : 'Hello',
...
}
},
initComponent : function() {
this.appcombo = Ext.create('Ext.form.field.ComboBox', {
store: Ext.create('Ext.data.Store', {
fields: ['text'],
data: [
{text: "a"},
{text: "b"},
{text: "c"}
]
}),
listeners: {
select: function(combo, record, index) {
Ext.getCmp('name').setValue((this.datajson.xyz.name).toString());
}
}
});
...
...
//Here we have a textfield within a Panel whose id is 'name'
So basically I am loading the page and then selecting one value in combo box which serves as the event to load the values in the text-fields with the data which is in datajson.
EDIT: More information added.
The scope within your select function no longer contains datajson. To continue to use this.datajson you can pass the required scope into the function using bind
Ext.application({
name: 'Fiddle',
datajson: {
'name': 'Hello'
},
displayName: function (combo, record, index) {
Ext.getCmp('name').setValue((this.datajson.name));
},
launch: function () {
Ext.create('Ext.form.Panel', {
title: 'Contact Info',
width: 300,
bodyPadding: 10,
renderTo: Ext.getBody(),
items: [{
xtype: 'combo',
store: Ext.create('Ext.data.Store', {
fields: ['text'],
data: [{
text: "a"
}, {
text: "b"
}, {
text: "c"
}]
}),
listeners: {
select: this.displayName.bind(this)
}
}, {
xtype: 'textfield',
id: 'name',
fieldLabel: 'Name'
}]
});
}
});

Resources