Sencha touch: cannot get reference to items in panel - sencha-touch

I'm am trying to get MVC to work in my first application and am trying to change cards based button clicked in toolbar.
I'm getting a runtime error when I click the hello or world button in the toolbar: TypeError: Cannot read property 'items' of undefined on the line:
var exerciseListPanel = this.items.items[0], // CODE ERRORS HERE!
I'm having a problem in getting a reference to the items in the panel, WHY?
Here is the complete code for the panel:
MyApp.views.HomeScreenPanel = Ext.extend(Ext.Panel, {
layout : 'card',
cardSwitchAnimation: 'slide',
initComponent : function() {
this.dockedItems = this.buildDockedItems();
this.items = this.buildItemList();
MyApp.views.HomeScreenPanel.superclass.initComponent.call(this);
},
buildItemList : function(){
return [
new Ext.Panel({html:"hello"}),
new Ext.Panel({html:"world"}),
];
},
buildDockedItems : function(){
return [
this.buildTopDockToolbar(),
this.buildBottomDockToolbar(),
];
},
buildTopDockToolbar : function(){
return {
xtype : 'toolbar',
dock : 'top',
title : 'My first MVC app',
};
},
buildBottomDockToolbar : function(){
return this.NavigationToolbar();
},
NavigationToolbar : function(){
return{
xtype : 'toolbar',
dock : 'bottom',
defaults : {
handler : this.NavigationToolbarHandler,
controller: 'NavigationBarController'
},
items : [
{
text : 'hello',
action: 'hello'
},
{
text : 'world',
action : 'world'
}]
};
},
NavigationToolbarHandler : function(btn) {
var exerciseListPanel = this.items.items[0], // CODE ERRORS HERE!
workoutListPanel = this.items.items[1];
Ext.dispatch({
controller : btn.controller,
action : btn.action,
views : {
exerciseListPanel: exerciseListPanel,
workoutListPanel: workoutListPanel,
}
})
},
});
Ext.reg('HomeScreenPanel',MyApp.views.HomeScreenPanel);
Here is the code for the controller but I don't there is a problem here:
Ext.regController('NavigationBarController', {
world : function(dataObj) {
Ext.Msg.alert(
'world!',
'world button pressed from toolbar',
Ext.emptyFn
);
MyApp.views.HomeScreenPanel.setActiveItem(dataObj.views.worldPanel); // CORRECT SYNTAX????
},
hello : function(dataObj) {
Ext.Msg.alert(
'hello',
'hello button pressed',
Ext.emptyFn
);
MyApp.views.HomeScreenPanel.setActiveItem(dataObj.views.helloPanel); // CORRECT SYNTAX?????
}
});

It is probably just a scope issue. try:
exerciseListPanel = MyApp.views.HomeScreenPanel.items.items[0];
In this context this is probably the button.

Items is a MixedCollection so use the get function.
http://docs.sencha.com/touch/1-1/#!/api/Ext.util.MixedCollection
MyApp.views.HomeScreenPanel.items.get(0);
Bit late but for anyone else googling in the future ;)

Related

Failed to change the text of a titlebar in a container with sencha touch 2.1

