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}'
}
}]
}]
});
}
});
Related
I'm trying to do textfiled binding in extjs with the following conditions.
What i'm doing wrong?
Need to display three textfields where by default 2nd and 3rd textfields will be disabled.
Second textfield should enable only when first field value is entered.
third should be enabled only when first and second values are entered.
the fiddle.
You have forgotten to bind the second field value to 'field2'. This sample works:
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myvm',
data: {
field1: '',
field2: '',
field3: ''
},
formulas: {
fieldTwoDisabled: function (get) {
return Ext.isEmpty(get('field1'));
},
fieldThreeDisabled: function (get) {
return !(!Ext.isEmpty(get('field1')) && !Ext.isEmpty(get('field2')));
}
}
});
Ext.create({
xtype: 'panel',
title: 'VM Demo',
fullscreen: true,
defaults: {
xtype: 'textfield'
},
viewModel: {
type: 'myvm'
},
items: [{
label: 'Field 1',
bind: '{field1}'
}, {
label: 'Field 2',
bind: {
value: '{field2}', // THIS BINDING IS FORGOTTEN
disabled: '{fieldTwoDisabled}'
}
}, {
label: 'Field 3',
bind: {
disabled: '{fieldThreeDisabled}'
}
}]
})
}
});
I am using ExtJs6.2 Modern toolkit.I have a situation where all my display labels are stored in DB and I need to use those to display on my form.
example
{
xtype: 'textfield',
readOnly: true,
scrollable: false,
label: ** showFromStore ** ,
labelAlign: 'top',
name: 'someName',
bind: '{SomeValue}'
},
What would be the best way to manage this display on the forms?
For binding all config of textfield or any other EXTJS component you can use bind config.
Example
Ext.create({
xtype: 'textfield',
bind: {
label: '{user.label}',
name: '{user.name}',
value: '{user.value}',
}
})
In this FIDDLE, I have created a demo using viewmodel, formpanel and textfield. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
//defining view model
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myvm',
data: {
users: null
},
stores: {
formstore: {
autoLoad: true,
fields: ['name', 'email', 'phone', 'namelabel', 'phonelabel', 'emaillabel'],
proxy: {
type: 'ajax',
url: 'data.json',
reader: {
type: 'json',
rootProperty: ''
}
},
listeners: {
load: function (store, data, success) {
Ext.ComponentQuery.query('#myform')[0].getViewModel().set('users', data[0]);
}
}
}
}
});
//creating form
Ext.create({
xtype: 'formpanel',
itemId: 'myform',
title: 'Form example',
renderTo: Ext.getBody(),
fullscreen: true,
viewModel: {
type: 'myvm'
},
defaults: {
xtype: 'textfield',
readOnly: true
},
items: [{
bind: {
label: '{users.namelabel}',
value: '{users.name}'
}
}, {
bind: {
label: '{users.emaillabel}',
value: '{users.email}'
}
}, {
bind: {
label: '{users.phonelabel}',
value: '{users.phone}'
}
}]
});
}
});
JSON CODE
[{
"name": "Lisa Doshi",
"email": "lisa#simpsons.com",
"phone": "555-111-1224",
"namelabel": "Full Name",
"emaillabel": "Email Address",
"phonelabel": "Phone Number"
}]
I am not sure how to create a Fiddle to demonstrate this,but I will try to provide all details here
data returned from service is
[{"ID":"P1","Label":"Procedure"},{"ID":"P2","Label":"Process"},,
{"ID":"P3","Label":"Problem"}]
I am loading this data in a store
Ext.define('My.store.myLabels',
{
alias: 'store.Lang',
extend: 'Ext.data.Store',
config:
{
fields: ['ID', 'Label'],
pageSize: 10000,
proxy:
{
type: 'jsonp',
url: myserviceURL
}
}
});
Now how do I bind a single value from the store here
xtype: 'textfield',
readOnly: true,
scrollable: false,
labelAlign: 'top',
name: 'Process',
itemId: 'P1',
bind:{
value: '{somevalue}',
label: * how to bind the value of P1 here *,
}
I tried a formula: but with that I would have to write a formula for each UI element.
So my question is:
How to access a single item from the store to bind it here like:
store.data.items["0"].ID.P1
Or how to access the component
ID/itemId that triggered the view model formula so that I can do
displayLabel: {
get: function (get) {
var store = Ext.StoreMgr.get('myLabels');
//search the store based on item id of the component that
//triggered the formula
if (index > -1) {
return store.getAt(index).data.Label;
}
}
}
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
});
}
});
Let's say I've got a ViewController, ViewModel, and my View. In the View, I've got a form panel that gets a loaded record. When this record loads into the form, I want to hide or show a button based on the record's status field, so I figured do something with binding. However, it looks like binding is limited to only inverting, not actually using an expression. To get a better understanding, take a look at this code:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.define('User', {
extend: 'Ext.data.Model',
fields: ['name', 'status']
});
Ext.define('UserListController', {
extend : 'Ext.app.ViewController',
alias: 'controller.userlist'
});
Ext.define('UserListViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.userlist'
});
Ext.define('UserList', {
extend: 'Ext.form.Panel',
controller: 'userlist',
viewModel: 'userlist',
tbar: [{
text: 'Add',
reference: 'addButton',
bind: {
//hidden: '{status == 2}'
}
}, {
text: 'Delete',
reference: 'deleteButton',
bind: {
//hidden: '{status == 1}'
}
}],
items: [{
xtype: 'displayfield',
name: 'name',
fieldLabel: 'Name'
}, {
xtype: 'displayfield',
name: 'status',
fieldLabel: 'Status'
}]
});
var myForm = Ext.create('UserList', {
width: 400,
height: 200,
renderTo: Ext.getBody()
});
var record = Ext.create('User', {
name: 'blah',
status: 2
});
myForm.loadRecord(record);
if (record.get('status') === 2) {
myForm.lookupReference('addButton').hide();
}
}
});
As you can see, I'm currently just probing the values of the record to hide the addButton. Is there anyway I can accomplish this with binding or some other approach? It's good to note that I also looked at formulas, but from what I'm understanding, that's only for changing how data is rendered, so it didn't seem like the proper route.
If your record is part of the view model data - use formulas, like:
formulas: {
hideDeleteButton: function (getter) {
return getter('record.status') === 2;
},
hideAddButton: function (getter) {
return getter('record.status') === 1;
}
}
And then in your view you can bind:
{
text: 'Add',
reference: 'addButton',
bind: {
hidden: '{hideAddButton}'
}
}, {
text: 'Delete',
reference: 'deleteButton',
bind: {
hidden: '{hideDeleteButton}'
}
}
A working example: https://fiddle.sencha.com/#fiddle/mcg
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.
}