Flex's FileReference.save() can only be called in a user event handler -- how can I get around this?

11,135

Solution 1

Adobe does this as a sort of security measure to ensure users are the ones messing with files rather than potentially harmful code. My understanding is that they enforce this by only allowing handlers of (click?) events that originate from UI components to execute the FileReference methods, so generating your own events programmatically will not work, although I have not tried to verify this. Unfortunately the best resolution I've found is to re-work the UI a bit to conform to this constraint. In your particular situation, you could make this a two click process with a button that says something like "Prepare Download", which changes to "Download File" after the web service is complete. This is less than ideal from a user perspective, but I don't think there's much else that can be done unless you can somehow complete your web service call prior to displaying the button that triggers the FileReference.save() call.

Solution 2

After struggling for that for well, a couple hours I found a workaround: you can use both mouseDown AND mouseUp events instead of just click.

For instance: s:Button mouseDown="prepare_PDF()" mouseUp="save_PDF()"

Works fine for me!

Happy coding!

--Thomas

Solution 3

As a workaround I used the ExternalInterface class. I created a javascript function with this code

function downloadFile (url) {
            window.open(url);
        }

An in AS3 I call

var url = 'www.example.com/downloadfile.php?file_id=xxx';
ExternalInterface.call('downloadAttachmentFile', url);

So with that I transfer the file handling to JS/HTML.

Share:
11,135
James Adams
Author by

James Adams

Updated on June 05, 2022

Comments

  • James Adams
    James Adams about 2 years

    I need to call FileReference.save() after a web service call has completed, but this method has a restriction: "In Flash Player, you can only call this method successfully in response to a user event (for example, in an event handler for a mouse click or keypress event). Otherwise, calling this method results in Flash Player throwing an Error exception." (from the documentation here)

    This restriction is a bit vague. Does it mean that I can only call the FileReference.save() method from within an event handler function that is registered as a listener for certain types of user events? If so then exactly which user events are valid? (Perhaps there's an event that will never be dispatched by user interaction with my application and I could register an event handler function for that event type and make the save() call from within that function?)

    My difficulty is that I can't safely call the FileReference.save() method until my web service returns with the data that will be used as the argument of the FileReference.save() method call, so the event that triggers the FileReference.save() call is actually a ResultEvent rather than a user event, and I'm leery of dispatching a new (faux) user event type in order to be able to trigger the FileReference.save() call unless it's definitely a user event that would never be dispatched as a result of actual user interaction with my application.

    In a nutshell what I'm doing now is this: I have a function that is registered as a handler for a button click. In this function I make my web service call to fetch data from the server. I also have a result handler function which gets invoked when the web service call completes, and it's in here that I want to call the FileReference.save() method since it's at this point that I know that the data is ready to be saved to a file. But the aforementioned restriction is blocking me from doing this -- I get an error:

    Error #2176: Certain actions, such as those that display a pop-up window, 
    may only be invoked upon user interaction, for example by a mouse click 
    or button press.
    

    I've tried many things to get around this such as creating a second mouse click event handler function with the FileReference.save() call within and calling it after a timeout interval (to give the web service time to complete), but I keep running into the same error -- maybe that approach doesn't work since the second function isn't registered as an event listener for the event type used as its argument.

    I'm new to Flex development so perhaps I'm just not thinking about this in the right way. If anyone can suggest another approach I'd really appreciate it. Thanks in advance for your comments or suggestions.

    --James

  • user7740901
    user7740901 almost 14 years
    This is accurate. Browser based Flash applications are expected to obey the normal browser sandbox rules. Another option would be using Adobe AIR which gets outside of the browser sandbox (but requires the user to install the app).
  • James Adams
    James Adams over 13 years
    Thanks for this, Thomas. I haven't messed with this application in some time so I may not ever get the chance to test this, but it looks like a good solution and is something good to know and keep in mind.
  • paleozogt
    paleozogt about 13 years
    If prepare_PDF is asynchronous, it seems like you'll be in a race-condition with save_PDF. What do you do in save_PDF if prepare_PDF hasn't completed yet?
  • paleozogt
    paleozogt about 13 years
    Since you're doing a web-service call, I don't see how this works. You fire off the webservice call from mouseDown and assume its been completed by the time mouseUp happens. What if mouseUp happens before the webservice call completes?
  • Jaffer
    Jaffer about 13 years
    @paleozogt the web-service call is being fired on mouseUp, not mouseDown.
  • paleozogt
    paleozogt about 13 years
    In Thomas' example, prepare_PDF (called from mouseDown) is the webservice call, right? Then save_PDF (called from mouseUp) calls FileReference.save.
  • Mifune
    Mifune about 12 years
    It's still confusing the way this is written, if we're doing an AMF RemoteObject call, how can we do the call after the save() is initiated in mouseDown()?
  • durron597
    durron597 over 11 years
    Please pay attention to whether you are replying to an active thread... this thread is 2 years old and has an accepted answer!
  • havoc24k
    havoc24k over 11 years
    Yes but many people like me end up on "old" threads from google. So why not offer an alternative to another answer seeker like me?
  • Venryx
    Venryx over 6 years
    Agreed. I came here from a Google search, and want up-to-date answers, not just the one the OP liked!