I want to create an application with users login and logout. When the user logs in ,the system will store the user information such as username,sessionid into the localstorage and then go to the index page. The index page has a titlebar with username on the left and a button to log out.But it failed to get the data stored in the localstorage that was stored when a user logs in when the index page appears.
My code is as below:
index page:
Ext.define('MyApp.view.MyPanel', {
extend : 'Ext.Panel',
id : 'myPanel',
config : {
xtype : 'panel',
layout : 'vbox',
height : '100%',
width : '100%',
items : [
{
xtype : 'titlebar',
docked : 'top',
title : 'my panel',
items : [
{
align : 'left',
id : 'portal-username',
text : 'qq' //i used localStorage.getItem('userName') first,but not as good.
},
{
align : 'right',
text : 'log out',
listeners : {
tap : function(){
var userName=null;var rememberPassword=null;var password=null;
if(userName=Ext.getCmp('userName'))userName.setValue('');
if(password=Ext.getCmp('password'))password.setValue('');
if(rememberPassword=Ext.getCmp('rememberPassword'))rememberPassword.setChecked(false);
//localstorage
localStorage.removeItem('userName','');
localStorage.removeItem('password','');
localStorage.removeItem('SessionId','');
localStorage.removeItem('rememberPassword','');
var oldp=Ext.getCmp('loginPanel');if(oldp)oldp.destroy();
var newActivePanel = Ext.create('MyApp.view.LoginPanel');
Ext.Viewport.add(newActivePanel);
Ext.Viewport.animateActiveItem(newActivePanel,{type:'slide',direction:'left'});
}
}
}
]
}
]
}
});
part of login panel:
items : [
{
xtype : 'button',
text : 'login',
ui : 'action',
handler : function() {
var userName = Ext.getCmp('userName').getValue();
var password = Ext.getCmp('password').getValue();
var rememberPassword = Ext.getCmp('rememberPassword').getChecked()+ '';
if(!userName||!password){
Ext.Msg.alert('prompt','login failure,try again!',Ext.emptyFn);
}
else Ext.Ajax.request({
url : remoteServer,
params : {
loginName: userName,
passWord : password,
SessionId : localStorage.getItem('SessionId');
},
method : 'POST',
callback : function(options,success,response) {
if (success) {
var result = Ext.JSON.decode(response.responseText.trim());
var status = result.status;
if (status == 'success') {
if (rememberPassword == 'true')
localStorage.setItem('rememberPassword',rememberPassword);
localStorage.setItem('userName',userName);
localStorage.setItem('password',password);
localStorage.setItem('SessionId',result.SessionId);
var oldp=Ext.getCmp('MyPanel');if(oldp)oldp.destroy();
var newActivePanel = Ext.create('MyApp.view.MyPanel');
Ext.Viewport.add(newActivePanel);
Ext.Viewport.animateActiveItem(newActivePanel,{type:'slide',direction:'left'});
} else {
localStorage.setItem('userName','');
localStorage.setItem('password','');
localStorage.setItem('JSessionId','');
localStorage.setItem('rememberPassword','');
Ext.Msg.alert('prompt','login failure,try again!',Ext.emptyFn);
}
} else {
Ext.Msg.alert('prompt','login failure,try again!',Ext.emptyFn);
}
}
});
}
}
]
Below is my controller :
Ext.define('MyApp.controller.MyController',
{
extend : 'Ext.app.Controller',
id : 'MyController',
config : {
control : {
MyPanel : {
show : 'panelActive'
},
},
refs : {
MyPanel : '#myPanel'
}
}//config
,panelActive : function(){
Ext.getCmp('portal-username').setText(localStorage.getItem('userName'));
}
});
After Following line
Ext.Viewport.animateActiveItem(newActivePanel,{type:'slide',direction:'left'});
in login handler function just set the username using
Ext.getCmp('portal-username').setText(userName);

Sencha Touch2: Passing data from Controller to floating Panel not working

