Switch view with ExtJS - javascript

It looks pretty easy but I'm unable to do it. I want to change the view after click on login button, this is my code:
app.js
Ext.require ('Ext.container.Viewport');
Ext.application({
name: 'MyApp',
appFolder: 'app',
views: [
'Login',
'Main'
],
controllers:[
'Login'
],
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'fit',
items: [{
xtype: 'loginView'
}]
});
}
});
Login.js (View)
Ext.define('MyApp.view.Login' ,{
extend: 'Ext.panel.Panel',
alias : 'widget.loginView',
title: 'MyApp',
layout: {
type: 'hbox',
pack: 'center',
padding: 50
},
defaults: {
border: false,
width: 400,
height: 400
},
items: [{
xtype: 'panel',
html: '<img src="resources/img/img.jpg" />'
}, {
xtype: 'loginForm'
}]
});
Ext.define('MyApp.view.LoginForm', {
extend: 'Ext.form.Panel',
alias: 'widget.loginForm',
title: 'PSSP',
bodyPadding: 5,
layout: 'anchor',
fieldDefaults: {
labelAlign: 'top',
labelWidth: 100,
labelStyle: 'font-weight:bold'
},
defaults: {
anchor: '100%',
margins: '0 0 10 0',
allowblank: false,
xtype: 'textfield',
},
items: [{
fieldLabel: 'User',
name: 'username',
itemId: 'username',
}, {
fieldLabel: 'Password',
name: 'password',
itemId: 'password',
inputType: 'password',
}],
buttons:[{
text: 'Login',
listeners: {
click: function() {
var username = this.up('form').down('#username').getValue();
var password = this.up('form').down('#password').getValue();
this.fireEvent('login', username, password);
//Ext.Msg.alert('Datos', 'User: ' + username + '<br>Password: ' + password);
}
}
}]
});
Login.js (Controller)
Ext.define('MyApp.controller.Login', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'loginView button': {
login: this.loginUser
}
});
},
loginUser: function(username, password) {
// check if the username and password is valid
Ext.create('Ext.container.Viewport', {
items:[{
xtype: 'mainView'
}]
});
}
});
Main.js (View)
Ext.define('MyApp.view.Main' , {
extend: 'Ext.container.Viewport',
alias : 'widget.mainView',
layout: 'border',
items: [{
region: 'north',
title: 'MyApp'
}, {
region: 'west',
width: 250,
html: 'WEST'
//xtype: 'westView'
}, {
region: 'east',
width: 250,
html: 'EAST'
//xtype: 'eastView'
}, {
region: 'center',
html: 'CENTER'
//xtype: 'centerView'
}]
});
What I have to change to load MainView when I click on login button??? Now, when I click on it, Chrome shows this error:
Uncaught HierarchyRequestError: A Node was inserted somewhere it doesn't belong.
What's wrong in my code?
Thanks!

