Sencha Touch Swap Panels - panel

I just started using sencha touch recently and so far I've got this built:
app.js:
Ext.regApplication({
name: 'app',
launch: function() {
this.launched = true;
this.mainLaunch();
},
mainLaunch: function() {
if (!device || !this.launched) {return;}
this.views.viewport = new this.views.Viewport();
}
});
Viewport.js:
app = Ext.extend(Ext.TabPanel, {
fullscreen: true,
sortable: false,
tabBar: {
dock: 'bottom',
layout: {pack: 'center'}
},
cardSwitchAnimation: {
type: 'slide',
cover: true
},
initComponent: function() {
Ext.apply(app.views, {
searchListTab: new app.views.SearchListTab(),
searchTab: new app.views.SearchTab(),
mapTab: new app.views.MapTab(),
infoTab: new app.views.InfoTab()
});
Ext.apply(this, {
items: [
app.views.searchTab,
app.views.mapTab,
app.views.infoTab
]
});
app.views.Viewport.superclass.initComponent.apply(this, arguments);
}
});
SearchTab.js
app.views.SearchTab = Ext.extend(Ext.Panel, {
title: 'Search',
iconCls: 'search',
dockedItems: [{
xtype: 'toolbar',
title: 'Search'
}],
items: [
{
xtype: 'button',
ui: 'round',
text: 'Hledej',
listeners: {
tap: function() {
Ext.dispatch({
controller: app.controllers.main,
action: 'search',
animation: {type:'slide', direction:'right'}
});
}
}
}
],
initComponent: function() {
app.views.SearchTab.superclass.initComponent.apply(this, arguments);
}
});
SearchListTab.js
app.views.SearchListTab = Ext.extend(Ext.Panel, {
title: 'Search',
iconCls: 'search',
dockedItems: [{
xtype: 'toolbar',
title: 'Search Results'
}],
items: [{
xtype: 'list',
store: app.stores.results,
itemTpl: '{titul}',
grouped: false
//onItemDisclosure: function (record) {
//Ext.dispatch({
// controller: app.controllers.contacts,
// action: 'show',
// id: record.getId()
//});
//}
}],
initComponent: function() {
app.stores.results.load();
app.views.SearchListTab.superclass.initComponent.apply(this, arguments);
}
});
and search.js
app.controllers.main = new Ext.Controller({
search: function(options) {
app.views.searchTab.setActiveItem(
app.views.searchListTab, options.animation
);
}
});
and some other stuff which is not important now. So basically I've got a main viewport which is a tabpanel, then few panels which are its items and one panel which is nowhere from the beginning. Now I want to achieve, that when I click the button in searchTab I want the searchTab panel to swap with searchListTab panel. The problem is, when I use app.views.viewport.setActiveItem(...); it works fine, but it adds a new tab to the tab panel. I just want the current tab panel to slide to another panel, but when I use the code I posted here - app.views.searchTab.setActiveItem(...); it doesn't do anything.
What am I doing wrong? Thanks.

I think you will have to introduce another layer of nesting to achieve this.
I think you want to nest your SearchTab in another Ext.Panel with a card layout and add your SearchListTab to this panel when needed and then you can use the setActiveItem() method to slide across. This will keep your TabPanel visible while moving between sub-views within a tab.
I've drawn a wee diagram to try and explain it better! The black box is the new Panel I think you should add which will replace the SearchTab as the item directly added to the TabPanel.
Hope this helps and is clear!

Related

Proper components usage in ST2 application