I am new to Sencha Touch2 and facing problem while passing data from my Controller to Floating panel on listitem tap. Here is my controller implementation code:
Ext.define('CustomList.controller.Main', {
extend: 'Ext.app.Controller',
requires:['CustomList.view.DatePanel'],
config: {
refs: {
listView: 'listitems'
},
control: {
'main test2 list': {
activate: 'onActivate',
itemtap: 'onItemTap'
}
}
},
onActivate: function() {
console.log('Main container is active');
},
onItemTap: function(view, index, target, record, event) {
console.log('Item was tapped on the Data View');
Ext.Viewport.add({
xtype: 'DatePanel'
});
}
});
Am able to get data in the controller and DatePanel.js is my floating Panel.
DatePanel.js:
Ext.define('CustomList.view.DatePanel', {
extend: 'Ext.Panel',
alias: 'widget.DatePanel',
xtype:'datepanel',
config: {
itemid:'DatePanel',
modal:true,
centered: true,
hideOnMaskTap:true,
width:'500px',
height:'650px',
items:[
{
styleHtmlCls:'homepage',
tpl:'<h4>{name3}</h4>'
},
{
xtype:'toolbar',
docked:'bottom',
items:[{
text:'OK',
ui:'confirm',
action:'ShowTurnOverReport',
listeners : {
tap : function() {
console.log('Ok');
}
}
},
{
text:'Cancel',
ui:'confirm',
action:'Cancel',
listeners : {
tap : function() {
console.log('Cancel');
var panelToDestroy = Ext.getCmp('datepanel');
panelToDestroy.destroy();
Ext.Viewport.add(Ext.create('CustomList.view.Test2'));//Test.js is my list Panel
}
}
}]
}
]
}
});
Help me out in destroying the panel on 'Cancel' Button.
Can anyone please help me. Thanks.
Create instance of panel you want to add first.
var floatingDatePanel = Ext.create('Yourapp.view.YourDatePanel');
Next get data of selected list item on itemTap
var data = record.getData();
Assign this data to floatingDatePanel with setData() method
UPDATE,
after looking at your panel code, I guess you want to set data to first item in panel ie
{
styleHtmlCls:'homepage',
tpl:'<h4>{name3}</h4>'
}
Right ? If so then you need to change following code
floatingDatePanel.setData(data);
to
floatingDatePanel.getAt(0).setData(data);
Because, it is first item inside panel that is having a template assigned and hopefully the same where you want to set data.
then finally, you can add this panel into viewport with
Ext.Viewport.add(floatingDatePanel);

How to set a value into a openerp form view field from javascript

this is the code i use to call the form view:
get_view_form_dimension: function() {
var self = this;
var action_manager = new openerp.web.ActionManager(this);
var dialog = new openerp.web.Dialog(this, {
width: 800,
buttons : [
{text: _t("Cancel"), click: function() { $(this).dialog('destroy'); }},
{text: _t("Save"), click: function() {
var form_view = action_manager.inner_viewmanager.views.form.controller;
form_view.do_save(function() {
$.jstree._reference("#new_tree").destroy();
self.get_tree_structure();
});
$(this).dialog('destroy');
}}
]
}).open();
action_manager.appendTo(dialog.$element);
action_manager.do_action({
res_model : 'df.bi.dimension',
res_id: self.process_id,
views : [[false, 'form']],
type : 'ir.actions.act_window',
flags : {
search_view: false,
sidebar : false,
views_switcher : false,
action_buttons : false,
pager: false
}
});
},
how can i set values into the form that this method will rise ?? or in case that exist other solution please tell me ? sorry for my english!
Add a context field to your do_action call with default values, like this:
context: {'default_account_id': 5, 'default_name': 'hello'},

One view and multiple controller actions for the same button in EXTJS