This is how I do it: The basic idea is to have a parent container (I prefer a Viewport, as it's the whole viewable browser area). Set its layout to card. It will contain 2 views, a Login View and a Main View. In your Controller, use setActiveItem to set the current view:
Ext.getCmp('ViewportID').getLayout().setActiveItem('ViewIndex');
You can reference to the Viewport however you like (personally I use ref in Controller).
Also I see that you're trying to create 2 Viewport. This is impossible because there can be only 1 Viewport at a time. See the docs for more detail.

Related

How would I put part of a Handler function into a controller in Sencha

I have a handler function that creates a Ext.window.Window, with fields to enter data, I need o move this part of the code to a controller function, and separate it from the main ajax request, this is for code reuse purposes.
var win = Ext.create('Ext.window.Window', {
title: 'New Client',
id: 'addClientWindow',
width: 500,
height: 300,
items: [{
xtype: 'form',
bodyPadding: 10,
items: [{
xtype: 'fieldset',
title: 'My Fields',
items: [{
xtype: 'textfield',
anchor: '100%',
id: 'nameTextField',
fieldLabel: 'Name',
labelWidth: 140
}, {
xtype: 'textfield',
anchor: '100%',
id: 'physicalTextField',
fieldLabel: 'Physical Address',
labelWidth: 140
}, {
xtype: 'textfield',
anchor: '100%',
id: 'postalTextField',
fieldLabel: 'Postal Address',
labelWidth: 140
}]
}],
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
items: [{
xtype: 'button',
id: 'cancelClientBtn',
text: 'Cancel',
listeners: {
click: function(c) {
Ext.getCmp('addClientWindow').close();
}
}
}, {
xtype: 'tbspacer',
flex: 1
}, {
xtype: 'button',
id: 'saveClientBtn',
text: 'Save',
listeners: {
click: function(c) {
Ext.Ajax.request({
url: 'system/index.php',
method: 'POST',
params: {
class: 'Company',
method: 'add',
data: Ext.encode({
name: Ext.getCmp('nameTextField').getValue(),
physical: Ext.getCmp('physicalTextField').getValue(),
postal: Ext.getCmp('postalTextField').getValue()
})
},
success: function(response) {
Ext.MessageBox.alert('Status', 'Record has been updated.');
Ext.getStore('CompanyStore').reload();
Ext.getCmp('addClientWindow').close();
},
failure: function() {
Ext.MessageBox.alert('Status', 'Failed to update record.');
}
});
}
}
}]
}]
}]
});
win.show();
The button opens this window and performs this ajax request, I just need the two separated from one another. Any help appreciated.
You can define your window in a separated file and give it an alias:
Ext.define('MyApp.view.MyWindow', {
extend: 'Ext.window.Window',
alias: 'widget.addclient',
...
click: function(){
var data = Ext.encode({
name: Ext.getCmp('nameTextField').getValue(),
physical: Ext.getCmp('physicalTextField').getValue(),
postal: Ext.getCmp('postalTextField').getValue()
});
// I assume here "this" links to the window component,
// if not, adjust accordingly
if(this.mycallback){
this.mycallback(data);
}
}
});
Then you can call it from other controllers and provide a callback:
Ext.define('MyApp.view.MyController', {
extend: 'Ext.app.ViewController',
requires: 'MyApp.view.MyWindow',
openWindow: function(){
var win = Ext.widget('addclient');
win.mycallback = this.onAddClientCallback.bind(this);
win.show();
},
onAddClientCallback: function(data){
console.log("data from window", data);
}
});

ExtJS 5: disable form fields in hidden card

