2

I have created a custom ComboCheck which extends the spark DropDownList that is a DropDownList of checkboxes. Inside of my itemRenderer I have the code:

[Bindable]override public function set data (value:Object):void {
    if (value!=null) {
        _data = value;
        item.label = value.label;
        item.group = value.group;
        item.toolTip = value.toolTip;
        item.selected = value.selected;
        item.enabled = value.enabled;
    ...

This code allows me to enable and disable individual items in the dropdown list so that when it is rendered, you will not be able to select the items I have disabled. I am trying to create the functionality where a user clicks on a specific item that is in a given category which results in all other categories being disabled until you de-select everything.

My issue is that while the DropDownList is up, the items have already been rendered so changing the enabled property on each item that should be disabled doesn't change the items that have already been rendered. If you scroll down and back up to re-render the data it works fine.

Is there a way to have the itemRenderer re-render the data on the screen so that it refreshes and applies this update?

Below is sample code of an item being selected, it disables every other item then enables only the one you have selected. I also have a itemDeselect function that decrements the itemCount and enables everything

private function itemSelect(evt:Event):void{
            itemCount++;
            var myText:String = '';
            var items:Vector.<Object> = allItems.selectedItems;
            if(itemCount == 1){
                    for each(var obj:Object in allItems.dataProvider){
                        obj.enabled = false;
                    }
            }
            for (var i:String in items) {
                if(items[i].group == "HU"){
                    items[i].enabled = true;
                    huList[items[i].label] = items[i].selected;
                }else if(items[i].group == "ALL"){
                    items[i].enabled = true;
                    allCase = items[i].selected;
                }else{
                    items[i].enabled = true;
                    otherList[items[i].label] = items[i].selected;
                }

            }

            selectionChanged = true;
}

This works but again it is not re-rendered so the obj.enabled=false does not appear unless you scroll down and back up.

EDIT: Final Solution
Using the third option suggested by www.Flextras.com I used the itemUpdated property dataProvider.itemUpdated(obj) so inside of the

for each(var obj:Object in allItems.dataProvider){
    obj.enabled = false;
    allItems.dataProvider.itemUpdated(obj);
}

This will also not cause the dropdownlist to reset to scrollPosition 0

Mike
  • 8,137
  • 6
  • 28
  • 46
  • Hi Mike, in the update your sentence seems to be cut off, "I used the itemUpdated property dataProvider.itemUpdated(obj) so inside of the..." blank. Is it inside of the itemrenderer? And if so are you calling it on a specific event? Thanks (background - the data in the data provider can change in another location but the item render for that data item isn't updated.) – 1.21 gigawatts Dec 06 '11 at 20:08
  • I am not sure what I had meant to say there now :P No I did not have it in the itemrenderer but instead in the click event after adding the new value. This may not be the best way to do it since I found out recently my code is a bit buggy with how it does the update (Although I think that is my fault on how I set up the ItemRenderer). I think that if you iterate through all objects in the dataprovider when the data inside of it changes and do the itemupdated you should be okay. – Mike Dec 07 '11 at 17:08

3 Answers3

3

Is there a way to have the itemRenderer re-render the data that is shown to apply this update?

I have three ways.

1) invalidate the list's dataGroup instead of the list.

listInput.dataGroup.invalidateDisplayList();

2) Refresh the dataProvider

(listInput.dataProvider as ArrayCollection).refresh();

3) When the dataProvider item changes, invoke the itemUpdated() property on the collection. No code sample for this one, sorry.

The one thing I often forget to do in this situation is implement the renderer so that it knows to switch itself back into the 'non-active' state. So in your set data method of the itemRenderer be sure to add an else condition putting all those values back to some default.

JeffryHouser
  • 39,401
  • 4
  • 38
  • 59
  • I tried some of these out (although i did not have a dataGroup specifically defined so that one didn't work for me) but I think I worded the question wrong. Is there any way to re-render it on the screen so the disabling of values is apparent immediately? The data is affected immediately but since they are rendered already because the dropdown is still open, the values that are displayed do not disabled – Mike Mar 02 '11 at 16:30
  • Edit: The second option works but it always brings the dropdown to the top (ie if you're scrolled to the bottom and click something it then scrolls it up to the top as it applies the change). Is there any way to maintain the position the client is viewing the dropdown at while still refreshing the data? – Mike Mar 02 '11 at 16:41
  • @Mike I'm still pretty sure this answers your question. Any of these should cause the list renderers to re-render themselves and visual changes should be apparent immediately. I think the dataGroup is part of the skin; which contains the drop down list, which contains the renderers you want to update. For your use case, you may need to do something like this: dropDownList.dropDown.dataGroupd.invalidateDisplayList() . If you can provide a runnable code sample, that may help more. – JeffryHouser Mar 02 '11 at 16:43
  • It does answer the question thank you, will the invalidateDisplayList not move the scrolled position on the dropdownlist? This is now my issue if you look at my second comment, each time it is refreshed it updates but brings you all the way scrolled to the top. If I am looking at just the top items it works as I wanted (can you return them to the scrolled position after the refresh?). I will try to provide a working code sample for you though. – Mike Mar 02 '11 at 16:52
  • @Mike: I just have been writing my previous comment when you made the 2nd; sorry about that. We cross our streams. I would not expect invalidateDisplayList to scroll the drop down, however I can understand why calling refresh on the dataProvider does. The 'list' won't know exactly what changed, so it resets itself. I'd look into getting at the scrollPosition of the scroller; saving it and resetting it and you update. Looks like you'll have to do some API diggingfind that out, though. [I couldn't find it in a minute) – JeffryHouser Mar 02 '11 at 18:43
  • @Flextras Yes I have been spending time looking through it all before you commented and was trying to use the dataGroup's verticalScrollPosition since I thought the scroller on the dropDown would be the answer but it turned out to be null while debugging. I also was watching the firstInView, dataGroup.scrollRect, dataGroup.layout.verticalScrollPosition and firstIndexInView, and dropDownController.dropDown.y yet none of these reset to 0 after the refresh was called so I am at a bit of a loss – Mike Mar 02 '11 at 19:03
1

I found the way to "re-render", just override the set data function and update all the properties in the itemRenderer: eg

I have a DataGrid with a column with an itemRenderer that shows a different backgroundColor for each item in my dataProvider.

<mx:DataGrid>
  <mx:columns>
    <mx:DataGridColumn itemRenderer="myItemRenderer"/>
  </mx:columns>
</mx:DataGrid>

//myItemRenderer:

override public function set data( value:Object ) : void {
  super.data = value;
  if( value > 0) setStyle("backgroundColor",0xff99ff);
  else setStyle("backgroundColor",0xffffff);
}

That's all.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
0

You can also add event listener for dataChange event to the item renderer itself. This event gets fired after data property is changed.

<s:ItemRenderer dataChange="updateView(event)">
    <fx:Script>
        <![CDATA[
            protected function updateView(event:Event):void{
                //update logic
            }
        ]]>
    </fx:Script>
</s:ItemRenderer>
bekce
  • 3,782
  • 29
  • 30