Ext JS 4.1 - User-defined validation doesn't bind button - extjs

I defined a validation which controls if the id is unique or not to bind a button. It works well with built-in validations well, but it doesn't bind for my own validation.
Here's what I've tried:
View - FormPanel:
Ext.define(appName + '.view.user.UserForm', {
extend: 'Ext.form.Panel',
requires: [appName + '.view.language.LanguageCombo'],
alias: 'widget.userform',
// title : 'User Form',
iconCls: 'icon-form',
frame: true,
padding: '5 5 0 5',
border: true,
buttonAlign: 'right',
width: '100%',
// height : 200,
monitorValid: true,
bodyPadding: 10,
fieldDefaults: {
labelAlign: 'left',
labelWidth: 110,
anchor: '98%',
allowBlank: false,
selectOnFocus: true,
msgTarget: 'side'
},
initComponent: function () {
var me = this;
this.title = bundle.getMsg('userform.title');
this.items = [{
xtype: 'numberfield',
minValue: 1,
fieldLabel: bundle.getMsg('userform.field.recordId'),
name: 'recordId',
itemId: 'recordId'
}, {
];
this.btnReset = Ext.create('Ext.ux.button.ResetButton', {
handler: function (btn) {
me.getForm().reset();
}
});
this.btnSubmit = Ext.create('Ext.ux.button.SaveButton', {
disabled: true,
formBind: true
});
this.buttons = [me.btnReset, me.btnSubmit];
this.callParent(arguments);
}
});
Controller Method:
var form = this.getUserForm();
if (field.getValue() && field.getValue() != '') {
Ext.Ajax.request({
url: 'user/chkRecordIdUnique.ajax',
method: 'POST',
params: {
recordId: field.getValue()
},
success: function (response, options) {
var res = Ext.decode(response.responseText);
if (!res.success) {
field.markInvalid(bundle.getMsg('record.taken'));
form.getForm().markInvalid(bundle.getMsg('record.taken'));
}
}
});
}

According to the docs, markInvalid doesn't actually change the validity of a field. It just applies the visual styles as if the field had an error. And there's no isValid property to set. All validity is determined by an immediate call to the isValid method.
As it stands, Ext JS forms do not support asynchronous validation natively. It assumes that either all validation is done on the client side, or that the server will perform validation. If you want to perform an Ajax call to determine if the form is valid before enabling the save button, I would recommend making your own validate method with a success callback. Manually enable the save button if the Ajax call succeeds and the rest of the form is valid. Then on form change, you can disable the save button again.
Side note: width should be a number, not a percentage.

Related

Saving data entered in extJS textbox

I have made textboxes in ExtJS through which I will be taking input for an ID and a name. I want to use these values(ID and name) in some other classes. So, I want to save these values somewhere(preferably in a string) so that they can be used later.
Please can someone advise me on how to do that.
function textBoxTab() {
var simple = new Ext.FormPanel({
labelWidth: 75,
frame: true,
title: 'TAB_DIM',
bodyStyle: 'padding:5px 5px 0',
width: 350,
defaults: {
width: 230
},
defaultType: 'textfield',
items: [{
xtype: 'textfield',
name: 'Module_id',
fieldLabel: 'Module_id',
allowBlank: false // requires a non-empty value
}, {
xtype: 'textfield',
name: 'Module_desc',
fieldLabel: 'Module_desc',
allowBlank: false // requires a non-empty value
}],
buttons: [{
text: 'Cancel',
handler: function() {
this.up('form').getForm().reset();
}
}, {
text: 'Submit',
handler: function() {
var form = this.up('form').getForm();
form.submit({
clientValidation: true,
url: 'save.txt',
success: function() {
Ext.Msg.alert('saved');
},
failure: function(form, action) {}
});
if (form.isValid()) {
//Ext.Msg.alert('Submitted Values', form.getValues(true));
this.up('form').getForm().submit();
}
}
}]
});
simple.render(document.body);
}
I have tried this "url:'save.txt" thing but it is not working.
Please help, thanks in advance.
The best way is to store them in a model, and have a controller manage your views and models.
There is several guide on how to architect your ExtJS application using MVC (model-view-controller) :
http://docs.sencha.com/extjs/4.2.1/#!/guide/application_architecture
http://docs.sencha.com/extjs/4.2.1/#!/guide/mvc_pt1
http://docs.sencha.com/extjs/4.2.1/#!/guide/mvc_pt2
http://docs.sencha.com/extjs/4.2.1/#!/guide/mvc_pt3
(The previous links are for ExtJS v4)

Extjs 5 Progress bar during initComponent

I have a tab panel, and I perform a server request in it's initComponent method to add tabs according to the result. This process can take a long time, and I would like to display a progress bar during the begining of initComponent, till the end (before the callParent call method for example).
Is it possible to achieve this behaviour ?
Thanks a lot !
You can use a LoadMask on any pretty much any component, here is an example, there is also a fiddle:
Ext.application({
name: 'Fiddle',
launch: function() {
var store = Ext.create('Ext.data.JsonStore', {
storeId: 'simpsonsStore',
fields: ['name', 'email', 'phone'],
autoLoad: true,
proxy: {
type: 'ajax',
url: 'data1.json',
reader: {
type: 'json',
rootProperty: 'characters'
}
},
listeners: {
load: function() {
console.log(this);
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
title: 'Simpsons',
store: store,
columns: [{
text: 'Name',
dataIndex: 'name'
}, {
text: 'Email',
dataIndex: 'email',
flex: 1
}, {
text: 'Phone',
dataIndex: 'phone'
}],
height: 200,
width: 400,
renderTo: Ext.getBody()
});
var myMask = new Ext.LoadMask(grid, {msg:"Please wait..."});
myMask.show();
var timeout = setTimeout(function() {
myMask.hide();
}, 5000);
}
});
I've added a setTimeout to replicate a long loading request, you do not need to use this.
You do not need to rely on "callParent" method. You have two options:
Make your server request synchronously. (by setting async:false for your ext.ajax call or for the related operation) It causes your code to be waited till the response comes.it blocks UI interaction but makes you sure having response immediately in line after server call
Another way is calling this.setLoading(true) before calling ajax call and setting this.setLoading(false) in your ajax/operation callback method. Note that this should refer to your main component. So it is bettor to save it in a variable at initComponent first line. For example by a line like var me= this;. After that refer to current main component bymeinstead ofthis`
var progressBar = Ext.create('Ext.ProgressBar');
progressBar.wait({
interval: 1000,
duration: 10000,
increment: 10,
text: 'Adding tabs...',
scope: this,
fn: function() {
var tabPanel = Ext.create('Ext.tab.Panel');
me.add(tabPanel);
tabPanel.add({
xtype: 'panel',
title: 'Main tab'
});
tabPanel.add({
xtype: 'panel',
title: 'Chunk'
});
tabPanel.add({
xtype: 'panel',
title: 'My girl'
});
progressBar.hide();
}
});
Fiddle

What is the correct way to handle ajax events with MVC controller in ExtJs

We are trying to build a simple prototype to consume our data service using ExtJs (also to learn ExtJs at the same time).
While developing the prototype (with basic knowledge on ExtJS), I encountered several hickups. Before I post questions, I would like to have you to take a quick look at the following.
The following is the main class which interacts with the service. We wanted to make sure that certain UI components are masked/unmasked during ajax communications.
Ext.define('Sample.provider.SvcClient', {
TestConnectivity: function(prms){
debugger;
Ext.Ajax.on('beforerequest', function(conn,o,result) {
prms.BeforeRequest(conn,o,result);
});
Ext.Ajax.on('requestcomplete',function(conn,o,result) {
prms.RequestComplete(conn,o,result);
});
Ext.Ajax.on('requestexception',function(conn,o,result) {
prms.RequestException(conn,o,result);
});
Ext.Ajax.request({
url: prms.Url,
method: prms.HttpMethod,
headers: {
'Authorization' : 'Basic ' + prms.Credentials
},
success: prms.Success,
failure: prms.Failure,
callback: prms.Callback
});
}
});
We developed an extension to SvcClient especially to help masking of controls during ajax communications:
Ext.define('Sample.util.ClientProxy', {
CtlToMask : null,
DoTestConnection: function(ctlToMask, callback, url, userName, pwd) {
debugger;
var proxy = this;
proxy.CtlToMask = ctlToMask;
var client = new Sample.provider.SvcClient();
var params = {
Url: url,
HttpMethod: "GET",
Credentials: Sample.util.Conversions.Base64.encode(userName + ":" + pwd),
CtlToMask: proxy.CtlToMask,
Scope:proxy,
BeforeRequest: function(conn,o,result,Scope) {
debugger;
if(Scope.CtlToMask !=null) {
if(Scope.CtlToMask.getEl() != undefined)
Scope.CtlToMask.getEl().mask('Testing Connectivity...', 'x-mask-loading');
else
Scope.CtlToMask.mask('Testing Connectivity...', 'x-mask-loading');
}
},
RequestComplete: function(conn,o,result) {
if(this.CtlToMask !=null) {
if(this.CtlToMask.getEl() != undefined)
this.CtlToMask.getEl().unmask(true);
else
this.CtlToMask.unmask(true);
}
},
RequestException: function(conn,o,result) {
if(this.CtlToMask !=null) {
if(this.CtlToMask.getEl() != undefined)
this.CtlToMask.getEl().unmask(true);
else
this.CtlToMask.unmask(true);
}
}
};
client.TestConnectivity(params);
}
});
I have the controller as shown below:
Ext.define('Sample.controller.Locations', {
extend: 'Ext.app.Controller',
models: ['Location', 'Country'],
views: [
'portal.location.Menu',
'portal.location.Edit'
],
init: function() {
this.control({
'locationsMenu':{
OpenAddNewSvcPopup: this.OnOpenAddNewSvcPopup
},
'locationsEdit':{
TestSvcConnectivity: this.OnTestSvcConnectivity,
render: function () { },
afterrender: function () { },
boxready: function () { }
}
});
},
OnOpenAddNewSvcPopup: function(){
var newLoc = Ext.create('Sample.model.Location', {
UserName: 'admin',
Uri: 'http://localhost/DataServicesBase/Data.svc'
});
var v = Ext.create('widget.locationsEdit',{ mode:'add'});
v.down('form').loadRecord(newLoc);
},
OnTestSvcConnectivity: function(ctl){
var proxy = new Sample.util.ClientProxy();
proxy.DoTestConnection(
ctl,
this.OnTestSvcConnectivityCallback,
ctl.down("#Uri").value + '/Countries',
ctl.down("#UserName").value,
ctl.down("#Password").value
);
},
OnTestSvcConnectivityCallback: function(options,success,result){
if(success) {
//show the result
}
else {
//Show error in window
}
}
});
The view would look like the following:
Ext.define('Sample.view.portal.location.Edit', {
extend: 'Ext.window.Window',
alias: 'widget.locationsEdit',
//title: 'Edit Service Location',
layout: 'fit',
autoShow: true,
title: 'Edit Service Location',
bodyStyle: 'border:0px',
closeAction:'destroy',
config:{
mode: 'edit'
},
constructor: function(configs){
this.callParent(arguments);
this.initConfig(configs);
if(this.mode == "add") this.setTitle('Add New Service Location');
},
initComponent: function() {
this.items = [
{
xtype: 'form',
items: [
{
xtype: 'textfield',
name: 'Id',
itemId: 'Id',
fieldLabel: 'Unique Name',
labelStyle: 'font-weight:bold',
allowBlank: false,
maxLength: 64,
width: 300
},
{
xtype: 'textfield',
name : 'Uri',
itemId: 'Uri',
fieldLabel: 'URI',
maxLength: 300,
width: 500,
allowBlank: false
},
{
xtype: 'textfield',
name : 'UserName',
itemId: 'UserName',
fieldLabel: 'User Name',
allowBlank: false,
maxLength: 64,
width: 200
},
{
xtype: 'textfield',
name : 'Password',
itemId: 'Password',
fieldLabel: 'Password',
allowBlank: false,
maxLength: 64,
width: 200
}
],
bodyStyle: 'padding:5px;'
}
];
this.buttons = [
{
text: 'Test Connectivity',
action: 'test',
scope: this,
handler: this.OnTestSvcConnectivity
},
{
text: 'Save',
action: 'save'
},
{
text: 'Cancel',
scope: this,
handler: this.close
}
];
this.callParent();
this.addEvents('TestSvcConnectivity') //custom event
},
OnTestSvcConnectivity: function(){
this.fireEvent('TestSvcConnectivity', this); //will be raised to controller
}
});
Q1
The approach works fine during first time when I click on "Test Connection" button (from the popup). If I click the same button for the second time, the (BeforeRequest) handler fires twice. Clicking for the third time, the handler gets fired thrice. What is the mistake in my code.
Q2
If I cancel the popup and again click on "Test Connection" it would never work. The handler still maintains "some" kind of reference (or state) of previous popup instance. As it could not be found, it throws "undefine" on object members. I confirmed this as through the debugger, I could see the id of previous popup instance instead of the current one. The handler always tries to honor the first popup instantiated no matter what.
Q3
Is the pattern we are trying to follow for this sample prototype is having any pitfalls/problems. We are trying to develop using MVC features of ExtJS and ensure that we are using stand and good patterns/practices so that we will not be facing above kind of very basic issues.

How to check few form fields are empty or not?

I am using ExtJS 3.4.0
I have a form in "var new" variable that comes to Ext.Window().
I need to do code that checks between textfield and textarea is one of them empty or not.
I mean if textfield is empty and textarea is not then form data can be submitted vice versa.
This code must be placed to the code that starts like below:
newform
.getForm()
.submit(
I hope you can find in my example
Ext.onReady(function(){
var newForm=Ext.create('Ext.form.Panel',{
title:"Form",
items:[
{
xtype:"textfield",
fieldLabel:"Name"
},
{
xtype : 'textareafield',
name : 'message',
fieldLabel: 'Message'
}
],
renderTo:document.body
});
var win= new Ext.Window
({
title:"Window",
layout:'fit',
height:250,
width:300,
items:[newForm],
buttons:[
{
text:"Submit",
handler:function(){
var textFieldValue=newForm.items.items[0].getValue();
var textAreaValue=newForm.items.items[1].getValue();
if(textFieldValue!=""||textAreaValue!=""){
alert("you can submit the data");
}
else{
alert("you can't submit the data");
}
}
}
]
}).show();
});
The following example shows a form with textfield and text area. Both are mandatory.
allowBlank::Specify false to validate that the value's length must be > 0. If true, then a blank value is always taken to be valid regardless of any vtype validation that may be applied.
validate() : Boolean
Returns whether or not the field value is currently valid by validating the field's current value, and fires the validitychange event if the field's validity has changed since the last validation. Note: disabled fields are always treated as valid.
See an example in:http://docs.sencha.com/extjs/6.2.0/classic/Ext.form.Panel.html#ext-form-panel_example-usage
Ext.create('Ext.form.Panel', {
title: 'Simple Form',
bodyPadding: 5,
width: 350,
// The form will submit an AJAX request to this URL when submitted
url: 'save-form.php',
// Fields will be arranged vertically, stretched to full width
layout: 'anchor',
defaults: {
anchor: '100%'
},
// The fields
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
name: 'first',
allowBlank: false,
validator: function(val) {
return (val.trim().length > 0) ? true : "This field may not be empty";
}
}, {
xtype: 'textarea',
fieldLabel: 'Last Name',
name: 'last',
allowBlank: false,
validator: function(val) {
return (val.trim().length > 0) ? true : "This field may not be empty";
}
}],
// Reset and Submit buttons
buttons: [{
text: 'Reset',
handler: function() {
this.up('form').getForm().reset();
}
}, {
text: 'Submit',
formBind: true, //only enabled once the form is valid
disabled: true,
handler: function() {
var form = this.up('form').getForm();
if (form.isValid()) {
form.submit({
success: function(form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action.result.msg);
}
});
}
}
}],
renderTo: Ext.getBody()
});

Resetting event handlers in ExtJS

I have a page where there are multiple records. Each record has a button to open a dialog box to create a name. The name then creates a related record in the database and updates the source record.
There is a single dialog box instantiated and I want to show the dialog box, get the result and return it to the correct record.
The code below works once but doesn't work the second time. I can see the the Create button gets clicked but the event doesn't got caught.
Many thanks for your help.
TrailNamePresenter.prototype.onCreateTrailClick = function (trailSegment, combo, personalRouteId) {
if (!this.createTrailWindow) {
this.createTrailWindowPanel = new CreateTrailFormPanel();
this.createTrailWindow = new Ext.Window({
title: 'Create Trail',
closable: true,
closeAction: 'hide',
plain: true,
items: [this.createTrailWindowPanel],
id: 'createtrailwindow'
});
}
this.createTrailWindowPanel.on('createTrail', this.getCreateTrailHandler(personalRouteId, trailSegment, combo), null, {single:true});
this.createTrailWindow.show();
};
TrailNamePresenter.prototype.getCreateTrailHandler = function(personalRouteId, trailSegment, currentTrailCombo) {
var thisPersonalRouteId = personalRouteId;
var thisPresenter = this;
var thisCurrentTrailCombo = currentTrailCombo;
var thisTrailSegment = trailSegment;
return function(newTrailName) {
thisPresenter.mapEditorService.createPersonalTrail(newTrailName, thisPersonalRouteId, thisPresenter.getCreateTrailServiceHandler(thisCurrentTrailCombo, thisTrailSegment));
};
};
CreateTrailFormPanel = Ext.extend(Ext.form.FormPanel, {
initComponent: function() {
Ext.apply(this, {
id: 'createtrailpanel',
width: 500,
frame: true,
bodyStyle: 'padding: 10px 10px 0 10px;',
labelWidth: 50,
defaults: {
anchor: '95%',
msgTarget: 'side'
},
items: [
{
id: 'crt_trailnamefield',
xtype: 'textfield',
fieldLabel: 'Trail Name'
}
],
buttons: [{
text: 'Create',
handler: this.getCreateClickHandler()
},{
text: 'Cancel',
handler: function(b, e){
Ext.getCmp('createtrailwindow').hide();
}
}]
});
this.addEvents('createTrail');
CreateTrailFormPanel.superclass.initComponent.apply(this, new Array());
}
});
CreateTrailFormPanel.prototype.getCreateClickHandler = function() {
var thisPanel = this;
return function() {
var trailNameField = Ext.getCmp('crt_trailnamefield');
alert('click');
thisPanel.fireEvent('createTrail', trailNameField.getValue());
};
};
In ExtJS, when you have components that will belong to a parent. I would suggest using itemID, otherwise the ability of reuse of the component across your web application is reduced because id acts similarly to a singleton. Also on the action, you have {single:true} which will remove the listener after the first trigger. IF you remove that, it may solve your issue

Resources