I have a form panel with a radiogroup, and depending on the radiogroup selection, it will show some other components. If a radiofield is not selected, then its items will be hidden, as they're not part of the active card.
Now, if I have allowblank: false set on a field (and it's empty) within the hidden card, my form is still considered invalid. Being hidden means the user would not like to use it, so it should not be considered as part of the form. Here's an example.
In the example, I have 2 forms... the top form is the one that I'm curious about... is there a way to get this working without having to bind to disabled? I tried looking at hideMode, but that wasn't what I was looking for.
Ideally, I wouldn't have to create a formula for each card that I add... that seems silly. I realize I could create a generic formula, but once again, that just seems extraneous. Another option could be ditching the card layout, and binding each card to hidden and disabled, but I'm creating more formulas. Is there some sort of property I'm missing?
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.define('MyController', {
extend: 'Ext.app.ViewController',
alias: 'controller.myview',
onValidityChange: function(form, isValid, eOpts) {
this.getViewModel().set('isFormValid', isValid);
}
});
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myview',
data: {
activeItem: {
myInput: 0
}
},
formulas: {
activeCardLayout: function(getter) {
var myInput = getter('activeItem.myInput');
console.log(myInput);
return parseInt(myInput);
}
}
});
Ext.define('MyForm', {
extend: 'Ext.form.Panel',
title: 'My Form',
controller: 'myview',
viewModel: {
type: 'myview'
},
layout: {
type: 'hbox'
},
listeners: {
validitychange: 'onValidityChange'
},
dockedItems: [{
xtype: 'toolbar',
dock: 'top',
layout: {
type: 'hbox'
},
items: [{
xtype: 'button',
text: 'Save',
reference: 'saveButton',
disabled: true,
bind: {
disabled: '{!isFormValid}'
}
}]
}],
items: [{
xtype: 'radiogroup',
vertical: true,
columns: 1,
bind: {
value: '{activeItem}'
},
defaults: {
name: 'myInput'
},
items: [{
boxLabel: 'None',
inputValue: '0'
}, {
boxLabel: 'Something',
inputValue: '1'
}]
}, {
xtype: 'container',
layout: 'card',
flex: 1,
bind: {
activeItem: '{activeCardLayout}'
},
items: [{
xtype: 'container',
layout: 'fit'
}, {
xtype: 'container',
layout: 'fit',
items: [{
xtype: 'textfield',
fieldLabel: 'hello',
allowBlank: false
}]
}]
}]
});
Ext.define('MyViewModel2', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myview2',
data: {
activeItem: {
myInput: 0
}
},
formulas: {
disableSomethingCard: function(getter) {
return getter('activeItem.myInput') !== '1';
},
activeCardLayout: function(getter) {
var myInput = getter('activeItem.myInput');
console.log(myInput, 'here');
return parseInt(myInput);
}
}
});
Ext.define('MyForm2', {
extend: 'MyForm',
title: 'My Form 2 (works)',
viewModel: {
type: 'myview2'
},
items: [{
xtype: 'radiogroup',
vertical: true,
columns: 1,
bind: {
value: '{activeItem}'
},
defaults: {
name: 'myInput'
},
items: [{
boxLabel: 'None',
inputValue: '0'
}, {
boxLabel: 'Something',
inputValue: '1'
}]
}, {
xtype: 'container',
layout: 'card',
flex: 1,
bind: {
activeItem: '{activeCardLayout}'
},
items: [{
xtype: 'container',
layout: 'fit'
}, {
xtype: 'container',
layout: 'fit',
bind: {
disabled: '{disableSomethingCard}'
},
items: [{
xtype: 'textfield',
fieldLabel: 'hello',
allowBlank: false
}]
}]
}]
});
Ext.create('MyForm', {
renderTo: Ext.getBody()
});
Ext.create('MyForm2', {
renderTo: Ext.getBody()
});
}
});

Losing scope in combobox ExtJS 4.2

I have a popup window with a combobox and a few buttons. The idea is to make a selection in the combobox and then either save the selection to a store or cancel. I have done this before and never had any problems, but with this code I get Uncaught TypeError: Cannot call method 'apply' of undefined whenever I try to interact with the combo. It seems to me like ExtJS is trying to run code meant for the store on the combobox.
I load the popup window with Ext.create('Account.Window.Reuse');
The definitions:
Ext.define('SimpleAccount', {
extend: 'Ext.data.Model',
idProperty: 'AccountID',
fields: [ {
name: 'AccountID',
type: 'int',
useNull: true
}, 'Name']
});
var userAccountReuseStore = Ext.create('Ext.data.Store', {
model: 'SimpleAccount',
storeId: 'userAccountReuseStore',
data: [{"AccountID":"1", "Name":"FirstAccount"},
{"AccountID":"2", "Name":"SecondAccount"},
{"AccountID":"3", "Name":"ThirdAccount"}]
});
Ext.define('Account.Reuse.ComboBox', {
extend: 'Ext.form.ComboBox',
alias: 'widget.accountReuseComboBox',
initComponent: function(){
Ext.apply(this, {
fieldLabel: 'Account',
displayField: 'Name',
valueField: 'AccountID',
queryMode: 'local'
})
}
});
Ext.define('Account.Reuse.Fieldset', {
extend: 'Ext.form.FieldSet',
alias: 'widget.accountReuseFieldset',
initComponent: function(){
Ext.apply(this, {
items: [
{
xtype: 'label',
cls: 'text-important',
margin: '0 0 10 0',
style: 'display: block',
text: 'Only attach an account you have permission to use. After attaching the account you will not be able to use, remove, or edit it until approved by SCSAM'
},
{
xtype: 'accountReuseComboBox',
store: userAccountReuseStore
}
]
});
this.callParent();
}
});
Ext.define('Account.Reuse.Details', {
extend: 'Ext.form.Panel',
alias: 'widget.accountReuseDetails',
initComponent: function(){
Ext.apply(this, {
plain: true,
border: 0,
bodyPadding: 5,
fieldDefaults: {
labelWidth: 55,
anchor: '100%'
},
layout: {
type: 'vbox',
align: 'stretch',
flex: 1
},
items: [
{
xtype: 'accountReuseFieldset',
defaults: {
labelWidth: 89,
anchor: '100%',
layout: {
type: 'vbox',
defaultMargins: {top: 0, right: 5, bottom: 0, left: 0},
align: 'stretch'
}
},
title: 'Details',
collapsible: false
}]
});
this.callParent();
}
});
Ext.define('Account.Window.Reuse', {
extend: 'Ext.window.Window',
alias: 'widget.accountWindowReuse',
initComponent: function(){
Ext.apply(this, {
title: 'Account Details',
width: 400,
autoShow: true,
modal: true,
layout: {
type: 'fit',
align: 'stretch' // Child items are stretched to full width
},
items: [{
xtype: 'accountReuseDetails',
id: 'attachAccountReuseForm'
}],
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
layout: {
pack: 'center'
},
items: [{
minWidth: 80,
text: 'Attach',
id: 'saveButton',
handler: function(){
var rec = this.up('accountWindowReuse').down('accountReuseDetails').getValues();
var store = Ext.getStore('userAccountReuseAttachStore');
store.add(rec);
this.up('window').close();
}
},{
minWidth: 80,
text: 'Cancel',
handler: function(){
this.up('window').close();
}
}]
}]
});
this.callParent();
}
});
It looks like you forget call parent in your Account.Reuse.ComboBox initComponent function so combobox is not initialized properly.
Your Account.Reuse.ComboBox initComponent function should look like this:
initComponent: function(){
Ext.apply(this, {
fieldLabel: 'Account',
displayField: 'Name',
valueField: 'AccountID',
queryMode: 'local'
});
this.callParent();
}

