PDA

View Full Version : Tabpanel brokes practices of MVC pattern



lexer
8 Feb 2011, 11:53 PM
To create Iphone like bottom navbar I should use Tabpanel.

The bad thing here is that instead of controller tabpanel itself is responsible to set activeitems.

I tried to use tabbar separately from tab panel, but found that it is deeply coupled with tab panel and cannot be used without it.

I think you should decouple tabbar from tabpanel, so it can be used as menu control, which change event could be used to controller's actions.

lexer
9 Feb 2011, 3:17 AM
I've made a hack to get it work. But I think this should be solved by framework.


app.views.Viewport = Ext.extend(Ext.Panel, {
dockedItems: [
new Ext.TabBar({
dock : 'bottom',
ui : 'dark',
layout: { pack: 'center'},
cardLayout: this.layout,
cardSwitchAnimation: this.cardSwitchAnimation,
items: [
{
iconCls: 'activity',
text: 'Activity',
controller: app.controllers.activity,
action: 'index'
},
{
iconCls: 'prescriptions',
text: 'Prescriptions',
controller: app.controllers.prescriptions,
action: 'index'
},
{
iconCls: 'doctors',
text: 'Doctors',
controller: app.controllers.doctors,
action: 'index'
},
{
iconCls: 'myinfo',
text: 'My info',
controller: app.controllers.myinfo,
action: 'show'
}
],
listeners: {
'render' : function(bar) {
var tabs = bar.query('.tab')[0].activate();
},
'change': function (bar, currentTab, card) {
var tabs = bar.query('.tab');

var previousTab = null;

for (var i = 0; i < tabs.length; i++) {
if (tabs[i].active) {
previousTab = tabs[i];
tabs[i].deactivate();
}
}

var direction = (bar.items.indexOf(currentTab) < bar.items.indexOf(previousTab)) ? 'right' : 'left';

Ext.dispatch({
controller: currentTab.controller,
action: currentTab.action,
animation: {type:'slide', direction:direction}
});

currentTab.activate();
}
}
})
],

Hope you solve this in future versions.

SpNg
14 Feb 2011, 8:50 AM
I'm running into the same problem here. I have cards that don't belong in the bottom tabbar of a tabpanel, but when I render them with the controller the tabpanl starts adding them to the tab bar. Your solution is right on point of what I'm about to write. I wonder if there is something we are missing with best practice here.

Thanks for your post.

preyz
12 Apr 2011, 5:04 AM
Same problem here!!!

Sencha released a new Screencast that demonstrates how to create an interface like we imagine. However, even though the example code is using a MVC-like pattern, it does not include controller files. Maybe not a coincidence? Check it out:
http://vimeo.com/22251762

dreamdu5t
7 Jun 2011, 5:53 PM
Has anyone figured out a better solution to this? Otherwise, I'll have to use lexer's hack (thanks lexer!!!).

This should be handled by the framework, as there is no clean way to use an MVC architecture with tabs.

interfasys
7 Jun 2011, 6:11 PM
It's not necessarily wrong if Sencha is trying to build a framework that contains HMVC patterns. From my point of view, it's OK to have a hierarchy for some parts of the GUI.

dreamdu5t
7 Jun 2011, 6:58 PM
It's not necessarily wrong if Sencha is trying to build a framework that contains HMVC patterns. From my point of view, it's OK to have a hierarchy for some parts of the GUI.

Well it's not wrong, it just sucks that this is one of the few components that breaks the MVC pattern.

miroamarillo
7 Jun 2011, 8:25 PM
I was starting a new project with the MVC Model proposed by the videos and suddenly I bumped with this post. What are the recommendations then?? discard the MVC model and do it with the index.js and the Ext structure with the onReady function? Any hint here would be really appreciated as I found the MVC way a bit intricate for people that is just getting to know Sencha Touch. Any advice???

dreamdu5t
8 Jun 2011, 10:47 AM
I was starting a new project with the MVC Model proposed by the videos and suddenly I bumped with this post. What are the recommendations then?? discard the MVC model and do it with the index.js and the Ext structure with the onReady function? Any hint here would be really appreciated as I found the MVC way a bit intricate for people that is just getting to know Sencha Touch. Any advice???

You can:

* Live with having logic in your views.
* Use the method lexer posted above.
* Abandon the MVC pattern altogether.

I'd recommend using lexer's method. It would just be nice to have it in the framework.

tinyfactory
8 Jun 2011, 10:57 AM
I ended up using a derivative of lexer's post. Don't use a tab panel, use a toolbar with tabs that you active on your own, and use the rendering approach of the MVC pattern. I personally really like the MVC pattern as it keeps the DOM lightweight. Just mimic the functionality of the tab panel, and use the MVC pattern.

jchau
11 Aug 2011, 4:40 PM
any updates on the best practice to do this???

tinyfactory
11 Aug 2011, 5:45 PM
I ended up not using a tab panel, but just a bottom docked toolbar, with a bunch of tab components. When the tabs are tapped I have logic to make them active / inactive and dispatch to the controller to render the appropriate panels. Hope this helps.

senchito
18 Aug 2011, 12:52 PM
i also just ran into the same issue and am very glad to have found this thread! I will try lexer's example.

Tinyfactory is there any chance you could post an example of what you did? I also tried to use a toolbar but I found that it didn't accept my custom icons the same way the tabpanel was.. the icons are much smaller and the 'selected' style is quite different as well. I haven't tried to hack that style yet but I really like the look&feel of the tabpanel and was hoping to keep using that.

If you can make the toolbar look like a tabpanel i'd love to know how.

tinyfactory
19 Aug 2011, 8:59 AM
Sure. It took me a bit of digging to get everything working correctly initially. In the end this turned out to be very stable and allow me to use the MVC pattern to render panels to my Viewport as needed. This code is a snippet from my application Viewport in the dockedItems: [ ] array. Let me know if you want to see the whole panel:



{
xtype: 'tabbar',
dock: 'bottom',
ui: 'dark',
layout: {
pack: 'center'
},
items: [
{
id: 'home-tab',
xtype: 'tab',
iconCls: 'icon-home',
text: 'Home',
handler: function(){
if(!this.getEl().hasCls('x-tab-active')){
Ext.dispatch({
controller: 'Viewport',
action: 'renderHomeMenu'
});
}
}
},
{
id: 'suppliers-tab',
xtype: 'tab',
iconCls: 'icon-suppliers',
text: 'Suppliers',
hidden: HIDE_SUPPLIERS_BTN == true ? true : false, // this is set in the config.js file. removed when app is branded for a specific supplier
handler: function(){
if(!this.getEl().hasCls('x-tab-active')){
Ext.dispatch({
controller: 'Viewport',
action: 'renderSuppliers'
});
}
}
},
{
id: 'favorites-tab',
xtype: 'tab',
iconCls: 'icon-favorites',
text: 'Favorites',
handler: function(){
if(!this.getEl().hasCls('x-tab-active')){
Ext.dispatch({
controller: 'Viewport',
action: 'renderFavorites'
});
}
}
},
{
id: 'contact-tab',
xtype: 'tab',
iconCls: 'user',
text: 'Contact',
handler: function(){
if(!this.getEl().hasCls('x-tab-active')){
Ext.dispatch({
controller: 'Viewport',
action: 'renderContact'
});
}
}
}
]
}


The tab's active class ('x-tab-active') is being in the "render" event of the matching panel. I typically don't like to reference components by id, but in this situation it was the simplest solution. For example if you were to tap on my the "Favorites" tab, I have this in the "Favorites Panel":



listeners: {
render: function(){
Ext.getCmp('favorites-tab').getEl().addCls('x-tab-active');
}
}



Hoe this helps.

Alexander Rolek