Dynamically add TextAreas to a FormPanel on User Input with ExtJS - javascript

I have a FormPanel displaying a pretty basic form, essentially, it just contains a "Name" field, a "Description" field, and multiple "Rules" text areas. What I want is for the user to be able to type text into the first such Rule text area and have another empty TextField appear (when they start typing) for an additional rule.
Currently, I've got a function that should generate new TextAreas when called with a specified name (the newRulesField function), and a function to handle KeyPress events inside my text areas.
What I'm essentially looking for is how I can dynamically modify the number of TextAreas in the form.
Here's the code, in case it helps:
function handleRuleKeypress(a,b) {
Ext.Msg.alert('kp');
}
function newRulesField(name) {
var rulesField = new Ext.form.TextArea({
fieldLabel: 'Rules',
anchor: '100%',
name: name,
allowBlank: false,
grow: false,
enableKeyEvents: true,
listeners: {
keypress: handleRuleKeypress
}
});
return rulesField;
}
function handleNewRuleSetClick(nodes) {
var nameField = new Ext.form.TextField({
fieldLabel: 'Name',
name: 'ruleSetName',
anchor: '100%',
allowBlank: false,
grow: false
});
var descField = new Ext.form.TextField({
fieldLabel: 'Description',
name: 'ruleSetDescription',
anchor: '100%',
allowBlank: false,
grow: false
});
var form = new Ext.FormPanel({
labelWidth: 75,
defaultType: 'textfield',
bodyStyle: 'padding:30px',
id: 'newRuleSetPanel',
name: 'newRuleSetPanel',
title: 'New Rule Set',
buttons: [{
text: 'Save',
id: 'saveBtn',
hidden: false,
handler: function() {
form.getForm().submit({
url: 'server/new-rule-set',
waitMsg: 'Saving...',
success: function(f,a) {
Ext.Msg.alert('Success', 'It worked');
},
failure: function(f,a) {
Ext.Msg.alert('Warning', 'Error');
}
});
}
},{
text: 'Cancel',
id: 'cancelBtn',
hidden: false
}]
});
form.add(nameField);
form.add(descField);
form.add(newRulesField('rules1'));
this.add(form);
this.doLayout();
}

you are very close to doing this already - just call your newRulesField function from your handleRuleKeypress function. something like this:
function handleNewRuleSetClick(nodes) {
var nameField = new Ext.form.TextField({
fieldLabel: 'Name',
name: 'ruleSetName',
anchor: '100%',
allowBlank: false,
grow: false
});
var descField = new Ext.form.TextField({
fieldLabel: 'Description',
name: 'ruleSetDescription',
anchor: '100%',
allowBlank: false,
grow: false
});
var form = new Ext.FormPanel({
labelWidth: 75,
defaultType: 'textfield',
bodyStyle: 'padding:30px',
id: 'newRuleSetPanel',
name: 'newRuleSetPanel',
title: 'New Rule Set',
buttons: [{
text: 'Save',
id: 'saveBtn',
hidden: false,
handler: function() {
form.getForm().submit({
url: 'server/new-rule-set',
waitMsg: 'Saving...',
success: function(f, a) {
Ext.Msg.alert('Success', 'It worked');
},
failure: function(f, a) {
Ext.Msg.alert('Warning', 'Error');
}
});
}
}, {
text: 'Cancel',
id: 'cancelBtn',
hidden: false
}]
});
function handleRuleKeypress(a, b) {
form.add(newRulesField('rules' + Ext.id()));
}
function newRulesField(name) {
var rulesField = new Ext.form.TextArea({
fieldLabel: 'Rules',
anchor: '100%',
name: name,
allowBlank: false,
grow: false,
enableKeyEvents: true,
listeners: {
keypress: handleRuleKeypress
}
});
return rulesField;
}
form.add(nameField);
form.add(descField);
form.add(newRulesField('rules1'));
this.add(form);
this.doLayout();
}
you will want additional logic for checking if you have already added the new text area (or you will get a new one for each key press), perhaps removing the additional text area if the latest rule is emptied later on, and fixing the textarea id's a little prettier (all this is your handleRuleKeypress func).
My general thoughts on your application design is to keep the FormPanel as a class member somewhere instead of a private function member, this will make it easier to access whenever it comes to modifying it after creation - stacking functions like this is not very pretty nor readable.

Related

Binding viewModel property with variable

