PDA

View Full Version : Dynamic Carousel setActiveItem MVC trouble



TheStreet
4 Sep 2012, 11:07 AM
Hi All,

I'm having trouble getting the setActiveItem method to work how I need it to. This is my first time using Sencha Touch. I have built a few apps with Ext 3.1 and Ext 4.0 so I thought I had a good base to start on, but this particular problem giving me trouble.

I have a container with Mitchell Simeons' ST2 Accordion docked left with several lists filled with data loaded from stores. On list item tap I fire a custom method in my controller to load the corresponding store and iterate through each record to build out an items array for a generic carousel view filled with a container that has a template for each carousel item. I then try to setActiveItem by id like I used to with Ext 4. What is happening is that it is setting the wrong item active, it set's the last item in the carousel active instead of the one I'm trying to send in.

I tried using an id with type 'number, when that didn't work I tried converting the id to a string, when that didn't work I tried using Ext.getCmp(id). If someone can shed some light on what I need to do to get this working properly it would be much appreciated.

I was able to, on init, set the active item using index 0, but my app needs more specificity than that.

Code:

Controller:


Ext.define('TheStreet.controller.News', {
extend: 'Ext.app.Controller',
requires: ['TheStreet.view.Article'],
config: {
refs: {
newsMain : 'newsmain',
newsFeed : 'newsfeed',
newsMenu : 'newsmenu',
article : 'article',
articleCarousel : '#articleCarousel',
sectionTitle : 'button[cls=x-section-title]',
splash : 'splash',
sectionCarousel : 'sectionCarousel'
},
control: {
newsfeed: {
select : 'onArticleTap',
selectionchange : 'onSelectionChange'
},
article: {
widthChange : 'newsWidthChanged',
viewready : 'fillCarousel'
},
sectionTitle: {
tap: 'onSectionTitleTap'
},
articleCarousel: {
viewready: 'onNewsInitialize'
}
}
},


init: function() {
// var me = this;


// this.newsmenu = this.getNewsMenu();
// this.newsmain = this.getNewsMain();
// this.newsfeed = this.getNewsFeed();
// this.article = this.getArticle();
// this.articleCard = this.getArticleCard();
// this.splashCard = this.getSplashCard();
console.log('News Controller Initialized');


},


newsWidthChanged: function(component, value, oldValue, eOpts) {
console.log('changed: ', component);
},


launch: function() {
// var topnews = this.getTopNews(),
// topNewsStore = Ext.getStore('TopNews');
// console.log('topNews:', topnews);
// console.log('topnews xtypes:', topnews.getXTypes());
},


onNewsInitialize: function() {
var articleCarousel = this.getArticleCarousel();
console.log('init carousel', articleCarousel);
this.loadCurrentSectionArticles(articleCarousel, 'StockPicks', 0);
},


onArticleTap: function(selection, record, eOpts) {
var newsmenu = this.getNewsMenu(),
newsmain = this.getNewsMain(),
articleCarousel = this.getArticleCarousel(),
sectionCarousel = this.getSectionCarousel(),
article = this.getArticle(),
storeId = record.stores[0].getStoreId(),
recordId = record.data.articleId;


console.log('Selection');
console.log('==========================');
console.log(selection);
console.log('Record');
console.log('==========================');
console.log(record);
console.log('eOpts');
console.log('==========================');
console.log(eOpts);


console.log('article component:',Ext.getCmp(recordId));


console.log('store id', storeId);
//newsmenu.deselectAllLists();
//sectionCarousel.hide();
this.loadCurrentSectionArticles(articleCarousel, storeId, recordId);
console.log('items',articleCarousel.getItems());


console.log('record id type', typeof(recordId));
//articleCarousel.setActiveItem(recordId);
console.log('active item',articleCarousel.getActiveItem());
},


onSectionTitleTap: function(btn) {
console.log('Button Title', btn.config.text);
var splash = this.getSplash(),
sectionCarousel = this.getSectionCarousel(),
article = this.getArticle(),
//articleCard = this.getArticleCard(),
section = btn.config.text.replace(/\s/g, '');


console.log('section', section);


article.hide();
splash.setStore(section);
sectionCarousel.show();
},


onSelectionChange: function(changed, records, eOpts) {
//console.log(changed, records, eOpts);
},


loadCurrentSectionArticles: function(carousel, store, item) {
console.log('store passed', store);
var store = Ext.getStore(store),
storeData = store.getData(),
items = [],
initItem = item,
changeItem = item.toString();


console.log('store data', storeData);

store.each(function(rec) {
var recId = rec.data.articleId;
items.push(Ext.create('TheStreet.view.Article', {
record: rec,
id: recId.toString()
}));
});


console.log('setActiveItem type', typeof(initItem));
console.log('activeItem passed', Ext.getCmp(changeItem));


carousel.setItems(items);
if (typeof(item) === 'number'){
carousel.setActiveItem(initItem);
} else {
carousel.setActiveItem(Ext.getCmp(changeItem));
}
console.log('carousel items', carousel.getItems());
}
});


