Sencha Touch 2 - TabPanel does not work in MVC designed App - javascript

simple question for you today...
This works:
var carousel = Ext.create('Ext.Carousel', {
fullscreen: 'true',
//load in views view clean instantiation using
// the widget.alias's defined in each view... yea
// For some reason, putting flex on these components... oh...
// Have to call directly in by just the xtype since these are just
// references..
items: [
{
xtype: 'Main'
},
{
xtype: 'CommentList'
}
]
This does NOT work:
var tabpanel = Ext.create('Ext.TabPanel', {
fullscreen: 'true',
tabBarPosition: 'bottom',
defaults: {
styleHtmlContent: true
},
//load in views view clean instantiation using
// the widget.alias's defined in each view... yea
// For some reason, putting flex on these components... oh...
// Have to call directly in by just the xtype since these are just
// references..
items: [
{
xtype: 'Main',
title: 'The Main',
iconCls: 'user'
},
{
xtype: 'CommentList',
title: 'Comments',
iconCls: 'user'
}
]
});
As you can see, they are pretty much the same except one is a TapPanel (with the required default configs added) and the other is a carousel.
Everything else is exactly the same.... This is in the app.js of my Sencha Touch 2.0 app designed following the MVC architecture.
The result of the not-working TabPanel is that I only see the first view (Main) and no tab-bar appears in the bottom of the screen.
Any ideas what my problem might be?

I am not sure if this is an issue but in my code the line is:
Ext.create("Ext.tab.Panel", {
Not:
Ext.create('Ext.TabPanel', {

Fullscreen should be fullscreen: true instead of fullscreen: 'true'. You could also add this code to make them switch:
cardSwitchAnimation: {type: "fade", duration: 1000},
layout: "card",
Didn't test it, but it worked for me (got it from a snippet of my own code)

Related

How to control the scope of event listeners in the extjs app controller

Ext JS - v 6.2.1
I'm interested in reusing a main component developed in ExtJs which i've written in different tabs of the tabpanel. The main component is composed of two child components and each of these components have their respective controllers and the child components interact among themselves. Since the event listeners are added in the controller domain the events fired in one instance of tab affects the other tabs as well.
Pseudo code of the scenario explained
*********** Views ***********
Ext.define('MainApp.view.main.Main', {
extend: 'Ext.tab.Panel',
xtype: 'mainapp-main',
controller: 'main',
...
items: [{
title: 'Main Component Instance 1',
closable: true,
items: [{
xtype: 'mainapp-maincomponent'
}]
}, {
title: 'Main Component Instance 2',
closable: true,
items: [{
xtype: 'mainapp-maincomponent'
}]
}]
});
Ext.define('MainApp.view.maincomponent.MainComponent', {
extend: 'Ext.panel.Panel',
xtype: 'mainapp-maincomponent',
controller: 'maincomponent',
...
items: [{
xtype: 'mainapp-component1'
},{
xtype: 'mainapp-component2'
}]
});
Ext.define('MainApp.view.component1.Component1', {
extend: 'Ext.panel.Panel',
xtype: 'mainapp-component1',
controller: 'component1',
...
items: [{
xtype: 'button',
cls: 'contactBtn',
scale: 'large',
text: 'Fire Event',
handler: 'onComponentButtonTapped'
}]
});
Ext.define('MainApp.view.component2.Component2', {
extend: 'Ext.panel.Panel',
xtype: 'mainapp-component2',
controller: 'component2',
...
items: [{
xtype: 'textfield',
value: 'Button is not clicked yet',
width: 500,
readOnly: true
}]
});
*********** Controllers ***********
Ext.define('MainApp.view.component1.Component1Controller', {
extend: 'Ext.app.ViewController',
alias: 'controller.component1',
onComponentButtonTapped: function (btn, eventArgs) {
this.fireEvent('component1ButtonTapped', btn, eventArgs);
}
});
Ext.define('MainApp.view.component2.Component2Controller', {
extend: 'Ext.app.ViewController',
alias: 'controller.component2',
listen: {
controller: {
'component1': {
component1ButtonTapped: 'onComponent1ButtonTapped'
}
}
},
onComponent1ButtonTapped: function(){
this.getView().down('textfield').setValue(Ext.String.format('Button tapped at {0}', Ext.Date.format(new Date(), 'Y-m-d H:i:s')));
}
});
Can somebody please suggest the correct way of addressing this used case.
More Details
The tab panel is loaded in viewport
Tab 1 has first instance of Main Component - M1
Tab 2 has second instance of Main Component - M2
Every instance of Main Component has two child components
Component1 - M1C1 > M1C1 View and M1C1 Controller
Component2 - M1C2 > M1C2 View and M1C2 Controller
Similarly for the second instance of Main Component
Component1 - M2C1 > M2C1 View and M2C1 Controller
Component2 - M2C2 > M2C2 View and M2C2 Controller
Requirement here is to restrict Actions done on M1C1 view should be processed by M1C2 Controller only.
Issue is that with the code above M2C2 Controller also listens to the event
Change handler: 'onComponentButtonTapped' to
{
xtype: 'button',
cls: 'contactBtn',
scale: 'large',
text: 'Fire Event',
listeners: {
click: 'onComponentButtonTapped',
scope: SCOPE-YOU-WANT
}
}
First, I believe you are overnesting in your MainApp.view.main.Main component and you don't use a layout for your overnesting either. That can lead to unnecessary consequences like extra layout runs and bloated DOM affecting performance.
Ok, onto your question! I don't think scope is what you're actually after here. I see it as how to properly architect your ViewControllers. While understanding this isn't your real code, I will say that in this example you don't need that Component1Controller controller. Get rid of it and the button's handler will get resolved up to the maincomponent controller which is where you can control both child items. I only say this fully knowing that your Component1Controller is likely doing other things so it's not going anywhere just to say that not all containers need controllers. It also serves what I would do in this case if Component1Controller is to stick around. Instead of firing an event on the Component1Controller instance and use the event domain to get to Component2Controller, I would fire a view event on Component1 and add a listener on your config object so that maincomponent controller gets the event to do it's thing.
That sounds messy and hard to follow so I created this fiddle.

EXTJS inline initComponent method within items config

Disclaimer: I am relatively new to ExtJS (version 5.01). I am hoping to reach some ExtJS experts to point me in the right direction:
I am getting an error when specifying an initComponent method within an items config. The code below generates the error:
"Uncaught TypeError: Cannot read property 'items' of undefined"
The error disappears when the 'initComponent' function of the north-child panel is commented out. I have the feeling I missed something on initialization order.
Q: How can I specify an initComponent method of a child item within the items configuration?
Ext.define('MyApp.view.TestView', {
extend: 'Ext.panel.Panel',
title: 'Parent',
height: 300,
layout: 'border',
items: [{
xtype: 'panel',
region: 'north',
title: 'North Child',
/* Problematic function: If commented, it works */
initComponent: function(){
console.log("test north child");
this.callParent(arguments);
}
}],
initComponent: function(){
console.log("Test parent");
this.callParent(arguments);
}
});
Short answer: You can't define initComponent on a child, because you can't do anything there that can't be done anywhere else.
InitComponent is executed when an instance of the component 'MyApp.view.TestView' is created (you only defined it here, using Ext.define). It can be created using Ext.create('MyApp.view.TestView',{, or by creating another view that has this component added as an item, or by deriving another component (extend:'MyApp.view.TestView').
All the child components are also created when 'MyApp.view.TestView' is created, so the initComponent function on the child would be superfluous, because the child cannot be created without the parent, so the initComponent of the parent can be used for everything that you want to do in the child's initComponent.
If you need sth. to be calculated before the items can be addded, you would proceed as follows:
Ext.define('MyApp.view.TestView', {
extend: 'Ext.panel.Panel',
title: 'Parent',
height: 300,
layout: 'border',
initComponent: function(){
var me = this,
tf = Ext.getCmp("someTextField"),
myTitle = (tf?tf.getValue():'');
Ext.applyIf(me,{
items: [{
xtype: 'panel',
region: 'north',
title: myTitle,
}]
});
this.callParent(arguments);
}
});
Please refer to the docs what exactly Ext.applyIf does (and how it differs from Ext.apply, because that function also comes handy sometimes).

Set layout on Sencha touch 2

I try to setLayout when the orientation was changed , but I get this type of error :
*Console.js:17Uncaught Error: [ERROR][Ext.Container#setLayout] Replacing a layout after one has already been initialized is not currently supported.*
and I cannot get, what is going on here. Here is my code :
onOrientationChange:function(viewport, orientation){
viewport.setLayout('vbox');
}
where the viewport is :
Ext.define("Q4.view.blg", {
extend: 'Ext.Container',
xtype: 'blg',
config:{
title:"blg",
iconCls:'star',
cls:'blogList',
disableSelection: true,
layout: 'hbox',
defaults:{
scrollable:false
},........
Thanks !!!!!!

Sencha Touch 2: data intigration or how to share dynamic information between sencha and javascript

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.

Defining a Panel and instantiating it in a viewport

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

Categories