Intro:
I need to call the backend controller to see if the user is admin. If the user is NOT admin, hide the toolbar in the application. Currently the var is successfully changing; However, it is changing after the view is already created causing the view to always have the toolbar visable.
Problem:
Need to check backend to see if user is in the admin group.
Need to return true if they are in admin group
MyCode:
var adminBool = false;
function CheckAdmin() {
debugger;
var a;
Direct.Report.IsAdmin(this.results, a);
debugger;
};
function results(result, constructor, c, d, e, f, g, h) {
debugger;
this.adminBool= result.adminUser; //returns bool
}
Ext.define('Ext.View.MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.AdministrationViewModel',
init: this.CheckAdmin(),
data: {
addNew: true,
update: true,
gridData: null,
isAdmin: this.adminBool
}
});
Synopsis:
Call the backend controller for admin status
Return bool
Update viewModel with bool respectively
ViewModel property,'isAdmin', will bind with hidden property to hide unwanted actions for non admins
UPDATE:
Basically I need a way to delay "isAdmin: this.adminBool" check to after the backend call is finished.
As you are using ViewModel.
So you can use set() method to update your viewmodel field.
I have created an sencha fiddle demo using viewmodel. You can check, how it is working in fiddle. In this fiddle I have not used any API, it just example regarding of ViewModel. Hope this will help you to solve your problem or achieve your requirement.
//ViewModel
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.AdministrationViewModel',
data: {
isAdmin: true
}
});
//Panel
Ext.create('Ext.panel.Panel', {
title: 'ViewModel example',
width: '100%',
renderTo: Ext.getBody(),
viewModel: 'AdministrationViewModel',
layout: {
type: 'vbox', // Arrange child items vertically
align: 'stretch', // Each takes up full width
padding: 10
},
defaults: {
margin: 10
},
items: [{
xtype: 'combo',
height: 40,
fieldLabel: 'Choose Admin or user',
emptyText: 'Choose Admin or user',
labelAlign: 'top',
store: {
fields: ['name', 'value'],
data: [{
"value": true,
"name": "Admin"
}, {
"value": false,
"name": "User"
}]
},
queryMode: 'local',
displayField: 'name',
valueField: 'value',
listeners: {
select: function (combo, record) {
var viewModel = combo.up('panel').getViewModel(),
isAdmin = record.get('value');
//If selected value is {Admin} then we will show toolbar otherwise in case of {User} hide
viewModel.set('isAdmin', !isAdmin);
}
}
}, {
xtype: 'toolbar',
width: '100%',
height: 50,
padding: 10,
bind: {
hidden: '{isAdmin}'
},
items: [{
// xtype: 'button', // default for Toolbars
text: 'Admin',
}, {
xtype: 'splitbutton',
text: 'Split Button'
},
// begin using the right-justified button container
'->', // same as { xtype: 'tbfill' }
{
xtype: 'textfield',
name: 'field1',
emptyText: 'enter search term'
},
// add a vertical separator bar between toolbar items
'-', // same as {xtype: 'tbseparator'} to create Ext.toolbar.Separator
'text 1', // same as {xtype: 'tbtext', text: 'text1'} to create Ext.toolbar.TextItem
{
xtype: 'tbspacer'
}, // same as ' ' to create Ext.toolbar.Spacer
'text 2', {
xtype: 'tbspacer',
width: 50
}, // add a 50px space
'text 3'
]
}]
});

How to update a Ext.form.ComboBox store (simple store) once created in a Ext.window (Extjs)

