Reputation: 23038
Does anybody please have an idea, why do I get the runtime error:
RangeError: Error #1125: The index 0 is out of range 0.
........
at Popup/update()[Popup.mxml:80]
at PopupTest/showPopup()[PopupTest.mxml:45]
at PopupTest/___btn_click()[PopupTest.mxml:52]
when calling the function:
private function showPopup(event:MouseEvent):void {
_popup.update(new Array('Pass' ,
'6♠', '6♣', '6♦', '6♥', '6 x',
'7♠', '7♣', '7♦', '7♥', '7 x',
'8♠', '8♣', '8♦', '8♥', '8 x',
'9♠', '9♣', '9♦', '9♥', '9 x',
'10♠', '10♣', '10♦', '10♥', '10 x'), true, 80);
}
As if my _list would have no entries at all (but why? I do assign _data.source=args) and thus the _list.ensureIndexIsVisible(0) call would fail at the line 80:
<?xml version="1.0" encoding="utf-8"?>
<s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="220" height="200"
initialize="init(event)">
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;
private static const FORCE:uint = 20;
[Bindable]
private var _data:ArrayList = new ArrayList();
private var _timer:Timer = new Timer(1000, 120);
private function init(event:FlexEvent):void {
_timer.addEventListener(TimerEvent.TIMER, timerUpdated);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleted);
}
public function close():void {
_timer.reset();
_data.source = null;
visible = false;
}
private function timerUpdated(event:TimerEvent=null):void {
var seconds:int = _timer.repeatCount - _timer.currentCount;
title = 'Your turn! (' + seconds + ')';
// show panel for cards too
if (seconds < FORCE)
visible = true;
}
private function timerCompleted(event:TimerEvent=null):void {
title = 'Your turn!';
close();
}
public function update(args:Array, bidding:Boolean, seconds:int):void {
if (seconds <= 0) {
close();
return;
}
// nothing has changed
if (ObjectUtil.compare(_data.source, args, 0) == 0)
return;
_data.source = args;
if (args == null || args.length == 0) {
close();
return;
}
if (seconds < FORCE || bidding)
visible = true;
_timer.reset();
title = 'Your turn! (' + seconds + ')';
_list.ensureIndexIsVisible(0); // the line 80
_timer.repeatCount = seconds;
_timer.start();
}
]]>
</fx:Script>
<s:VGroup paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10" gap="10" width="100%" height="100%">
<s:List id="_list" dataProvider="{_data}" width="100%" height="100%" fontSize="24" itemRenderer="RedBlack" />
</s:VGroup>
</s:Panel>
Upvotes: 0
Views: 1090
Reputation: 11912
the reason
You are adding the new array allright, but then the List starts creating ItemRenderers based on the items that are in that array. This takes some time and happens asynchronously. In the meantime you're saying "show me item 1", but the ItemRenderer for item 1 doesn't exist yet. It will very soon, but not right now. That's why you get an indexoutofrange error.
the solution
You have to be sure the List is done creating ItemRenderers before you call that method. The easiest way to solve this situation - though definitely not the cleanest - is to just wait until the next render cycle by using the infamous callLater().
callLater(_list.ensureIndexIsVisible, [0]);
This essentially saying: wait for the next render cycle and then call ensureIndexIsVisible()
on _list
with parameter 0
.
(On a side note: if you really only want index 0 this whole thing is rather pointless, because I think a List scrolls back to the top when its dataprovider is changed anyway)
a cleaner solution
You can listen on the List for the RendererExistenceEvent#RENDERER_ADD event. This will be dispatched whenever a new ItemRenderer was added to the list and it holds a reference to the item's index in the List, the data and the ItemRenderer itself. However in your case we only need the 'index'. Whenever an ItemRenderer is added at index 0 we'll scroll back to the top:
_list.addEventListener(RendererExistenceEvent.RENDERER_ADD, onRendererAdded);
private function onRendererAdded(event:RendererExistenceEvent):void {
if (event.index == 0) myList.ensureIndexIsVisible(0);
}
This will immediately scroll to the top when the first ItemRenderer is added and doesn't need to wait until all of them are ready.
Upvotes: 1