Views:


Ext.define("TheStreet.view.Article", {
extend: 'Ext.Container',
xtype: 'article',


config: {
//id: articleId,
autoDestroy: true,
cls: 'articletpl',
layout: 'fit',
scrollable: {
direction: 'vertical',
directionLock: true
},
tpl: new Ext.XTemplate(
'<div class="sector">{sector}</div>',
'<div class="headline">{headline}</div>',
'<div class="byline">by {byLine}</div>',
'<div class="postedOn">posted on {[this.formatDate(values.publishDate)]}</div>',
'<div class="ticker">Ticker: {tickers}</div>',
'<div class="body"><img class="largeThumb" src="{largeThumb}" alt="" />{body}</article>',
{
// XTemplate configuration:
compiled: true,
formatDate: function(date){
var newDate = Ext.Date.parse(date, 'm-d-YTG:i'),
formattedDate = Ext.Date.format(newDate, 'F j,Y g:ia');
return formattedDate;
}
}
)
}
});

Ext.define("TheStreet.view.ArticleCarousel", {
extend: 'Ext.Carousel',
xtype: 'articleCarousel',


requires: ['TheStreet.view.Article'],


config: {
autoDestroy: true,
id: 'articleCarousel',
items: []
//layout: 'card',
//hidden: true
},


initialize : function() {
var me = this;


me.on('painted', function() {
me.fireEvent('viewready', me);
}, null, { single : true });


me.callParent();
}
});


Please excuse all the console.logs, I was too lazy to remove them.

mitchellsimoens
6 Sep 2012, 4:20 AM
Is typeof(initItem) return string or number?

TheStreet
6 Sep 2012, 6:22 AM
Right...I forgot to mention that that was the actual problem. No matter what I do it always seems to be a number. Which is why it's always treating it as an index.

mitchellsimoens
6 Sep 2012, 6:31 AM
The actual id of the component is a string due to your toString() call on the record id but you are trying to make a component active that the id is a number therefore probably failing there as the type can make a difference..

Like if you have


"1" === 1

That will be false. If you have


"1" == 1

That will be true

TheStreet
6 Sep 2012, 6:51 AM
Right...that is how Javascript works. Now that I fixed the typing issue by adding letters to the id I'm getting "Uncaught Error: [ERROR][Ext.Container#factoryItem] Invalid config, must be a valid config object ". I'm trying to understand how setActiveItem works. If it gets a number as a type it assumes it's an index? If it get's an object, it assumes it's a config object and tries to create a new card? How do I get it to just show a card that is already an item in the carousel?

mitchellsimoens
6 Sep 2012, 6:55 AM
Yes, best way to figure out how something works is to set a breakpoint and step into code. In the applyActiveItem method in Ext.Container, it checks the type of what you pass in. If it's a number, it does assume it's an index. If you pass a string it will try to find it via the id/itemId