I have a quite simple mobile app I want to build with Sencha Touch 2. I have quite a lot of experience with ExtJs, but not really with their MVC architecture. What I want to achieve is :
first a main screen with toolbar and some icons rendered in the middle which are to be used to navigate across the app functionality.
clicking one of the icons should switch to a screen with a scrollable list.
What I'm struggling with is the proper place to define the views, and controllers. As well as should for example the main screen use a controller ? Should I create a viewport manually or not ?
What I have right now, which is not rendering anything apart of the toolbar :
app.js
Ext.application({
name: 'SG',
views: [
'Main',
'MainScreen'
],
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
Ext.Viewport.add(Ext.create('SG.view.Main'));
}
})
Main.js
Ext.define('SG.view.Main', {
extend: 'Ext.Container',
requires: [
'Ext.TitleBar',
'ShopGun.view.MainScreen'
],
config: {
layout : 'fit',
items: [
{
title: 'Welcome',
iconCls: 'home',
position: 'top',
scrollable: true,
items: [
{
docked: 'top',
xtype: 'titlebar',
title: 'SG Alpha 1'
}
Ext.create('SG.view.MainScreen', {
docked: 'bottom'
})
]
}
]
}
});
MainScreen.js
Ext.define('SG.view.MainScreen', {
extend: 'Ext.Container',
xtype: 'mainScreen',
initialize : function(){
Ext.define("MenuIcon", {
extend: "Ext.data.Model",
config: {
fields: [
{name: "Name", type: "string"},
{name: "Icon", type: "string"}
]
}
});
this.store = Ext.create('Ext.data.Store', {
model: 'MenuIcon',
data: [
{
Name: "A",
Icon: "a.png"
},
{
Name: "B",
Icon: "b.png"
}
]
});
this.html = 'foo';
this.callParent(arguments);
}
});
And finally an image of what I'd like to get :
EDIT:
A senchafiddle demo here : http://www.senchafiddle.com/#jSqtV (which is not rendering at all but doesn't throw any errors).

activate/deactivate config listeners not firing in navigationview to hide navigationbar button in sencha touch 2

I am attempting to do something which (at least I believe) should be very straightforward in ST2 but it is not working. I have a main view (xtype: navigationview) and a secondary view (xtype: container). There is a button in the navigationbar on the main view that should be hidden when navigating to the secondary view and shown when returning to the main view. I have added the code to mark the setHidden(true) in the main view config listeners but neither of the events fire.
Is there maybe a better way of doing this?
Main view:
Ext.define('MyApp.view.Main', {
extend: 'Ext.navigation.View',
xtype: 'main',
requires: [
'Ext.dataview.List'
],
config: {
navigationBar: {
items: [
{
xtype: 'button',
iconCls: 'refresh',
iconMask: true,
itemId: 'refreshBtn',
align: 'left'
}
]
},
items: [
{
xtype: 'button',
itemId: 'next-page-button',
text: 'Next Page'
}
],
listeners: {
activate: function() {
this.query('[itemId=refrehBtn]')[0].setHidden(false);
},
deactivate: function() {
this.query('[itemId=refrehBtn]')[0].setHidden(true);
}
}
},
initialize: function() {
this.callParent();
}
});
Sencondary view:
Ext.define('MyApp.view.Main2', {
extend: 'Ext.Container',
xtype: 'main2',
config: {
items: [
{
xtype: 'panel',
items: [
{
xtype: 'panel',
html: 'second view'
},
]
}
]
}
});
Controller:
Ext.define('MyApp.controller.TestController', {
extend: 'Ext.app.Controller',
config: {
refs: {
nextPgBtn: '[itemId=next-page-button]'
},
control: {
nextPgBtn: {
tap: 'showNextPg'
}
}
},
showNextPg: function(btn, e, opts) {
btn.up('navigationview').push({
xtype: 'main2'
});
}
});
Firstly, you need to change your query to correctly retrieve your button. Change this:
this.query('[itemId=refrehBtn]')[0].setHidden(false);
to this:
Ext.ComponentQuery.query('#refreshBtn')[0].setHidden(false);
Secondly, instead of using activate and deactivate event, you should make use of back
event which fires when the back button in the navigation view was tapped. and push event which fires when a view is pushed into this navigation view in order to show and hide your button accordingly:
back: function() {
Ext.ComponentQuery.query('#refreshBtn')[0].setHidden(false);
},
push: function() {
Ext.ComponentQuery.query('#refreshBtn')[0].setHidden(true);
}
Here is a demo: http://www.senchafiddle.com/#GSt6x

Load another view after login with sencha touch 2.0

