How to use up() in Ext.Button handler - sencha-touch

Back Ground : I am working on an MVC application using sencha touch 2. I am working on a page which has two tabs. Inside the first tab, I have a button inside a title bar.
Issue : I am not able to call anyother function from the button handler. I think, there is an issue with the scope of the calling function.
Here is my code.
Ext.define('WUPOC.view.WUHomePage', {
extend: 'Ext.TabPanel',
requires:['Ext.TitleBar','Ext.dataview.List','Ext.data.proxy.JsonP'],
alias: 'widget.wuHomePageView',
config: {
fullscreen: true,
defaults: {
styleHtmlContent: true
},
items: [{
title: 'Home',
iconCls: 'home',
items: [{
xtype: 'titlebar',
title: 'Hello',
docked: 'top',
items: [{
xtype: 'button',
text: 'LogOut',
ui: 'action',
itemId: 'newButton',
align: 'right',
handler : function(btn){
console.log('LogOut is tapped'); // This is printed
this.up.onNewButtonTap(); // Throws error
}
}],
}],
}, {
title: 'Contact',
iconCls: 'user',
html: 'Contact Screen'
}]
},
onNewButtonTap: function () {
alert('newNoteCommand');
},
});
I am getting the error as below.
Uncaught TypeError: Object function (selector) {
var result = this.parent;
if (selector) {
for (; result; result = result.parent) {
if (Ext.ComponentQuery.is(result, selector)) {
return result;
}
}
}
return result;
} has no method 'onNewButtonTap'
I think there is an issue with setting the scope of a button. Kindly help.
Thank you

First, up is a function so you need to call it this way :
this.up();
Then this.up() would only bring to the container of the button, which has no method onNewButtonTap. You could just keep doing up() until you get the right component but this would me more clever to do :
Add an xtype to your view
Use this xtype as a selector in the up function : this.up('myXType').onNewButtonTap();
Example
Hope this helps

Related

Controller ref not working

In my SenchaTouch 2.3.1 app I have build a login panel for the user. It looks like this:
Ext.define('MyApp.view.LoginPanel', {
extend: 'Ext.form.Panel',
alias: 'widget.loginPanel',
requires: [
'Ext.form.FieldSet',
'Ext.field.Password',
'Ext.Button'
],
config: {
layout: 'vbox',
items: [
{
xtype: 'fieldset',
title: 'Business Login',
itemId: 'login',
items: [
{
xtype: 'emailfield',
itemId: 'email',
label: 'E-Mail',
name: 'email',
required: true
},
{
xtype: 'passwordfield',
itemId: 'password',
label: 'Passwort',
name: 'password',
required: true
}
]
},
{
xtype: 'button',
itemId: 'loginButton',
cls: 'button-blue',
text: 'Login'
},
{
xtype: 'panel',
itemId: 'loggedInPanel',
cls: 'logged-in-panel',
tpl: [
'Sie sind eingeloggt als {firstname} {lastname} (ID: {agentId})'
],
hidden: true,
margin: '10 0'
}
]
}
});
In my controller, I want to use a reference to this panel like this:
config: {
refs: {
loginPanel: 'loginPanel',
navigationView: '#morenavigation',
loggedInPanel: '#loggedInPanel',
loginButton: '#loginButton'
}
}
In the launch function of the controller, I want to check if the user already logged in to show his id and show a logout button. But when I try to get the panel ref, it's undefined. But why?
launch: function() {
var me = this,
sessionInfo = Ext.getStore('SessionInfo');
console.log(me.getLoginPanel()); <-- undefined
if (null !== sessionInfo.getAt(0).get('sessionId')) {
me.successfullLogin(sessionInfo.getAt(0).get('sessionId'));
}
}
Is anything actually creating an instance of your view?
Inside your application's launch method, you'll probably have to create an instance of it, and then either give your view the fullscreen: true config, or add it to the viewport. The examples on the Sencha Touch API docs for Ext.app.Application have the main view being created from the application's launch function.
The correct way of using the ref in my example would be:
refs: {
loginPanel: {
autoCreate: true,
forceCreate: true,
xtype: 'loginPanel'
}
}

Rendering a List in a Panel