Am having a delete button in my EXTJS Application. On clicking the button, am opening a confirmation form, asking the user are they sure to delete the item. The delete button is a part of many forms in my Application. And irrespective of the form being used, am opening the confirmation window.
And on clicking the yes button in the confirmation window, i want to do some action. But these actions have to be specific to the form that was opened first.So, am confused about how to use the same view, the same button, but different actions depending upon the first form that was opened.
View: This is the window that opens on clicking the delete button in any of the forms
Ext.define('app.view.GenMessageWin', {
extend : 'Ext.panel.Panel',
alias : 'widget.genmessagewin',
var fp = {
xtype : 'panel',
itemId : 'MSGPANEL',
width : Width,
height : 150,
cls : 'msg effect1',
layout : 'form',
border : false,
items : [{
xtype : 'panel',
//cls : 'winTitle',
html : msgTxt,
border : 0
}, {
xtype : 'form',
itemId : 'MSGFORM',
border : false,
title : '',
buttonAlign : 'center',
fieldDefaults : {
msgTarget : 'side',
labelWidth : 110,
size : 30
},
buttons : [{
text : LANG.BTYES,
iconCls : 'icon-tick-tb',
iconAlign : 'right',
cls : 'tip-btn',
action : 'delete',
id : 'BTYES'
}, {
text : LANG.BTNO,
iconCls : 'icon-cross-tb',
iconAlign : 'right',
cls : 'tip-btn',
action : 'notDelete',
id : 'BTNO'
} ]
Controller
init : function() {
this.control({
'button[action = delete]' : {
click : this.delete
},
'button[action = notDelete]' : {
click : this.notDelete
},
So, in the delete action, we have to determine which form has been opened in the first place, and then delete the data accordingly.
You have 3 options:
1) Make the selector more specific:
'form1 button[action=delete]': {
click: this.form1Delete
},
form1Delete: function(){
this.showMsg(function() {
// form 1 delete
});
}
2) Traverse back up the component hierarchy and find the open form
onDelete: function(btn) {
var form = btn.up('form'); // find an xtype form or subclass
if (form.someCondition) {
//foo
} else {
//bar
}
}
3) As suggested by Dmitry. You'll need to convert it over to 'MVC style'.
Ext.define('ConfirmButton', {
extend: 'Ext.button.Button',
title: '',
msg: '',
requires: ['Ext.window.MessageBox'],
initComponent: function(){
this.callParent();
this.on('click', this.handleClick, this);
},
handleClick: function(){
Ext.MessageBox.confirm(this.title, this.msg, this.checkResponse, this);
},
checkResponse: function(btn){
if (btn == 'yes') {
this.fireEvent('confirm', this);
}
}
});
Ext.onReady(function(){
var btn = new ConfirmButton({
renderTo: document.body,
text: 'Foo',
title: 'Should I',
msg: 'Are you sure'
});
btn.on('confirm', function(){
console.log('Do something');
})
});
I am doing something similar; I simply use the native Ext.Msg class
Controller code
,onDelete: function() {
var me = this;
Ext.Msg.show({
title:'Really shure?',
msg: 'Really wanna do this?',
buttons: Ext.Msg.YESNO,
icon: Ext.Msg.QUESTION,
closable: false,
fn: function(btn) {
if (btn == 'yes') {
me.deleteRecord();
}
},
scope: me
});
}
,deleteRecord: function() {
var me = this,
store = Ext.StoreMgr.lookup('datastore');
store.remove(me.selectedRecord);
store.sync();
}
I would recommend you to keep all logic concerning this within the controller. I your case it'seems that's no problem, cause you just catching the button-events. You problem may be that all controllers catch these, if you are using totally the same window.
You can solve this for example by creating the action property value dynamically when creating the window. Like action='onDeleteCar'
I think you should embed the 'confirmation' functionality inside the button, i.e. create your own ConfirmButton class that would first fire a dialog upon pressing and executing the passed handler only if the dialog exited with "yes".
Here is the example implementation:
Ext.define('My.ConfirmButton', {
extend: 'Ext.button.Button',
alias: 'widget.confirmbutton',
dlgConf: {
title: 'Are you sure?',
msg: 'Are you sure you want to delete this?',
buttons: Ext.Msg.YESNO,
closable: false
},
initComponent: function() {
this.callParent(arguments);
// remember the originally passed handler
this.origHandler = this.handler;
this.origScrope = this.scope;
// override current handler to fire confirmation box first
this.handler = this.confirmHandler;
this.scope = this;
},
confirmHandler: function(me, e) {
// show dialog and call the original handler only on 'yes'
Ext.Msg.show(Ext.applyIf({
fn: function(buttonId) {
if(buttonId == 'yes') {
me.origHandler && me.origHandler.call(me.origScope || me, me, e)
}
},
scope: me
}, this.dlgConf))
},
// Method used to dynamically reassign button handler
setHandler: function(handler, scope) {
// remember the originally passed handler
this.origHandler = this.handler;
this.origScrope = this.scope;
// override current handler to fire confirmation box first
this.handler = this.confirmHandler;
this.scope = this;
return this;
},
});
Here is the sample usage:
Ext.create('My.ConfirmButton', {
text: 'Delete me',
renderTo: Ext.getBody(),
handler: function() {
alert('Aww, you deleted something! :(')
}
});
As you see, the confirmation logic is hidden from the outside world, you use this button exactly like you would use a regular Ext.Button (by passing a handler to it). Also, you can override the configuration of the dialog that the button fires (you may want to adjust it to your needs, e.g. allow passing record name to the dialog for a friendlier UI).
Note that the code isn't thoroughly tested, some cases might be left uncovered.
UPD. You need to add an alias (former xtype) to the component class definition so you can use it in ComponentQuery in your controller code, e.g.
this.control({
'confirmbutton[action = delete]' : {
click : this.delete
},
'confirmbutton[action = notDelete]' : {
click : this.notDelete
}
})
The final solution that i used was to declare variables using the global namespace so that they can be accessed from anywhere. On opening the first form, i get the data from the form using the record variable, and assign them a global name like
App1.Var1 = record.data.id;
And, on opening the delete window, these variables can be accessed by App1.Var1 when the buttons are clicked.

Ext JS StatusBar with clock

I'm trying to create a status bar with clock.
I found example in sencha examples, but I'm trying to build it more object oriented way.
Ext.define('Urlopy.Components.Statusbar', {
extend : 'Ext.ux.statusbar.StatusBar',
id : 'basic-statusbar',
defaultText : 'Wczytane...',
defaultIconCls : 'x-status-valid',
iconCls : 'x-status-valid',
autoClear : 3000,
initComponent : function() {
this.currentUserDisplay = Ext.create('Ext.toolbar.TextItem');
this.currentUserDisplay.setText('Not logged in!');
this.timeDisplay = Ext.create('Ext.toolbar.TextItem');
this.timeDisplay.setText(Ext.Date.format(new Date(), 'Y-m-d H:i:s'));
Ext.apply(this, {
items : [this.currentUserDisplay, {
xtype : 'tbseparator'
}, this.timeDisplay],
listeners : {
render : {
fn : function() {
Ext.TaskManager.start({
run : function() {
this.timeDisplay.setText(Ext.Date.format(new Date(),'Y-m-d H:i:s'));
},
interval : 1000
});
},
delay : 100
}
}
});
this.callParent();
},
setCurrentUser : function(username) {
this.currentUserDisplay.setText('Logged as' + ": " + username);
},
startLoad : function(message) {
if (message !== null) {
this.showBusy({
text : message,
iconCls : "x-status-busy"
});
} else {
this.showBusy();
}
},
endLoad : function() {
this.clearStatus({
useDefaults : true
});
}
});
The first time component shows it displays date and time correct, but it doesn't update.
Problem is probably TaskManager or my listeners.
Instead of them I've tried doing this:
initComponent : function() {
this.currentUserDisplay = Ext.create("Ext.toolbar.TextItem");
this.currentUserDisplay.setText('Nie jesteś zalogowany!');
this.timeDisplay = Ext.create("Ext.toolbar.TextItem");
this.timeDisplay.setText(Ext.Date.format(new Date(), "Y-m-d H:i:s"));
Ext.apply(this, {
items : [this.currentUserDisplay, {
xtype : 'tbseparator'
}, this.timeDisplay]
});
this.callParent();
var task = {
run : function() {
this.timeDisplay.setText(Ext.Date.format(new Date(), "Y-m-d H:i:s"));
},
interval : 1000
}
Ext.TaskManager.start(task);
},
but no luck :(
I know that this is probably a tiny mistake, but can't find it.
What you have is a scope issue, this in your run function doesn't point to the status bar. you need to add a scope: this after the interval.
see example http://jsfiddle.net/nscrob/kR9ev/17/