views:

344

answers:

2

Hi troops,

how would you prevent dragging for some items of your List or DataGrid?

Let's say I had a list with two items: 'Tom' and 'Jerry'. Only 'Tom' should be dragable, not 'Jerry'.

Ideally I had a 'isDragEnabled(item:Object):Boolean' function, which is being queried by the drag source.

My difficulties start with the fact that the 'dragStart' event handler has a null value for the dragSource, so right from the start I find it hard to find out what the drag-start is about..

Thanks in advance!

PS There have been a few discussions on preventing or canceling a drop, but I haven't seen much about preventing the drag start, hence this question.

+2  A: 

You can do two things:

  1. You can disable items in the List that are not draggable, based on a property on that selectedItem's data object. This will cause them to appear visually disabled, which you may not want, so you can also try...

  2. You can set the dragEnabled property of the list to "true" when valid items (based on the selectedItem's data object) are selected, and to "false" when the items are invalid.

Robusto
Good options Robusto, have you used/tested either of them? 1 seems pretty foolproof, but visually annoying. 2 seems like it would work, but a lot of things that seem like they should work for me don't.
invertedSpear
I have used them both and they work for my company. Note that #1 uses the disabledFunction property of the List, while #2 calls a handler from the dragDrop event, which checks whether the row is valid to drag and if it is NOT valid calls event.stopImmediatePropagation() and event.preventDefault().
Robusto
A: 

Ok, got it, thanks Robusto, your tip #2 was the inspiration, however I had to use a mouse-down listener -- the selection event fires too late.

In the sample all below I am using code from some other question of mine.

This sample lets you drag only the first item in the List or DataGrid:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" minWidth="955" minHeight="600">

    <mx:List id="list" dataProvider="{['Tom','Jerry', 'Amy', 'Betty', 'Chris', 'Dean', 'Email', 'Floyd', 'Grant', 'Helen', 'Iris', 'Jack']}" minWidth="200"
        mouseDown="onMouseDown(event)"
        />

    <mx:DataGrid id="dg" dataProvider="{[{title:'Tom'},{title:'Jerry'}]}" minWidth="200"
         mouseDown="onMouseDown(event)" 
    >
        <mx:columns>
            <mx:DataGridColumn dataField="title" />
        </mx:columns>
    </mx:DataGrid>

    <mx:Script>
        <![CDATA[
            import mx.controls.listClasses.ListBase;
            import mx.events.DragEvent;


            protected function onMouseDown(event:MouseEvent):void
            {
                var listBaseComp:ListBase = ListBase(event.currentTarget);
                var clickIndex:int = this.findClickedItemIndex(event.stageX, event.stageY, listBaseComp);
                listBaseComp.dragEnabled = clickIndex == 0;
            }

            /**
             * Returns a dataProvider item that displays at the given coords for the given dataGrid.
             * Code provided by Stackoverflow user http://stackoverflow.com/users/165297/amarghosh,
             * thanks a lot!
             */
            protected function findClickedItemIndex(globalX:Number, globalY:Number, listComp:ListBase):int
            {
                var p1 : Point;
                var p2 : Point;
                var renderer : DisplayObject;

                for(var i:int=0; i<listComp.dataProvider.length; i++) {
                    renderer = DisplayObject(listComp.indexToItemRenderer(i));
                    if (!renderer) //item is not displayed (scroll to view it)
                        continue;
                    p1 = new Point(renderer.x, renderer.y);
                    p2 = new Point(renderer.width, renderer.height);
                    p1 = renderer.parent.localToGlobal(p1);
                    p2 = renderer.localToGlobal(p2);
                    if(globalX >= p1.x && globalX <= p2.x && globalY >= p1.y && globalY <= p2.y)
                        return i;
                }   
                return -1;
            }

        ]]>
    </mx:Script>
</mx:Application>
Tom