I have a Panel where I render a search-form. This works.
My problem is rendering a List under that search-form (so in the same Panel).
This is what I've done so far:
Ext.define("TCM.view.UserSearch",
{
extend: "Ext.form.Panel",
requires:
[
"Ext.form.FieldSet",
"Ext.List"
],
xtype: "usersearch",
config:
{
scrollable:'vertical'
},
initialize: function ()
{
this.callParent(arguments);
var clubsStore = Ext.create('TCM.store.Clubs');
clubsStore.load();
var usersStore = Ext.create('TCM.store.Users');
var searchButton =
{
xtype: 'button',
ui: 'action',
text: 'Search',
handler: this.onSearchButtonTap,
scope: this
};
var topToolbar =
{
xtype: 'toolbar',
docked: 'top',
title: 'Search',
items: [
{ xtype: 'spacer' },
searchButton
]
};
var userClub =
{
xtype: 'selectfield',
store: clubsStore,
name: 'clubId',
label: 'Club',
displayField : 'name',
valueField : 'id',
required: true
};
var userList =
{
xtype: 'list',
store: usersStore,
itemTpl: '{name}',
title: 'Search results'
};
this.add([
topToolbar,
{
xtype: "fieldset",
items: [userClub]
},
userList
]);
},
onSearchButtonTap: function ()
{
console.log("searchUserCommand");
this.fireEvent("searchUserCommand", this);
}
});
I can't see anything being rendered under the fieldset (the searchform). What could be wrong?
Most of time, when you don't see a component it's because you did not set a layout to your container or a height.
You can find more about layout here.
In your case, you want to have two components in your container. Therefore, I suggest a Vbox layout.
Here's an example
Hope this helps.
I actually used something like this in a project try this...Put this in the items property of your fieldset...
{
xtype: 'searchfield',
clearIcon: true,
placeHolder: 'Type Some text'
},
{
xtype: 'list',
hidden:true, //Initially hidden populate as user types something
height: '150px',
pressedDelay: 1,
loadingText: '',
store: 'listStore',
itemTpl: '{\'What you want to be displayed as per your model field\'}'
}
In your controller write a handler for the keyup event of the searchfield to load the store with relevant data and toggle the hidden property of the list. Hopefully list should appear with the search results(Worked for me and looked quite good). Hope this helps...

Open another view within same tabpanel after button click in first panel

I have a Main view in which i create three tabs, on click login tab a login form open
after login success, i need to load another view (landing) in same login tabpanel..I have used the following lines of code to load the view but it doesnt opening it in same tabpanel but loading as a independent view. How to open it in same tabpanel.
Main View of application
Ext.define("SenchaTest.view.Main", {
extend: 'Ext.tab.Panel',
requires: [
'Ext.TitleBar',
],
config: {
tabBarPosition: 'bottom',
items: [
{
title: 'Home',
iconCls: 'home',
html: [
'<img src="http://staging.sencha.com/img/sencha.png" />',
'<h1>Welcome to Sencha Touch</h1>',
"<p>This demonstrates how ",
"to use tabs, lists and forms to create a simple app</p>",
'<h2>Sencha Touch (2.0.0)</h2>'
].join("")
},
{
title: 'Log In',
iconCls: 'user',
xtype: 'formpanel',
url: 'contact.php',
layout: 'card',
id:"loginForm",
items: [
{
xtype: 'fieldset',
title: 'Log In',
id:"submitForm",
instructions: 'Enter username and password to login.',
defaults: {
required: true,
labelAlign: 'left',
labelWidth: '45%'
},
items: [
{
xtype: 'textfield',
name : 'username',
label: 'User Name',
allowBlank:false,
useClearIcon: true
}, {
xtype: 'passwordfield',
name : 'password',
label: 'Password',
allowBlank:false,
useClearIcon: false
},{
xtype: 'button',
text: 'Submit',
ui: 'confirm',
id: 'btnSubmitLogin'
// this.up('formpanel').submit();
}]
}
]
}
]
}
});
Code for Controller
Ext.define("SenchaTest.controller.LoginForm", {
extend : "Ext.app.Controller",
config : {
refs : {
btnSubmitLogin : "#btnSubmitLogin",
LoginForm : '#loginForm'
},
control : {
btnSubmitLogin : {
tap : "onSubmitLogin"
}
}
},
onSubmitLogin : function(btn) {
alert("onSubmitLogin");
console.log("onSubmitLogin");
var values = this.getLoginForm().getValues();
//alert(values.username);
//alert(values.password);
Ext.util.JSONP.request({
url:'http://localhost:8092/returnjson.ashx',
params:{ callback:'callback',uname:values.username,password:values.password},
callbackKey: 'callback',
success: function (result,request)
{
if(result.status==true)
{
alert("Welcome " + result.UserName);
Ext.Viewport.setActiveItem(Ext.create('SenchaTest.view.Landing'));
}
else
{
alert("Username or Password is incorrect");
return;
}
console.log(result.UserName);
console.log(result);
alert(result);
// Handle error logic
if (result.error) {
alert(response.error);
return;
}
}
});
},
launch : function() {
this.callParent();
console.log("LoginForm launch");
Ext.Viewport.add(Ext.create('SenchaTest.view.Landing'));
},
init : function() {
this.callParent();
console.log("LoginForm init");
}
});
View to load after login landing
Ext.define("SenchaTest.view.Landing", {
extend: "Ext.Container",
xtype: 'landingScreen',
requires: [
"SenchaTest.view.Main"
],
config: {
html: "Welcome to my app"
}
});
i have used...
Ext.Viewport.setActiveItem(Ext.create('SenchaTest.view.Landing'));
to load landing view but it does not load in same tab but as a independent page.
Please Help on this.
The following code allows you to extend Sencha Touch with a 'replace' function that allows you to dynamically swap two view components within the same panel (I believe that is what you are trying to do):
http://www.sencha.com/forum/showthread.php?134909-Replace-component-function&langid=4
An alternative solution (not recommended) is to create a third, but hidden, tab panel ('Landing'), then create and show it on successfully login, while simultaneously hiding the login tab panel.

