flex actionscript-3 actionscript filereference flex4

El FileReference.save() de Flex solo se puede llamar en un controlador de eventos de usuario. ¿Cómo puedo evitar esto?



actionscript-3 actionscript (6)

Adobe lo hace como una especie de medida de seguridad para garantizar que los usuarios sean los que manipulen los archivos en lugar del código potencialmente dañino. Según tengo entendido, hacen cumplir esto al permitir que los manejadores de eventos (de clic) originados en los componentes de la interfaz de usuario ejecuten los métodos de FileReference, por lo que generar sus propios eventos mediante programación no funcionará, aunque no he intentado verificarlo. Desafortunadamente, la mejor resolución que he encontrado es volver a trabajar la UI un poco para cumplir con esta restricción. En su situación particular, podría hacer que este sea un proceso de dos clics con un botón que diga algo así como "Preparar descarga", que cambia a "Descargar archivo" después de que se complete el servicio web. Esto es menos que ideal desde la perspectiva del usuario, pero no creo que haya mucho más que pueda hacerse a menos que de alguna manera pueda completar su llamada al servicio web antes de mostrar el botón que activa la llamada a FileReference.save ().

Necesito llamar a FileReference.save () después de que se haya completado una llamada al servicio web, pero este método tiene una restricción: "En Flash Player, solo puede llamar a este método satisfactoriamente en respuesta a un evento de usuario (por ejemplo, en un controlador de eventos) para un clic de mouse o un evento de pulsación de tecla). De lo contrario, llamar a este método da como resultado Flash Player lanzando una excepción de Error ". (de la documentación aquí )

Esta restricción es un poco vaga. ¿Significa que solo puedo llamar al método FileReference.save () desde una función de controlador de eventos que está registrada como escucha para ciertos tipos de eventos de usuario? Si es así, ¿qué eventos de usuario son válidos exactamente? (Tal vez haya un evento que nunca será enviado por la interacción del usuario con mi aplicación y podría registrar una función de controlador de eventos para ese tipo de evento y realizar la llamada a save () desde esa función?)

Mi dificultad es que no puedo llamar de forma segura al método FileReference.save () hasta que mi servicio web regrese con los datos que se utilizarán como argumento de la llamada al método FileReference.save (), por lo que el evento que desencadena la FileReference. save () es en realidad un evento ResultEvent en lugar de un evento de usuario, y estoy receloso de enviar un nuevo tipo de evento de usuario (falso) para poder activar la llamada FileReference.save () a menos que sea definitivamente un evento de usuario que nunca sería enviado como resultado de la interacción real del usuario con mi aplicación.

En pocas palabras, lo que estoy haciendo ahora es esto: tengo una función que está registrada como controlador para un clic de botón. En esta función realizo mi llamada al servicio web para obtener datos del servidor. También tengo una función de controlador de resultados que se invoca cuando finaliza la llamada al servicio web, y aquí es donde quiero llamar al método FileReference.save () ya que es en este punto que sé que los datos están listos para guardarse en un archivo. Pero la restricción antes mencionada me está impidiendo hacer esto, me sale un 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.

He intentado hacer muchas cosas para evitar esto, como crear una segunda función de administrador de eventos de clic de mouse con la llamada FileReference.save () dentro y llamarla después de un intervalo de tiempo de espera (para dar tiempo al servicio web para completar), pero sigo corriendo el mismo error - tal vez ese enfoque no funciona ya que la segunda función no está registrada como un detector de eventos para el tipo de evento utilizado como argumento.

Soy nuevo en el desarrollo de Flex así que tal vez no estoy pensando en esto de la manera correcta. Si alguien puede sugerir otro enfoque, realmente lo agradecería. Gracias de antemano por sus comentarios o sugerencias.

--James


Después de luchar por eso durante un par de horas, encontré una solución alternativa: puedes usar los eventos MouseDown AND mouseUp en lugar de simplemente hacer clic.

Por ejemplo: s: Botón mouseDown = "prepare_PDF ()" mouseUp = "save_PDF ()"

¡Funciona bien para mí!

Feliz codificación!

--Thomas


Este es un comentario sobre la respuesta de Thomas (todavía no tengo suficientes XP para comentar): la solución alternativa para mousedown y mouseup funciona muy bien. Solo tenga en cuenta que si realiza cambios en prepare_PDF() que necesitan ''deshacer'' en save_PDF() , entonces es una buena idea llamar también a ese código en el evento mouseout , ya que podría haber un caso en el que el mousedown del usuario esté activado. el botón, pero luego aleja el mouse del botón.

Esto fue particularmente relevante para mi caso, en el que aumentamos el tamaño de una marca de agua en una imagen cuando el usuario hace clic en el botón de descarga (que desencadena la llamada a .save() ). mousedown el tamaño de la marca de agua a la normalidad en los eventos mousedown y mouseout .


Como solución, utilicé la clase ExternalInterface. Creé una función de JavaScript con este código

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

En AS3 llamo

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

Entonces con eso transfiero el manejo del archivo a JS / HTML.


Tuve este mismo problema, elegí usar los métodos de flash.net. Llame a flash.net.navigateToURL(url); desde un actionscript o navigateToURL(url); de mxml


Lo que hago para resolver esto es mostrar un mensaje de alerta con una función anónima para que no tenga que crear un botón.

Alert.show("Do you wish to download the file?", "Confirm", Alert.OK | Alert.CANCEL, this, function (eventObj:CloseEvent):void { if (eventObj.detail == Alert.OK) { fileReference.save(zipOut.byteArray, dateFormater_titulo.format(new Date ()) + ".zip"); }//if }/*function*/, null, Alert.OK);