Extjs 4: use ux.center

I'm having trouble using the custom layout ux.center. Am I doing the Ext.Loader or the Ext.require wrong? The Center.js file is under /var/www/application/ux/layout/Center.js and this file (app.js) is under /var/wwww/application/app.js
Ext.Loader.setPath('Ext.ux', '/var/www/application/ux');
Ext.require('Ext.ux.layout.Center');
Ext.application({
name: 'AM',
appFolder: 'app',
controllers: ['Users'],
launch: function(){
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
Ext.create('Ext.container.Viewport', {
width: 1150,
height: 'auto',
autoScroll: 'true',
layout: 'anchor',
items:[{xtype: 'userpanel'},
{
xtype: 'panel',
width: 1150,
layout:'ux.center',
items:[{
xtype: 'panel',
width: 1150,
widthRatio: .75,
items: [{
xtype: 'userbutton',
action: '',
text: 'Print'
},
{
xtype: 'userbutton',
action: '',
text: 'Download'
},
{
xtype: 'userbutton',
action: 'chart',
text: 'Chart!'
}]
}]}]
});
}});
Thank you for any tips on getting this layout to work
You should run Ext.application method after extjs loads /var/www/application/ux/layout/Center.js script. To do this, just add a callback using Ext.onReady
Ext.Loader.setPath('Ext.ux', '/var/www/application/ux');
Ext.require('Ext.ux.layout.Center');
Ext.onReady(function () {
Ext.application({ ... });
});
But the right way is using "requires" configuration property
Ext.application({
requires: ['Ext.ux.layout.Center'],
name: 'AM',
appFolder: 'app',
controllers: ['Users'],
launch: function(){
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
Ext.create('Ext.container.Viewport', {
width: 1150,
height: 'auto',
autoScroll: 'true',
layout: 'anchor',
items:[{xtype: 'userpanel'},
{
xtype: 'panel',
width: 1150,
layout:'ux.center',
items:[{
xtype: 'panel',
width: 1150,
widthRatio: .75,
items: [{
xtype: 'userbutton',
action: '',
text: 'Print'
},
{
xtype: 'userbutton',
action: '',
text: 'Download'
},
{
xtype: 'userbutton',
action: 'chart',
text: 'Chart!'
}]
}]}]
});
}});
Also you can read following material http://docs.sencha.com/ext-js/4-1/#!/api/Ext.app.Application
You can also create your own class for viewport and put it in the [appFolder]/view/ folder
Ext.define('AM.view.Viewport', {
extend: 'Ext.view.Viewport',
requires: ['Ext.ux.layout.Center'],
width: 1150,
height: 'auto',
autoScroll: 'true',
layout: 'anchor',
initComponent: function () {
this.items = [{
xtype: 'userpanel'
}, {
xtype: 'panel',
width: 1150,
layout:'ux.center',
items:[{
xtype: 'panel',
width: 1150,
widthRatio: .75,
items: [{
xtype: 'userbutton',
action: '',
text: 'Print'
}, {
xtype: 'userbutton',
action: '',
text: 'Download'
}, {
xtype: 'userbutton',
action: 'chart',
text: 'Chart!'
}]
}]
}];
this.callParent();
}
});
And use Ext.app.Application config property autoCreateViewport. It will load [appFolder]/view/Viewport.js script and use it as viewport
Ext.application({
name: 'AM',
appFolder: **insert you app folder path here**, // in you case it will be 'application'
controllers: ['Users'],
autoCreateViewport: true
});