Android back button click showing blank page

I am new to sencha. Almost spent 2 day to understand sencha routing/history support to implement android back button. but ended up with blank screen always although navigation is working. Please help me to find out what wrong am i doing or what is wrong with my application architecture.
app.js
Ext.application({
name: "WorkFlow",
models: [],
stores: [],
controllers: ["WFController"],
views: ["LoginForm","WorkList"],
launch: function () {
var loginForm = {
xtype: "loginform"
};
var workList = {
xtype: "worklist"
};
Ext.Viewport.add([loginForm,workList]);
// set up a listener to handle the back button for Android
if (Ext.os.is('Android')) {
document.addEventListener("backbutton", Ext.bind(onBackKeyDown, this), false);
function onBackKeyDown(e) {
e.preventDefault();
// you are at the home screen
if (Ext.Viewport.getActiveItem().xtype == loginForm.xtype ) {
navigator.app.exitApp();
}else {
this.getApplication().getHistory().add(Ext.create('Ext.app.Action', {
url: 'loginForm'
}));
}
}
}
}
});
LoginForm.js
var formPanel = null;
Ext.define("WorkFlow.view.LoginForm", {
extend: "Ext.form.Panel",
alias: "widget.loginform",
initialize: function () {
this.callParent(arguments);
formPanel = Ext.create('Ext.form.Panel', {
fullscreen: true,
items: [{
xtype: 'titlebar',
title: 'Login',
docked: 'top'
},
{
xtype: 'fieldset',
items: [
{
xtype: 'textfield',
name : 'username',
label: 'Username',
},
{
xtype: 'passwordfield',
name : 'password',
label: 'Password',
},
{
xtype: 'textfield',
name : 'deviceId',
label: 'Device Id',
}
]
}]
});
formPanel.add({
xtype: 'toolbar',
docked: 'bottom',
layout: { pack: 'center' },
items: [
{
xtype: 'button',
text: 'Login',
handler: this.onLoginTap,
scope: this
},
{
xtype: 'button',
text: 'Cancel',
handler: function() {
formPanel.reset();
}
}
]
});
},
onLoginTap: function() {
this.fireEvent("loginCommand", this);
},
});
WorkList.js
Ext.define("WorkFlow.view.WorkList", {
extend: "Ext.form.Panel",
alias: "widget.worklist",
config:{
html: 'This is worklist...',
}
});
WFController.js
Ext.define("WorkFlow.controller.WFController", {
extend: "Ext.app.Controller",
config: {
refs: {
loginForm: "loginform",
workList: "worklist",
},
control: {
loginForm: {
loginCommand: "onLoginCommand",
}
},
routes: {
'loginForm': 'activateLoginFormPage'
}
},
activateLoginFormPage: function(){
Ext.Viewport.animateActiveItem(this.getLoginForm(), this.slideRightTransition);
},
slideLeftTransition: { type: 'slide', direction: 'left' },
slideRightTransition: { type: 'slide', direction: 'right' },
onLoginCommand: function () {
var values = formPanel.getValues();
window.plugins.AuthPlugin.authenticate(values.username,values.passwordvalues.deviceId,values,
function loginCallBack(result){
if(result=="PASSWORD_MATCH"){
loginForm.onLoginSuccess();
}
});
},
onLoginSuccess: function(){
this.getApplication().getHistory().add(Ext.create('Ext.app.Action', {
url: 'loginFormroute/workList'
}));
Ext.Viewport.animateActiveItem(this.getWorkList(), this.slideRightTransition);
},
launch: function () {
},
init: function () {
}
});
Not totally sure of what you are trying to accomplish, but if it is just regular navigation (press back to return to previous tab etc.) then you do not need to bind anything to the android back button. You should use routes and create a history item for every step the user takes.
Example: I have an app with two tabs, in one of the tabs there is a list of locations and in the second one there is a map with the same locations marked. Pressing on wither a list item or a location in the map generates the same details screen. So this is what I got to get this to work:
Routes:
routes: {
'tab/:tabId': 'gotoTab',
'details/:stnId': 'viewDetails'
},
Important part: ensure that you create history items for each step, I basically have two in this app, one for changing tabs and one for opening a details page.
So, tabs:
//If I change to the 'map' tab, it will navigate the browser to myapp.com/#tab/map
// and therefore creating a history item.
onTabpanelActiveItemChange: function(container, value, oldValue, options) {
this.getApplication().getHistory().add(new Ext.app.Action({
url: 'tab/' + value.id
}), true);
},
Similar for my details page, only it is a function that is called from two seperate handlers (one for the list and one for the map):
showDetails: function(record, staticUrl, doUpdate) {
/*some logic stripped out*/
this.getApplication().getHistory().add(new Ext.app.Action({
url: 'details/' + record.data.id
}), true);
}
After this you are more or less ready to go, if you can guarantee that users always start at the main page. If you enable deep-linking etc. than you will need to restore a state for those links. e.g. a #/tab/map/ link should open the app with the map tab active.
If we take my details page as an example, we have a few things to do. First of all re-create history (press back on details page returns to tab-list by default in my app) and then ensure that stores are loaded and so on.
So as a final example, my viewDetails route:
var store = Ext.StoreManager.get("dcStations");
//recreate history
this.getApplication().getHistory().add(new Ext.app.Action({
url: 'tab/list'
}), true);
this.getApplication().getHistory().add(new Ext.app.Action({
url: 'details/' + stnId
}), true);
//make sure the store is loaded, then show the details page with passed id
store.on("load", function() {
this.showDetails(Ext.StoreManager.get("dcStations").getById(stnId));
}, this);
Hope that this boosts your efforts in getting started with routes and history management

