tags:

views:

342

answers:

5

I wonder how to achieve this in Flex.

Basically, I have enabled Drag and Drop in some of my list controls.

<mx:DataGrid id="dg1" width="100%" height="100%" dataProvider="{xmllcData}"   
             dropEnabled="true" dragDrop="dg1_dragDropHandler(event)">
</mx:DataGrid>

In the function dg1_dragDropHandler event, I have the following codes:

private function dg1_dragDropHandler(evt:DragEvent):void
{
  // Perform some actions here...
  // .......

  // Show Message to Confirm.
Alert.show('Proceed?', 'Title', Alert.YES | Alert.NO, null, handleAlert, null, Alert.YES);
}

private function handleAlert(evt:CloseEvent):void 
{
  if (evt.detail == Alert.YES)
{
 // Perform the functions as necessary
}
else
{
 // Execute the script to prevent the dropping of the object.
 // How can I call the DragEvent.preventDefault(); function from here?
}

}

In the codes above, I want to call the preventDefault() on the alertHandler function since the other scripts after the call to the Alert.show in dg1_dragDropHandler event would be executed concurrently with the alert.show.

How would I be able to reference the DragEvent of the dg1_dragDropHandler event from the alertHandler event?

A: 

You probably want to store the details of the dropEvent in a local variable. Then when you want to do your "preventDefault" part, just access the event object and do your magic.

Not sure why you want to preventDefault though. I'm not quite understanding that part. Wouldn't all the other listeners of the event run to completion while the program is waiting for you to say YES/NO to the alert?

Glenn
The preventDefault is meant to prevent the dragDrop operation if the condition is not met. As you can see, I have placed a limiting Alert.show function there to confirm from the user if to proceed with the operation *despite* the condition. If user would click on NO, then I do not have any idea how the alertHandler would be able to handle the preventDefault function which is only available to the dragEvent.
Angelo
What I'm saying is that I expect that by the time you click "NO" on the alert, it's already too late. The problem is, I believe you're dealing with multiple call stacks. While the alert dialog shows, I'm expecting that your other call stacks will execute and complete the event. Maybe what you want to do allow the drop, but if "NO" is selected, you delete the drop immediately.
Glenn
Yes you're quite right. The other call stacks are executed immediately. If the No is selected, then prevent the drop which is done by calling preventDefault of the event. But if you could only continue the same from the alertHandler, how would you reference the dragEvent then?
Angelo
dragEvent can always be accessed if you decide to save it to a local variable. But that's not the problem. The event is actually just an object with information in it. By the time you hit "NO", the callstack where "preventDefault" would have had an effect has already (probably) run to completion. That being said, I'm not sure how to solve your basic problem. The only way you can use preventDefault effectively is to change it within the original drop handler.
Glenn
A: 

Instead of specifiying your listener function, handleAlert(), as a normal function, you can use an anonymous function. Write your code like this:

private function dg1_dragDropHandler(evt:DragEvent):void
   {
   // Perform some actions here...
   // .......

   // Show Message to Confirm.
   Alert.show('Proceed?', 'Title', 
               Alert.YES | Alert.NO, 
               null, 
               function(evt:CloseEvent) {
                     if (evt.detail == Alert.YES) {
                        // Perform the functions as necessary
                     }
                     else {
                      // Execute the script to prevent the dropping of the object.
                      // Now you have access to the evt:DragEvent!
                     }
                },
                null, Alert.YES);
             }
     }

When you use an anonymous function, you still have access to all the variables in your current scope. This means you can still access the evt:DragEvent variable. As Glenn said though, I don't know if this will solve your default action problem.

ryanday
A: 

Which other parts of the callstack are operating here? You could stop anything else in the event chain from happening by calling event.stopImmediatePropergation(); on the first line of your dragDropHandler (assuming that the listener has a higher priority than others in the chain). You would then need to manually replicate the drag and drop operations on confirm, which I'm not sure but you could achieve using the doDrag() method of the DragManager.

DragManager.doDrag() langauge reference

A: 

You're absolutely right that the Alert will be popped up asynchronously with respect to the original DragEvent dispatch.

Since you don't want the default datagrid behavior to kick in at that point, you need to call preventDefault() on receipt of the event, and then throw up your alert panel.

Then, in the success branch of your alert handler, you could try to rethrow ( throw a new) DragEvent. Use a local variable to keep track of the original event details so that you can clone() or simply create a new event with the same properties. Basically, you're intercepting and interrupting the event flow and then attempting to resume it later.

Haven't tried this myself, but that's what I'd explore first.

verveguy
A: 

I have not tried this myself, but preventing default behavoiur immediately is the only way to stop the grid from performing the copy or move.

Try preventing the default behaviour and maintaining the drag event. Then, if you user hits no, you have already stopped the event. If the user hits yes, you can (this is the part i am unsure of) re-dispatch the drop event on the grid. Hopefully it will behave normally. To get the event into your Alert handler you can simply use the data property on the Event window to track it.

private function dg1_dragDropHandler(evt:DragEvent):void 
{ 
  // Perform some actions here... 
  // ....... 

  evt.preventDefault();

  // Show Message to Confirm. 
Alert.show('Proceed?', 'Title', Alert.YES | Alert.NO, null, handleAlert, null, Alert.YES).data = evt; 
} 

private function handleAlert(evt:CloseEvent):void  
{ 
  if (evt.detail == Alert.YES) 
{ 
        // Perform the functions as necessary 
    var dgEvt:DragEvent = Alert(evt.currentTartet).data;
    var newDrag:DragEvent;   //need a new event because the default behaviour on the old one is still prevented
     //copy event values to new drag event
    dg1.dispatchEvent(newDrag);

} 
else 
{ 
        // Execute the script to prevent the dropping of the object. 
        // How can I call the DragEvent.preventDefault(); function from here? 
} 

Again, not entirely sure if it will work, just off the top of my head. Of course, you have to remove the custom dragDrop event handler from your grid before you redispatch the approved drag, otherwise your handler with prevent the default, then pop an alert and repeat over and over.

David