ExtJs 4 MVC Nested Layouts

I'm trying to implement a simple framework for an app. The idea is to create a background viewport type 'layout' with a north region containing the page header and an interchangeable center region.
When my app starts, a Login form is shown. If the user/password is ok, the form is destroyed and the main layout should appear. The main layout should insert a nested layout in its center region.
This is my background layout code:
Ext.define('DEMO.view.BackgroundLayout', {
extend: 'Ext.container.Viewport',
alias: 'widget.background',
requires: [
'DEMO.view.Main'
],
layout: {
type: 'border'
},
initComponent: function() {
var me = this;
Ext.applyIf(me, {
items: [
{
region: 'north',
html: '<h1 class="x-panel-header">Page Title</h1>'
},
{
xtype: 'mainview',
region: 'center',
forceFit: false,
height: 400
}
]
});
me.callParent(arguments);
}
});
The main layout is this:
Ext.define('DEMO.view.Main', {
extend: 'Ext.container.Viewport',
alias: 'widget.mainview',
requires: [
'DEMO.view.MyGridPanel'
],
layout: {
type: 'border'
},
initComponent: function() {
var me = this;
console.log('bb');
Ext.applyIf(me, {
items: [
{
xtype: 'mygridpanel',
region: 'center',
forceFit: false
},
{
xtype: 'container',
height: 38,
forceFit: false,
region: 'north',
items: [
{
xtype: 'button',
height: 34,
id: 'btnLogout',
action: 'logout',
text: 'Logout'
}
]
}
]
});
me.callParent(arguments);
}
});
As you can see, the center region needs an xtype named "mygridpanel". This is the code for it:
Ext.define('DEMO.view.ui.MyGridPanel', {
extend: 'Ext.grid.Panel',
border: '',
height: 106,
title: 'My Grid Panel',
store: 'MyJsonStore',
initComponent: function() {
var me = this;
Ext.applyIf(me, {
viewConfig: {
},
columns: [
{
xtype: 'gridcolumn',
dataIndex: 'Id',
text: 'Id'
},
{
xtype: 'gridcolumn',
dataIndex: 'Name',
text: 'Name'
},
{
xtype: 'gridcolumn',
dataIndex: 'Sales',
text: 'Sales'
}
],
dockedItems: [
{
xtype: 'toolbar',
dock: 'top',
items: [
{
xtype: 'button',
disabled: true,
id: 'btnDelete',
allowDepress: false,
text: 'Delete'
},
{
xtype: 'button',
disabled: true,
id: 'btnEdit',
allowDepress: false,
text: 'Edit'
}
]
}
]
});
me.callParent(arguments);
}
});
My problem is that when I call Ext.create('DEMO.view.BackgroundLayout', {}); it only shows the nested layout, and the background layout is hidden, also I get this error in Chrome's console:
Uncaught Error: HIERARCHY_REQUEST_ERR: DOM Exception 3
What I'm doing wrong?.
Thanks in advance,
Leonardo.

Categories