I have a test application with a couple of views. I am trying to invoke a simple 'tap' listener on my buttons. Even though the controller is instantiated and launched, the tap event does not seem to fire.
Here's my app.js
Ext.application({
name: 'MyApp',
requires: [
'Ext.MessageBox',
'Ext.form.FormPanel',
'Ext.navigation.View'
],
views: [
'Main',
'Tasks'
],
controllers: [
'Main'
],
models: [
'Task',
'Schedule'
],
stores: [
'Tasks',
'Schedules'
],
launch: function() {
// Destroy the #appLoadingIndicator element
try{
Ext.fly('appLoadingIndicator').destroy();
}catch(err){
console.warn("[CUSTOMWARN]Could not destroy loading indicator because of -- \n"+err);
}
var DEBUG=false;
if(!DEBUG){
// Initialize the main view
Ext.Viewport.add(Ext.create('MyApp.view.Main'));
}
}
});
Main.js -- controller
Ext.define('MyApp.controller.Main', {
extend: 'Ext.app.Controller',
requires: [
'MyApp.view.Main'
],
init: function(){
// download and parse data from server here.
console.log('controller initiated!');
},
config: {
refs: {
loginBtn: 'button[action=login]'
},
control: {
loginBtn: {
tap: 'loginBtnHandler'
}
}
},
loginBtnHandler: function(){
this.callParent(arguments);
Ext.Msg.alert('here');
}
});
Main.js -- view
Ext.define('MyApp.view.Main', {
extend: 'Ext.navigation.View',
alias: 'customnavigationview',
requires: [
'MyApp.form.Login'
],
config: {
navigationBar: {
hidden: true
},
items: [
{
xtype: 'logincard',
flex: 1
}
],
}
});
Login.js -- for xtype: 'logincard'
Ext.define('MyApp.form.Login', {
extend: 'Ext.form.Panel',
xtype: 'logincard',
requires: [
'Ext.field.Password',
'Ext.field.Email',
'Ext.form.FieldSet',
'Ext.field.Toggle',
'Ext.Label'
],
// id: 'loginForm',
config: {
items: [
{
xtype : 'label',
html : 'Login failed. Please enter correct credentials.',
itemId : 'signInFailedLabel',
hidden : true,
hideAnimation : 'fadeOut',
showAnimation : 'fadeIn',
style : 'color:#990000;',
margin : 10
},
{
title: 'Please log in',
xtype: 'fieldset',
items:[
{
xtype: 'textfield',
name : 'username',
label: 'UserName'
},
{
xtype: 'passwordfield',
name : 'password',
label: 'Password'
}
]
},
{
xtype: 'fieldset',
items: [
{
xtype : 'togglefield',
name : 'rememberLogin',
label : 'Remember Me '
}
]
},
{
xtype : 'button',
id : 'loginSubmitBtn',
itemId : 'loginSubmitItemBtn',
text : 'Login',
ui : 'action',
action : 'login',
margin : 10
}
]
}
});
Any help would be highly appreciated!
EDIT: So I tried to use Ext.ComponentQuery.query("#loginSubmitBtn") and on printing the output on console, I can see that it is pointing to the correct button. Here's the output.
0: Class
_badgeCls: "x-badge"
_baseCls: "x-button"
_disabledCls: "x-item-disabled"
_floatingCls: "x-floating"
_hasBadgeCls: "x-hasbadge"
_hiddenCls: "x-item-hidden"
_icon: false
_iconAlign: "left"
_itemId: "loginSubmitItemBtn"
_labelCls: "x-button-label"
_margin: 10
_pressedCls: "x-button-pressing"
_pressedDelay: 0
_styleHtmlCls: "x-html"
_text: "Login"
_ui: "action"
action: "login"
badgeElement: Class
bodyElement: Class
config: objectClass
currentUi: "x-button-action"
element: Class
eventDispatcher: Class
getEventDispatcher: function () {
getId: function () {
getObservableId: function () {
getUniqueId: function () {
iconElement: Class
id: "loginSubmitBtn"
initConfig: function (){}
initialConfig: Object
initialized: true
innerElement: Class
managedListeners: Object
observableId: "#loginSubmitBtn"
onInitializedListeners: Array[0]
parent: Class
referenceList: Array[4]
refreshFloating: function () {
refreshSizeState: function () {
renderElement: Class
rendered: true
textElement: Class
usedSelectors: Array[1]
__proto__: Object
length: 1
**EDIT 3: ** Found it! See answer here: Sencha Tap listener not firing
The listener for a button tap should be just 'tap' instead of 'itemtap'
tap: 'loginBtnHandler'
Hope it helps-
I think I've had this problem in the past. Try qualifying the ref in the controller with the view name to narrow the query down:
loginBtn: 'logincard button[action=login]'
Not the best, but should work:
First remove the tap listener on the controller. Also remove the 'action' property on the button, and set the handler on the button:
{
xtype : 'button',
id : 'loginSubmitBtn',
itemId : 'loginSubmitItemBtn',
text : 'Login',
ui : 'action',
//action : 'login',
margin : 10,
handler : function () {
MyApp.app.getController('Main').loginBtnHandler()
}
}
Ok, this is weird, but I found out why my buttonclick was not being handled properly. I usually use Google Chrome as my testing browser with web inspector on. I downloaded Safari and tried the same code and it worked like its supposed to. I looked at both the browsers, and the only difference was that Chrome had web inspector on, while Safari didn't. I closed the web inspector in Chrome and the button handler worked great (without reloading). I restarted the browser, pushed the inspector to a separate window, none of them worked. However, Safari works great even with inspector on. Probably a Chrome bug?
Google Chrome version: 27.0.1453.110
*EDIT: * I had the touch emulation turned on in the web inspector. With this turned on, we have to close the web inspector for the touch event to register. Otherwise, we have to turn off the touch emulation to register for the events while the web inspector is open.
TL;DR: Close your web inspector in Chrome before testing, if you have touch emulation turned on.
Related
ExtJS 5.1.3 - I'm slightly baffled that a simple Panel cannot resolve its VC on 'show' event. The attached fiddle will work - it has a panel with VC. Click the button to see the VC correctly resolved.
If you un-comment the 'show' event however, the code will fail in the console because the function can't be found (Unable to dynamically resolve scope for "show" listener on mypanel-xxxx). Lots of my code works like this already, am I doing something stupid?
I've tried using add() instead of widget() in case it's some kind of MVC nesting issue but Ext just seeks the function in the wrong VC - the top-level VC applied to the viewport.
Any help very much appreciated. Thx
https://fiddle.sencha.com/#view/editor&fiddle/1kvd
Ext.define('Admin.view.TheController', {
extend : 'Ext.app.ViewController',
alias : 'controller.thecontroller',
doShowStuff : function() {
Ext.Msg.alert('SHOW STUFF!', 'yep, this works');
},
doOkStuff : function() {
Ext.Msg.alert('OK STUFF!', 'yep, this works');
}
});
Ext.define('Admin.view.Panel.MyPanel', {
extend : 'Ext.panel.Panel',
alias : 'widget.mypanel',
autoRender : true,
autoShow : true,
controller : 'thecontroller',
width : 200,
height : 200,
html : 'I am your panel',
buttons : [
{ text : 'OK', handler : 'doOkStuff', scope : 'controller' }
],
listeners : [
// This listener causes an error
//{ show : 'doShowStuff', scope : 'controller' },
]
});
Ext.widget('mypanel');
listeners: {
// This listener causes an error
show:{
fn: 'doShowStuff',
scope: 'controller'
}
}
here's the fiddle
Your listeners are misconfigured, they should be an object, not an array. Also, you should omit the scope, it will be automatically determined:
Ext.define('Admin.view.Panel.MyPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
autoShow: true,
controller: 'thecontroller',
width: 200,
height: 200,
html: 'I am your panel',
buttons: [{
text: 'OK',
handler: 'doOkStuff'
}],
listeners: {
show: 'doShowStuff'
}
});
I'm using button to move between tabs. But for that I have to remember the user's tab position. So my buttons keep working when the user leaves the screen and returns later.
The tabchange event should be the event to use for that, however I cannot get it to trigger.
View:
Ext.define('MyApp1.view.Home',
{
extend: 'Ext.form.Panel',
requires:
[
'Ext.tab.Panel'
],
xtype: 'home',
config:
{
itemId: 'home',
layout: 'fit',
items:
{
xtype: 'tabpanel',
tabBarPosition: 'top',
height: 500,
renderTo: document.body,
listeners:
{
beforetabchange: function (tabs, newTab, oldTab)
{
console.log('tab is going to change');
},
tabchange: function ()
{
console.log('recorded tab change from listener');
},
change: function ()
{
console.log('change of tab from listener');
}
},
items:
[
{
title: 'one'
},
{
title: 'two'
}
]
}
}
});
Controller:
Ext.define('MyApp1.controller.HomeController',
{
extend: 'Ext.app.Controller',
requires:
[
'MyApp1.view.Main'
],
config:
{
refs:
{
home: 'home'
},
control:
{
home:
{
beforetabchange: 'onTabChange',
tabchange: 'onTabChange',
change: 'onTabChange'
}
}
},
init: function()
{
console.log('HomeController initialized');
},
onTabChange: function ()
{
console.log('active tab changed');
}
});
So I see the initialization text in the log but none of the tab change events when I click the tab buttons.
First off it seems you can only implement these listeners on the tabBar of the tabPanel
Having looked through the source code though it seems that this never get's fired even though it is documented. http://docs-origin.sencha.com/touch/2.4/2.4.1-apidocs/source/Bar3.html#Ext-tab-Bar-event-tabchange
What I could suggest is either as you pointed out to hook into the activeitemchange event on the panel or activetabchange (which strangely is firing twice) event of the tabbar as activeitemchange also seems not to work as intended.
https://fiddle.sencha.com/#fiddle/g44
Turns out I was looking at the ExtJs 5 docs, instead of the Sencha 2.4.1 docs...
Which only has the 'activeitemchange' event.
I'am trying to build my first little Sencha Touch 2 app. I've created some stuff that is working as expected and now I could like to create some event handling stuff.
I've created the following store:
Ext.define('Mobile.store.Blogs', {
extend: 'Ext.data.Store',
config: {
},
listeners: {
'load' : function(store,records,options) {
store.loaded = true;
console.log("fired blogCountAvailable");
store.fireEvent("blogCountAvailable");
},
'blogCountAvailable': function(store, records, options) {
console.log("blogCountAvailable has been fired");
}
}
});
This stuff works as expected, but now comes the next step.
Here is the code of my tab panel bar:
Ext.create("Ext.tab.Panel", {
xtype:'mainTabPanelBottom',
tabBarPosition: 'bottom',
fullscreen: true,
items: [
{
title: 'Blog',
iconCls: 'home',
xtype:'mainpanel'
},
{
title: 'Users',
iconCls: 'user',
xtype:'userpanel'
}
],
listeners: {
blogCountAvailable: function(tabpanel, newTab) {
var tab = newTab.tab,
badge = 10;
tab.setBadge(badge);
console.log("blogCountAvailable has been fired");
}
}
});
My question now is how I could achieve it to "fire" my custom event blogCountAvailable to the tab panel?
The easiest way is just set an id for your TabPanel and then:
Ext.getCmp('your_TabPanel_id').fireEvent("blogCountAvailable");
I'd like to start quick.
What is my problem:
Within ST2 I structured my application with the MVC pattern. I have a store, a model, a controler and the views (for more information scroll down).
Workflow:
I click a list item (List View with a list of elements from store)
Controller acts for the event 'itemtap'
Controller function is looking for main view and pushes a detail view
Record data will be set as data
Detail view uses .tpl to generate the output and uses the data
Problem
Now I want to add a button or link to enable audio support.
I thought about a javascript function which uses the Media method from Phonegap to play audio
and I want to add this functionality dynamicly within my detail view.
Do you have any idea how I can achive that behavoir? I'm looking for a typical "sencha" solution, if there is any.
Detail Overview of all files starts here
My list shows up some data and a detail view visualize further information to a selected record.
The list and the detail view a collected within a container, I'll give you an overview:
Container:
Ext.define('MyApp.view.ArtistContainer', {
extend: 'Ext.navigation.View',
xtype: 'artistcontainer',
layout: 'card',
requires: [
'MyApp.view.ArtistList',
'MyApp.view.ArtistDetail'
],
config: {
id: 'artistcontainer',
navigationBar: false,
items: [{
xtype: 'artistlist'
}]}
});
List
Ext.define('MyApp.view.ArtistList', {
extend: 'Ext.List',
xtype: 'artistlist',
requires: [
'MyApp.store.ArtistStore'
],
config: {
xtype: 'list',
itemTpl: [
'<div>{artist}, {created}</div>'
],
store: 'ArtistStoreList'
}
});
Detail View
Ext.define('MyApp.view.ArtistDetail', {
extend: 'Ext.Panel',
xtype: 'artistdetail',
config: {
styleHtmlContent: true,
scrollable: 'vertical',
title: 'Details',
tpl: '<h2>{ title }</h2>'+
'<p>{ artist }, { created }</p>'+
'{ audio }'+
'',
items: [
//button
{
xtype: 'button',
text: 'back',
iconCls: 'arrow_left',
iconMask: true,
handler: function() {
var elem = Ext.getCmp("artistcontainer");
elem.pop();
}
}
]
}
});
And finally the controller
Ext.define('MyApp.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
artistContainer: 'artistcontainer',
},
control: {
'artistlist': {
itemtap: 'showDetailItem'
}
}
},
showDetailItem: function(list, number, item, record) {
this.getArtistContainer().push({
xtype: 'artistdetail',
data: record.getData()
});
}
});
Puh, a lot of stuff to Read
Here you can see an example of how to load audio from an external url with Sencha Touch "Audio" Component. Haven't work with it but I think it fits your needs. Declaring it is as simple as follows:
var audioBase = {
xtype: 'audio',
url : 'crash.mp3',
loop : true
};
Iwould reuse the component and load the songs or sound items by setting the url dynamically. By the way I tried it on Chrome and Ipad2 and worked fine but failed on HTC Desire Android 2.2 default browser.
I am trying to get Ext.define & Ext.create working in Sencha touch 2, so that I can define everything in my library and just create stuff pre-configured.
However, Ext.define is not doing what I would expect it to in anything I've tried.
Why does the following code not create a panel inside the viewport with the field label "Tame"?
Ext.define('mobi.form.Login',{
extend:'Ext.form.Panel',
items: [{
xtype: 'textfield',
name: 'Tame',
label: 'Tame'
}
]
});
Ext.application({
viewport: {
layout:'fit'
},
launch: function(){
var form = Ext.create('Ext.form.Panel', {
items: [{
xtype: 'textfield',
name: 'name',
label: 'Name'
}
]
});
Ext.Viewport.add(Ext.create('mobi.form.Login')); // This doesnt add anything to the viewport
Ext.Viewport.add(form); //magically this works
}
})
When using Ext.define, all configurations must go inside the config block. So your code should look like this:
Ext.define('mobi.form.Login',{
extend:'Ext.form.Panel',
config: {
items: [{
xtype: 'textfield',
name: 'Tame',
label: 'Tame'
}
]
}
});
In general the only exceptions to this are:
extend
requires
xtype
singleton
alternateClassName
Anything else should be inside the config object, but remember, only when using Ext.define.
It looks like you are trying to use the sencha MVC concept but this is wrong if this is your only piece of code.
First create the following folder structure:
MyAppFolder
index.html (include the sencha lib here)
app.js (main file)
app (folder)
controller
Main (main controller)
model (optional if no model is defined)
store (optional if no model is defined)
view
Viewport.js (your main viewport)
resources
css
style.css (your custom style)
images (your icons and images if you have)
Then in your app.js you would define something like this:
// enable loader for dynamic loading of .js classes
Ext.Loader.setConfig({
enabled : true,
paths : {
}
});
/**
* Better performance is achived when knowing which .js classes we need to load prior to execution of this class.
*/
Ext.require([
]);
/**
* This is the definition of our mobile application.
* The name of this app is MVCTest.
*/
Ext.application({
name : 'MVCTest',
controllers : ['Main'],
views : ['Viewport'],
launch : function() {
Ext.create('MVCTest.view.Viewport');
}
});
Then your main controller:
Ext.define('MVCTest.controller.Main', {
extend : 'Ext.app.Controller',
config : {
refs : {
viewport : 'mvctest-viewport'
}
}
});
Then your viewport would look something like this, according to your example:
Ext.define('MVCTest.view.Viewport', {
extend : 'Ext.Container',
xtype : 'mvctest-viewport',
config : {
fullscreen : true,
layout : 'card',
items:
[
{
xtype: 'textfield',
name: 'name',
label: 'Name'
},
{
xtype: 'mvctest-tame'
}
]
}
});
By specifying the xtype mvctest-tame it will search for this xtype and add this in as a new item to this card. So you need the tame view:
Ext.define('MVCTest.view.Login',{
extend:'Ext.form.Panel',
xtype: 'mvctest-tame',
items: [{
xtype: 'textfield',
name: 'Tame',
label: 'Tame'
}
]
});
And do not forget to add the Login view to the app.js..