Related
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'
]
}]
});
I intend to change the state of several fields in a form (hide) according to the value selected in a combobox.
This can be done using methods such as setVisible () or setHidden ().
It will be possible to achieve this goal using binding component state?
SOLVED
Fiddle https://fiddle.sencha.com/#fiddle/1itf
Yes. Using ViewModel formulas. Quoting from the documentation:
Many configs you will want to bind are boolean values, such as visible (or hidden), disabled, checked, and pressed. Bind templates support boolean negation "inline" in the template. Other forms of algebra are relegated to formulas (see below), but boolean inversion is common enough there is special provision for it.
Basically, you can using bindings to control the visible attribute, but the binding needs to be a boolean value. You can see that with your 'isAdmin' check. So what you need to do is create a formula on the ViewModel and bind to that.
Ext.define('My.ViewModel', {
extend: 'Ext.app.ViewModel',
formulas: {
isAlabama: function(get) {
return get('comboboxvalue') === 'AL';
}
}
}
To use this, you'll need to say that you're using this view model in your panel. Also... you see the comboboxvalue bit? Well, it looks like ComboBoxes don't publish their value attribute to the view model automatically - you need to do that explicitly, like so:
{ xtype: 'combobox',
fieldLabel: 'Choose State',
store: states,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
reference:'combobox',
bind: {
value: '{comboboxvalue}'
}
}
There may be a more elegant solution but you could add an attribute into your store to determine to hide or not, then bind to that attribute:
Ext.application({
name : 'Fiddle',
launch : function() {
}
});
var states = Ext.create('Ext.data.Store', {
fields: ['abbr', 'name'],
data : [
{"abbr":"AL", "name":"Alabama", "hide": 0},
{"abbr":"AK", "name":"Alaska", "hide": 1},
{"abbr":"AZ", "name":"Arizona", "hide": 1}
]
});
Ext.create('Ext.form.Panel', {
title: 'Sign Up Form',
width: 300,
height: 230,
bodyPadding: 10,
margin: 10,
layout: {
type:'anchor',
align: 'stretch'
},
viewModel: true,
items: [{
xtype: 'checkbox',
boxLabel: 'Is Admin',
reference: 'isAdmin'
},{
xtype: 'textfield',
fieldLabel: 'Admin Key',
bind: {
visible: '{!isAdmin.checked}'
}
},{
xtype : 'menuseparator',
width : '100%'
},{
xtype: 'combobox',
fieldLabel: 'Choose State',
store: states,
queryMode: 'local',
displayField: 'name',
valueField: 'abbr',
reference:'combobox'
},{
xtype: 'textfield',
fieldLabel: 'If Alabama, hide',
bind: {
visible: '{combobox.selection.hide}'
}
},{
xtype: 'textfield',
fieldLabel: 'If Alaska, hide',
bind: {
visible: '{}'
}
},{
xtype: 'textfield',
fieldLabel: 'If Arizona, hide',
bind: {
visible: '{}'
}
}],
renderTo: Ext.getBody()
});
Here is my window and form inside of it:
Ext.define('App.view.Users.Update', {
extend: 'Ext.window.Window',
title: 'User',
width: 250,
id: 'UpdateWindowUsers',
defaultType: 'textfield',
items: [{
xtype: 'UpdateFormUsers'
}],
buttons: [
{ text: 'Save', id: 'submitUpdateFormButtonUsers'},
{ text: 'Cancel', id: 'cancelUpdateFormButtonUsers'},
]
});
Ext.define('App.view.Users.UpdateForm', {
extend: 'Ext.form.Panel',
alias: 'widget.UpdateFormUsers',
layout: 'form',
id: 'UpdateFormUsers',
bodyPadding: 5,
defaultType: 'textfield',
items: [{
fieldLabel: 'Id',
name: 'id',
hidden: true
},{
fieldLabel: 'username',
name: 'username',
allowBlank: false,
},{
fieldLabel: 'password',
name: 'password',
minLength : 5,
allowBlank: false
},{
fieldLabel: 'Email',
name: 'email',
minLength : 5,
vtype: 'email',
allowBlank: false
},{
fieldLabel: 'first name',
name: 'first_name',
allowBlank: false
},{
fieldLabel: 'last name',
name: 'last_name',
allowBlank: false
}],
});
It's in one file: "App/view/Users/Update.js".
So, I'm creating an object with:
var win = Ext.create('App.view.Users.Update');
It's created with a button. But when I close the window with win.close() and when I close the "tab" inside my "border" layout and when I press the button for creating the same window again, it says (in my console) that I'm recreating an object with the same "id" again. It's already registered in Ext.AbstractManager.
How can I fully destroy the object? Maybe with Ext.AbstractManager.unregister(win); something?
If you need more code, no problem. :) Thank you.
P. S.
I'm getting a reference to my window with:
var window = Ext.ComponentQuery.query('#UpdateWindowUsers')[0];
window.close();
Does window.close() actually destroys the panel inside of it?
Solved it.
this == Controller
if(this.isCreated){
this.control(listeners);
}
I've put isCreated property inside Controller.
How to populate form with JSON data using data store? How are the textfields connected with store, model?
Ext.define('app.formStore', {
extend: 'Ext.data.Model',
fields: [
{name: 'naziv', type:'string'},
{name: 'oib', type:'int'},
{name: 'email', type:'string'}
]
});
var myStore = Ext.create('Ext.data.Store', {
model: 'app.formStore',
proxy: {
type: 'ajax',
url : 'app/myJson.json',
reader:{
type:'json'
}
},
autoLoad:true
});
Ext.onReady(function() {
var testForm = Ext.create('Ext.form.Panel', {
width: 500,
renderTo: Ext.getBody(),
title: 'testForm',
waitMsgTarget: true,
fieldDefaults: {
labelAlign: 'right',
labelWidth: 85,
msgTarget: 'side'
},
items: [{
xtype: 'fieldset',
title: 'Contact Information',
items: [{
xtype:'textfield',
fieldLabel: 'Name',
name: 'naziv'
}, {
xtype:'textfield',
fieldLabel: 'oib',
name: 'oib'
}, {
xtype:'textfield',
fieldLabel: 'mail',
name: 'email'
}]
}]
});
testForm.getForm().loadRecord(app.formStore);
});
JSON
[
{"naziv":"Lisa", "oib":"2545898545", "email":"lisa#simpson.com"}
]
The field names of your model and form should match. Then you can load the form using loadRecord(). For example:
var record = Ext.create('XYZ',{
name: 'Abc',
email: 'abc#abc.com'
});
formpanel.getForm().loadRecord(record);
or, get the values from already loaded store.
The answer of Abdel Olakara works great. But if you want to populate without the use of a store you can also do it like:
var record = {
data : {
group : 'Moody Blues',
text : 'One of the greatest bands'
}
};
formpanel.getForm().loadRecord(record);
I suggest you use Ext Direct methods. This way you can implement very nice and clean all operations: edit, delete, etc.
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.