I'm having a dumb problem and I would like you to give me a hand.Thanks in advance.
The situatios is as follows: I have 2 wiews (both created with sencha architect 2.0), one for login, and another for general purposes. And I would like to load the second view on successful response when trying to log in, this is, after any successful login. The main problem is that I've tried with Ex.create, Ext.Viewport.add, Ext.Viewport.setActiveItem, but I can't manage to make the second view to appear on screen, the login screen just keeps there and the app does not load the other view. Another thing, I don't have to use a navigation view for this.
Here is the code of my controller, from which I want to load my second view. And as you'll see, I even created a reference of the view, which has autoCreate enabled and has that ID "mainTabPanel":
Ext.define('MyApp.controller.Login', {
extend: 'Ext.app.Controller',
config: {
refs: {
loginButton: {
selector: '#login',
xtype: 'button'
},
username: {
selector: '#user',
xtype: 'textfield'
},
password: {
selector: '#pass',
xtype: 'passwordfield'
},
mainTabPanel: {
selector: '#mainTabPanel',
xtype: 'tabpanel',
autoCreate: true
}
},
control: {
"loginButton": {
tap: 'onLoginButtonTap'
}
}
},
onLoginButtonTap: function(button, e, options) {
Ext.Ajax.request({
url: '../../backend/auth.php',
method: 'POST',
params: {
user: this.getUsername().getValue(),
pass: this.getPassword().getValue()
},
success: function(response) {
var json = Ext.decode(response.responseText);
if (json.type == 'success') {
// LOAD THE DAMN SECOND VIEW HERE!
//var paneltab = Ext.create('MyApp.view.MainTabPanel');
//Ext.Viewport.add(paneltab);
//Ext.Viewport.setActiveItem(this.getMainTabPanel());
} else {
alert(json.value);
}
},
failure: function(response) {
alert('The request failed!');
}
});
}
});
And here is the code of my login view:
Ext.define('MyApp.view.LoginForm', {
extend: 'Ext.form.Panel',
config: {
id: 'loginForm',
ui: 'light',
items: [
{
xtype: 'fieldset',
ui: 'light',
title: 'Log into the system',
items: [
{
xtype: 'textfield',
id: 'user',
label: 'User',
name: 'user'
},
{
xtype: 'passwordfield',
id: 'pass',
label: 'Pass',
name: 'pass'
}
]
},
{
xtype: 'button',
id: 'login',
ui: 'confirm',
text: 'Login'
}
]
}
});
And finally, the code of the view I want to load. This view loads normally if I set it as the Initial View, but does not load when a successful login occurs:
Ext.define('MyApp.view.MainTabPanel', {
extend: 'Ext.tab.Panel',
config: {
id: 'mainTabPanel',
layout: {
animation: 'slide',
type: 'card'
},
items: [
{
xtype: 'container',
layout: {
type: 'vbox'
},
title: 'Tab 1',
iconCls: 'time',
items: [
{
xtype: 'titlebar',
docked: 'top',
title: 'General Report',
items: [
{
xtype: 'button',
iconCls: 'refresh',
iconMask: true,
text: '',
align: 'right'
}
]
},
{
xtype: 'container',
height: 138,
flex: 1,
items: [
{
xtype: 'datepickerfield',
label: 'From',
placeHolder: 'mm/dd/yyyy'
},
{
xtype: 'datepickerfield',
label: 'To',
placeHolder: 'mm/dd/yyyy'
},
{
xtype: 'numberfield',
label: 'Hours'
}
]
},
{
xtype: 'dataview',
ui: 'dark',
itemTpl: [
'<div style="height:50px; background-color: white; margin-bottom: 1px;">',
' <span style="color: #0000FF">{user}</span>',
' <span>{description}</span>',
'</div>'
],
store: 'hoursStore',
flex: 1
}
]
},
{
xtype: 'container',
title: 'Tab 2',
iconCls: 'maps'
},
{
xtype: 'container',
title: 'Tab 3',
iconCls: 'favorites'
}
],
tabBar: {
docked: 'bottom'
}
}
});
Please, I need help... :)
I'm stuck here for like 3 days now and can't figure out what the problem is. Thank you.
Could you post your app.js too?
I'm trying your code here and it load the view as expected. Here is my app.js:
Ext.application({
name: 'MyApp',
requires: [
'Ext.MessageBox'
],
controllers: ['Login'],
views: ['LoginForm','MainTabPanel'],
icon: {
'57': 'resources/icons/Icon.png',
'72': 'resources/icons/Icon~ipad.png',
'114': 'resources/icons/Icon#2x.png',
'144': 'resources/icons/Icon~ipad#2x.png'
},
isIconPrecomposed: true,
startupImage: {
'320x460': 'resources/startup/320x460.jpg',
'640x920': 'resources/startup/640x920.png',
'768x1004': 'resources/startup/768x1004.png',
'748x1024': 'resources/startup/748x1024.png',
'1536x2008': 'resources/startup/1536x2008.png',
'1496x2048': 'resources/startup/1496x2048.png'
},
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
//Ext.Viewport.add(Ext.create('MyApp.view.Main'));
Ext.Viewport.add(Ext.create('MyApp.view.LoginForm'));
},
onUpdated: function() {
Ext.Msg.confirm(
"Application Update",
"This application has just successfully been updated to the latest version. Reload now?",
function(buttonId) {
if (buttonId === 'yes') {
window.location.reload();
}
}
);
}
});
Destroy the login panel, You don't really need it anymore...
success: function(response) {
var json = Ext.decode(response.responseText);
if (json.type == 'success') {
// LOAD THE DAMN SECOND VIEW HERE!
var paneltab = Ext.create('MyApp.view.MainTabPanel');
Ext.getCmp('loginForm').destroy();
Ext.Viewport.add(paneltab);
} else {
alert(json.value);
}
},
There are several problems here:
Your autoCreate rule uses an xtype: 'tabpanel' which will only ever create a vanilla Ext.TabPanel with no items in it. You'd need to assign an xtype attribute to your MyApp.view.MainTabPanel like xtype: 'mainTabPanel' and then use that xtype value in your autoCreate rule.
This then explains why this code won't work since this.getMainTabPanel() will return the wrong object. Simpler would be to just use Ext.Viewport.setActiveItem(paneltab).
In general, you usually don't want assign an id to a view (id: 'mainTabPanel'). Safer to just use an xtype to fetch it. Although you don't need it in this case, avoiding global id's allows you to create multiple instances of a view (or any other class type).

