Proper components usage in ST2 application - model-view-controller

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).

Related

Is it possible to navigate from TapPanel in Sencha Touch?

I am using the Sencha Touch TapPanel and want to navigate down on a view from a view.
Ext.create('Ext.TabPanel', {
itemId: 'panel',
fullscreen: true,
defaults: {
styleHtmlContent: true
},
tabBarPosition: 'bottom',
layout: {
type: 'card',
animation: {
type: 'fade'
}
},
items: [{
title: 'Home',
html: 'Home Screen'
}, {
title: 'Contact',
xtype: 'OfferDetailView'
}]
});
If the user is on the OfferDetailView, I want to have a button and if the user clicks on the button, it should navigate to a view foo and display it with an back button to get back to the tabpanel. Is there any Sencha Touch functionality or frameworks, which is supporting this issue?
I can set the activeItem to a view with
Ext.Viewport.animateActiveItem(foo, {type: 'slide', direction: 'left'});
but there is no back button. So I have to add it manually and manage all the views on a stack.
You should create an Ext.navigation.View that contains the Ext.tab.Panel as the only object. Then you can push() your new view onto that view and it will work as you're hoping.
Ext.create('Ext.navigation.View', {
itemId: 'navView',
layout: 'fit',
items: [
{
xtype: 'tabpanel',
tabBarPosition: 'bottom',
items: [{
title: 'Home',
html: 'Home Screen'
}, {
title: 'Contact',
xtype: 'OfferDetailView',
items: [
{
xtype: 'button',
text: 'Go to Foo',
handler: function(btn) {
btn.up('navigationview').push({ xtype: 'foo' });
}
}
]
}]
}
]
});

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).

How to add a form xtype sencha touch 2.0

Currently I am teaching myself Sencha Touch 2.0 and I am encountering a problem with adding a xtype called test to my viewport.
The test class is extending "Ext.form.Panel'" the problem is that no form shows up in my view and sencha also doesn't give any errors. When I extend "Ext.Panel" and set a html attribute this does show up. Can someone tell me what i am doing wrong ?
Viewport file
Ext.define('App.view.Viewport', {
extend: 'Ext.viewport.Default',
config: {
scrollable: true,
fullscreen:true,
items:[
{
xtype: "panel",
items: [
{
xtype:"toolbar",
title:"Test App"
},
{
xtype:"panel",
items: [
{
xtype:"test"
}
]
}
]
}
]
}
});
Controller file
//Define controller name
Ext.define('App.controller.User', {
//Extend the controller class
extend: 'Ext.app.Controller',
//define associated views with this controller
views: ['user.Test'],
init: function()
{
//do something and setup listeners
//setup listeners
}
});
View File
Ext.define('App.view.user.Test', {
extend: 'Ext.form.Panel',
alias: 'widget.test',
config: {
items: [
{
xtype: 'textfield',
name: 'name',
label: 'Name'
},
{
xtype: 'emailfield',
name: 'email',
label: 'Email'
},
{
xtype: 'passwordfield',
name: 'password',
label: 'Password'
}
]
},
initialize: function() {
console.log('initialize home view');
this.callParent();
}
});
Simply specify
xtype: 'test'
in your App.view.user.Test definition
I have got it sorted. Have a look at:
http://www.sencha.com/forum/showthread.php?191765-My-Ext.form.Panel-object-does-not-want-to-show&p=767689#post767689

Extjs 4.0 MVC - how to close a view from within the controller?

I have a simple example here with a modal window that is a 'view'. I want to have a button within the window that does a window close, so the lazy user doesn't need to click the 'X' in top right.
My problem is I don't know how to reference the view from within the controller. In the non-MVC world I would just do a 'window.close()' in the button handler. Any ideas? Thanks!
View
Ext.define('AM.view.testwindow.window', {
extend: 'Ext.window.Window',
alias: 'widget.TESTwindow',
title: 'TEST Window',
layout: 'border',
width: 1000, height: 400,
minimizable: true,
maximizable: true,
closeAction: 'destroy',
initComponent: function () {
this.items = [
{xtype: 'gridpanel', region: 'center', // grid in the window
store: 'Equipments',
columns: [
{ text: 'Equip ID', dataIndex: 'EquipmentID' }
, { text: 'StationID', dataIndex: 'StationID' }
],
dockedItems: [{
xtype: 'toolbar', // Grid's toolbar
items: [
{
xtype: 'button', /* Close button to close the window */
text: 'Close Window',
itemId: 'btnTestClose'
}
]
}
]
}
];
this.callParent(arguments);
}
});
Controller
Ext.define('AM.controller.testwindow', {
extend: 'Ext.app.Controller',
stores: ['Equipments', 'Stations'],
models: ['Equipment'],
views: ['testwindow.window', 'testwindow.Grid'],
refs: [
{ ref: 'TESTgrid', selector: 'TESTgrid' },
{ ref: 'testwindow', selector: 'testwindow' }
],
init: function () {
this.control(
{
'#btnTestClose': {
click: function (butt, e, options) {
alert('close handler!');
this.getTestwindowWindowView().close(); // this fails. What should I do? ComponentQuery ?
}
}
}
)
}
}
);
Scope of 'this' from within Button handler
Your ref to the test window should match the alias TESTwindow (without the widget part), or maybe the long name testwindow.window:
refs: [
{ ref: 'TESTgrid', selector: 'TESTgrid' },
{ ref: 'TESTwindow', selector: 'testwindow' }
],
This will give you the autogenerated getter you need:
this.getTestwindow().close();
Getters are composed of get plus the reference selector with uppercase first letter.
refs: [
{ ref: 'TESTgrid', selector: 'TESTgrid' },
{ ref: 'win', selector: 'testwindow' }
],
Try this
this.getWin().close();
ready ok

Resources