I tried the find a solution of my case on the sencha forms, but no success :(
I'm a beginner on js and Extjs 3.4, I'm trying to use Ext.form.ComboBox in a Ext.window to show the list of js objects (layers). the problem is when I create the window the first time and I click on the ComboBox trigger I get my layers list correctly, but when I remove or add a layer, and I click again on the trigger the store don't update and I find the same list :(((
Can you please help me to find a solution to this problem, for example when I click on the trigger it will update and load the new list store ?
Any suggestion is welcome,
Thank you in advance !
Here is a part of the code :
createWindow: function() {
var FIELD_WIDTH = 250,
base = {
forceSelection: true,
editable: true,
allowBlank: true,
triggerAction: 'all',
mode: 'local',
labelSeparator: OpenLayers.i18n("labelSeparator"),
valueField: 'value',
displayField: 'text',
labelWidth: 300
};
var addComboxFieldItemsWCS = function() {
layer_liste_WCS = [];
var empty = true ;
layerStore.each (function (record) {
var layer = record.get('layer');
var queryable = record.get('queryable');
// var type = record.get('type');
var hasEquivalentWCS = record.hasEquivalentWCS()
if (queryable && hasEquivalentWCS) {
empty = false;
var ObjectRecordType = Ext.data.Record.create(['text', 'value']);
var rec = new ObjectRecordType({ text: layer.name, value:record })
console.log(rec.data.value)
var liste = [rec.data.text, rec.data.value];
layer_liste_WCS.push(liste)
}
}) ;
if (empty) {
var ObjectRecordType = Ext.data.Record.create(['text', 'value']);
var rec = new ObjectRecordType({ text: "No based WCS layer !", value:"" })
var liste = [rec.data.text, rec.data.value];
layer_liste_WCS.push(liste)
disabled: true
}
};
addComboxFieldItemsWCS();
var WCS_store = new Ext.data.SimpleStore({
autoLoad: true,
fields: ['text','value'],
data: layer_liste_WCS
});
ImageField = new Ext.form.ComboBox(Ext.apply({
name: "Image_ref",
fieldLabel: OpenLayers.i18n("Spot Image Input (Required)"),
// fieldLabel: WPS_config.img.title, // From WPS Server
emptyText: OpenLayers.i18n("Select your Image"),
autoDestroy: true,
width: FIELD_WIDTH,
triggerAction: 'all',
queryMode: 'local',
store: WCS_store,
}, base));
return new Ext.Window({
title: OpenLayers.i18n("addon_wpsjussie_title"),
closable: true,
resizable: false,
shadow: false,
closeAction: 'hide',
region: "center", //"north","south","east","west"
width: 480,
height: 190,
iconCls: 'wind_icon',
plain: true,
layout: 'border',
buttonAlign: 'right',
layout: 'fit',
listeners: {
show: function() {
this.el.setStyle('left', '');
this.el.setStyle('top', '');
}
},
items: [{
region: 'center',
xtype: 'tabpanel',
activeTab: 0,
width: 50,
height:20,
items: [{ // we will declare 3 tabs
title: OpenLayers.i18n('Datas Inputs'),
closable:false,
iconCls: 'input_icon',
active: true,
items:[{
xtype: 'form',
autoWidth: true,
labelWidth: 185,
bodyStyle: "padding:10px;",
items: [
ImageField,
]
}]
}]
}],
});
},
first you need to set up a 'click' listener.
Every time it's performed, you have to reload the store 'WCS_store' :
WCS_store.load({ params: { param_1: value_1, param_2: value_2, etc...} });
Let me know if It works.
Here is the solution !
store: myArrayStore,
listeners:
{
beforequery:function() {
addComboboxItemsWFS();
this.store.clearData();
this.store.loadData(my_data);
}
}

Referencing caller class in called class in ExtJS

I'm new to ExtJS and have the following problem: I have one class LoginWindow, that implements a FormPanel:
Ext.define('WebDesktop.LoginWindow', {
extend: 'Ext.window.Window',
title: Translator.get("login_window:Anmeldung"),
layout: 'fit',
closable: false,
resizable: false,
constructor: function() {
this.callParent();
},
initComponent: function () {
var me = this;
me.loginPanel = new WebDesktop.LoginPanel(me);
me.items = [
me.loginPanel
],
me.callParent();
},
});
Ext.define('WebDesktop.LoginPanel', {
extend: 'Ext.form.Panel',
header: false,
bodyPadding: 5,
reset: true,
waitMsgTarget: true,
url: Routing.generate('_route_core_login'),
items: [{
xtype: 'textfield',
fieldLabel: Translator.get("login_window:Benutzername"),
name: '_username',
width: 300,
},
{
xtype: 'textfield',
fieldLabel: Translator.get("login_window:Passwort"),
name: '_password',
inputType: 'password',
width: 300,
}],
buttons: [{
text: Translator.get("login_window:Anmelden"),
handler: function() {
var form = this.up('form').getForm();
if (form.isValid()) {
// Submit the Ajax request and handle the response
form.submit({
success: /* Call a function that is defined in main application class */,
failure: function(form, action) {
Ext.Msg.show({
title: Translator.get("login_window:Benutzeranmeldung"),
msg: action.result ? action.result.message : 'No response',
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
form.reset();
}
});
}
}
}],
});
Now in my main application class I create an instance of the LoginWindow and show it to the user. Also in this main class is a function defined, that should be called when the form of the login window has successfully been submitted. But I don't know how to put in a reference to that function. I tried to pass a reference of the caller class to the called class and save it there, but that did not work. As you can see I'm not working with the MVC architecture, I know it's not best practice...
me.loginPanel = new WebDesktop.LoginPanel();
me.loginPanel.referenceToParentWindow = me;
is this what you are looking for? I am very confused.

Extjs 4 save state of a checkboxGroup when parent window is closed

I have a window with a checkboxGroup in it. I would like whatever selections are made in the checkboxGroup to be saved when my "apply" button on the window is pressed. So far I have
xtype: 'checkboxgroup',
stateful: true,
stateID: 'checks',
getState: function() {
return {
items: this.items
};
},
stateEvents: ['close'],
columns: 2,
vertical: false,
items: [...]
I'm pretty sure my stateEvents are wrong, what would I use to indicate that I want the state to be saved when the parent window is closed?
I have this line in my app.js file's launch function, right before I create the top viewport
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
Thank you!
apparently the state of the checkbox group does not include the values of the checkboxes http://docs.sencha.com/ext-js/4-0/#!/api/Ext.form.CheckboxGroup-method-getState
i had to go via a session variable and the parent window events ..
var configPopup;
var configForm = Ext.create('Ext.form.Panel', {
id: 'form-config',
name: 'form-config',
frame: true,
layout: 'anchor',
items: [
{
border:0,
anchor: "100%",
xtype: 'checkboxgroup',
fieldLabel: 'Include options',
labelWidth: 100,
id: 'opt_relation',
labelStyle: 'margin-left:10px;',
items: [
{
boxLabel: 'relation 1',
name: 'opt_relation',
inputValue: 'rel1',
checked: true
},
{
boxLabel: 'relation 2',
name: 'opt_relation',
inputValue: 'rel2',
checked: true
},
{
boxLabel: 'relation 3',
name: 'opt_relation',
inputValue: 'rel3',
checked: true
}
]
}
],
buttons: [
{
text: 'Close',
handler: function() {
configPopup.hide();
}
}]
});
configPopup = new Ext.Window({
id:'configPopup',
title: 'Chart configuration',
layout : 'fit',
width : 390,
closeAction :'hide',
plain : true,
listeners: {
show: function() {
var v = Ext.state.Manager.get("optRelation");
if (v) {
Ext.getCmp('opt_relation').setValue(v);
}
},
hide: function() {
var v = Ext.getCmp('opt_relation').getValue();
Ext.state.Manager.set("optRelation",v);
}
},
items : [
configForm
]
});

ExtJS v3 - access data from grid panel inside a form panel

I have a GridPanel that I am using inside a Form.
When I submit the form, I have no problem grabbing the data from the form elements but cannot read/see the data that is placed inside the grid.
(Bascially, I am giving them an area to add email addresses in the grid).
I'm thinking I can just set the grid panel data as a hidden value in the form but that didn't work as I thought.
What direction should I take here so when someone submits the form I can see the main 'reason' field (which I can right now) and also each of the Email addresses that they are entering.
(I am submitting the form via a button that uses POST).
var projection_record = Ext.data.Record.create([
{ name: 'Email'}
]);
var projections_store = new Ext.data.Store({
reader: new Ext.data.ArrayReader({
idIndex: 0
}, projection_record)
});
var projections_grid = new Ext.grid.EditorGridPanel({
store: projections_store,
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'Email',
header: 'Approval Email',
sortable: false,
width: 250,
editor: new Ext.form.TextField({
valueField: 'displayText',
displayField: 'displayText'
})
},
{
xtype: 'actioncolumn',
header: "Delete",
width: 150,
items: [{
icon: 'images/delete.png',
handler: function(grid, rowIndex, colIndex) {
var rec = store.getAt(rowIndex);
alert("Delete " + rec.get('Email') + " ?");
}
//handler: function(grid, rowIndex, colindex) {
//var record = grid.getStore().getAt(rowIndex);
//var id = record.get("Email");
//window.location = '<% $base %>storage_approval_delete/' + id;
//}
}]
}
],
tbar: [{
text: 'Approvers',
icon: 'images/Add.png',
handler: function(){
var projection = projections_grid.getStore().recordType;
var p = new projection({
Email: ''
});
projections_grid.stopEditing();
projections_store.insert(0,p);
projections_grid.startEditing(0,0);
}
}],
autoHeight: true,
autoWidth: true,
trackMouseOver: true,
stripeRows: true
});
var simpleForm = new Ext.FormPanel ({
labelWidth: 175,
id: 'simpleForm',
url:'./manager_approvals',
method: 'POST',
frame:true,
title: 'Ada a New Project',
bodyStyle:'padding:5px 5px 0',
width: 850,
defaultType: 'textfield',
items: [
{
fieldLabel: 'Request Information',
name: 'Description',
xtype: 'textarea',
allowBlank: true,
anchor:'100%'
},
{
xtype: 'fieldset',
title: 'Approving Managers',
autoHeight: true,
autoWidth: true,
collapsible: false,
collapsed: false,
items: [projections_grid]
},
{
xtype: 'hidden',
name: 'hidden1',
value: projections_store
}
]
});
Hmmm.... I would seriously think about adding a comma separated field for a list of emails ....
If you are hell bent on letting them submit a form and edit a grid at the same time (good luck getting your users to understand what they need to do) what you need to do is on submit: lookup the store backing your grid, get the data values from the store records (iterate), extract the values you need, join with a comma, and finally either set a hidden field or just include as a parameter.
Good luck.

Categories

Resources