Sencha Formfields passing empty fields

I'm learning Sencha Touch. I created this app with a form before and it worked fine.
Now i'm working on a new little test app i copy the code from the other app and it only passes empty variables to the webservice.
the View:
<!-- language: lang-js -->
Ext.define('Gasoline.view.InsertTankTrip', {
requires: [
'Ext.form.FieldSet'
],
extend: 'Ext.form.Panel',
xtype: 'inserttankpanel',
id: 'insertTankForm',
config: {
title: 'Insert Tank Trip',
iconCls: 'add',
url: 'contact.php',
items:[
{
xtype: 'fieldset',
title: 'Insert Tank Trip',
instructions: '(Make sure the info is correct!)',
items:[
{
xtype: 'datepickerfield',
label: 'Date',
name: 'date',
value: new Date()
},
{
xtype: 'textfield',
label: 'Amount',
name: 'amount',
minValue:-9007199254740992,
maxValue: 9007199254740992
}
]
},{
xtype: 'button',
text: 'Send',
ui: 'confirm',
action: 'insertTankSubmit'
}
]
}
});
And in the controller :
launch: function() {
// Destroy the #appLoadingIndicator element
Ext.fly('appLoadingIndicator').destroy();
// Initialize the main view
Ext.Viewport.add(Ext.create('Gasoline.view.Main'));
this.control({
'button[action=insertTankSubmit]' : {
tap: 'insertTankForm'
}/*,
'list[itemId=kingsLeagueList]' : {
itemtap: 'onListTap'
},
'list[itemId=tournamentsList]' : {
disclose: 'showDetail'
}*/
});
},
insertTankForm : function(){
console.log('test');
var form = this.getInsertTankForm();
form.submit({
url:'contact.php'
});
},
This sends the following to the webservice (which currently doesn't exist i just check with developer tools)
date:2012-07-26T17:02:16
amount:
so the date does get sent , the number doesnt
If i fill in a standard value for the number ... that gets sent but if you type something in , it still doesn't send that
Use
xtype: 'numberfield'
instead of
xtype: 'textfield'
I had tried numerous solutions...none of them worked.
Lastly i deleted everything ... coded everything the exact same way and it started working ...