extjs binding with formulas - extjs

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}'
}
}]
})
}
});

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}'
}
}]
});
}
});

Bind Textfield Label to store value

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;
}
}
}

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