MVC Sencha Touch Won't Properly Display Tab Panels

I have a MVC Sencha Touch application I'm building and am having some issues getting the TabPanel to function correctly. The issue is this, when I have my PosViewport.js like this, everything works fine:
touch.views.PosViewport = new Ext.extend(Ext.TabPanel, {
initComponent: function () {
console.log("inside initComponent() of PosViewport.js");
touch.views.PosViewport.superclass.initComponent.call(this);
},
tabBar: {
dock: 'bottom',
layout: {
pack: 'center'
}
},
layout: 'fit',
scroll: 'vertical',
items: [
{
title: 'Reciepts',
iconCls: 'bookmarks',
html: 'one'
},
{
title: 'POS',
iconCls: 'Favorites',
html: 'two'
}
]
});
Here, everything is great! The tab bar shows up on the bottom, it fits perfectly, and I can switch back and forth between the two with no problems.
However, instead of keeping those panels inside my PosViewport.js file, let's move them out to two seperate files:
View1.js:
touch.views.View1 = new Ext.extend(Ext.Panel, {
initComponent: function () {
touch.views.View1.superclass.initComponent.call(this);
},
layout: 'fit',
scroll: 'vertical',
fullscreen : true,
title: 'Reciepts',
iconCls: 'bookmarks',
html: 'panel one'
});
and View2.js:
touch.views.View2 = new Ext.extend(Ext.Panel, {
initComponent: function () {
touch.views.View2.superclass.initComponent.call(this);
},
layout: 'fit',
scroll: 'vertical',
fullscreen : true,
title: '2',
iconCls: 'bookmarks',
html: 'panel two'
});
I add both new views to my index.html. Now, I update my PosViewport.js to point to the new views:
touch.views.PosViewport = new Ext.extend(Ext.TabPanel, {
initComponent: function () {
console.log("inside initComponent() of PosViewport.js");
touch.views.PosViewport.superclass.initComponent.call(this);
},
tabBar: {
dock: 'bottom',
layout: {
pack: 'center'
}
},
layout: 'fit',
scroll: 'vertical',
items: [ touch.views.View1, touch.views.View2]
});
And it all goes to hell. The Bottom Tab Bar is not visible, as only a tiny piece of the top is visible on the page. The panels do not show up at all, I cannot see their HTML content at all.
What is going on here? I have absolutely no idea why it is behaving like this. Any pointers in the right direction are much appreciated, thank you!
In the second case you created two classes by this:
touch.views.View2 = new Ext.extend(Ext.Panel, { // Class definition
whereas you needed two instances of these panels. So, add the items like this:
items: [new touch.views.View1(), new touch.views.View2()] // Panel instance
This should work now. And remove the fullscreen:true option from these panels. fullscreen means, it will make the panels take whole viewport area.

ExtJS toolbar not rendering correctly

I have a window where I'd like to add a toolbar at the top, and a panel for loading content in the remaining area. Unfortunately, the toolbar expands to a disproportionate size when I add the content panel. I've tried hardcoding the size, but that doesn't seem to work. What am I doing wrong?
Thanks in advance for responses:
// Main application entry point
Ext.onReady(function() {
var loginWin;
var mainWin;
var content;
var form = new Ext.form.FormPanel({
baseCls: 'x-plain',
labelWidth: 70,
//url:'',
defaultType: 'textfield',
items: [{
fieldLabel: ' User Name',
name: 'username',
anchor:'100%' // anchor width by percentage
},{
inputType: 'password',
fieldLabel: ' Password',
name: 'password',
anchor: '100%' // anchor width by percentage
}]
});
content = new Ext.Panel({
baseCls: 'x-plain',
layout:'fit',
anchor:'90%',
height: 500,
items: [
{
title: 'blah',
html: '<div>hello</div>'
}
]
});
var tb = new Ext.Toolbar({
height: 100,
//renderTo: mainWin
});
tb.render('toolbar');
var toolbarPanel = new Ext.Panel({
layout:'fit',
anchor:'10%',
width:100,
items: tb
});
var menu = new Ext.menu.Menu({
id: 'mainMenu',
style: {
overflow: 'visible' // For the Combo popup
},
items: [
{ text: 'blah'
},
{ text: 'blah2'
}
]
});
tb.add(
{
text: 'Classes',
iconCls: 'bmenu',
handler: function(){ alert('blah'); }
},
{
text: 'GPA',
iconCls: 'bmenu',
handler: function(){ alert('blah'); }
},
{
text: 'Semester Schedule',
iconCls: 'bmenu',
handler: function(){
}
},
{
text: 'Help',
iconCls: 'bmenu', // <-- icon
handler: function(){ alert('blah'); }
}
);
tb.doLayout();
if(!mainWin){
mainWin = new Ext.Window({
applyTo:'main-win',
resizable: false,
modal: true,
layout:'fit',
width:'80%',
height:'100%',
y: 0,
closeAction:'hide',
plain: true,
items: [ toolbarPanel, content ]
});
}
if(!loginWin){
loginWin = new Ext.Window({
applyTo:'hello-win',
closable:false,
layout:'fit',
width:300,
height:130,
closeAction:'hide',
plain: true,
items: form,
buttons: [{
text:'Login',
handler: function(){
loginWin.hide();
mainWin.show();
}
},{
text: 'Close',
handler: function(){
loginWin.hide();
}
}]
});
loginWin.show(this);
}
})
Seems you are working with the toolbar improperly:
var toolbarPanel = new Ext.Panel({
layout:'fit',
anchor:'10%',
width:100,
items: tb
});
Here you are telling this panel, "Take your one item, and make it as big as me". That is what layout "fit" does. So naturally, it will takes the toolbar you give it in the items and expand it as big as the panel.
Ext.Panel objects have a tbar config property that is designed to hold your toolbar. You don't need a panel for a toolbar and another panel for your content. Instead, add the toolbar to your content panel. Also, don't worry about rendering the toolbar explicitly, or adding items after the fact. It is better and more clear to write the objects together where they will be initialized (if this is possible)
Here is how I would recommend creating your content panel:
content = new Ext.Panel({
baseCls: 'x-plain',
layout:'fit',
tbar: [
{
text: 'Classes',
iconCls: 'bmenu',
handler: function(){ alert('blah'); }
},
{
text: 'GPA',
iconCls: 'bmenu',
handler: function(){ alert('blah'); }
},
{
text: 'Semester Schedule',
iconCls: 'bmenu',
handler: function(){
}
},
{
text: 'Help',
iconCls: 'bmenu', // <-- icon
handler: function(){ alert('blah'); }
}],
items: [
{
title: 'blah',
html: '<div>hello</div>'
}
]
});
Note also that I took out your panel's height attribute, since it is being put in a window with layout "fit", so that window will do all the sizing (no need to specify on the panel itself).
mainWin = new Ext.Window({
applyTo:'main-win',
resizable: false,
modal: true,
layout:'fit',
width:'80%',
height:'100%',
y: 0,
closeAction:'hide',
plain: true,
items: [ content ]
});
Good luck!
Note that Ext.Toolbar has a default minHeight value set ("2.6em", iirc) -- you may have to override this in your config.
This is not your issue, but I had a problem with minified ExtJS code not rendering. The tbar had a spacer between items, even though the unminified toolbar rendered correctly. I think Sencha has a dedicated function for this, but it fixed it.
}, ' ', {

Resources