lightning_2

Cómo adjuntar multiples Archivos desde un componente Lightning PARTE 2

Tweet about this on TwitterShare on Facebook0Share on Google+0Share on LinkedIn0Digg thisBuffer this pageEmail this to someone

Este post surgió de la necesidad de adjuntar múltiples archivos desde un componente Lightning. Salesforce limita el tamaño de los paquetes de callback desde Lightning a algo menos de 5 MB, por lo tanto, tuvimos que idear una manera de realizar llamadas sucesivas e ir insertando/completando nuestros archivos, llamada tras llamada.  En la entrada anterior vimos cómo crear un componente lightning que nos permitiera seleccionar archivos desde nuestro ordenador con sus validaciones correspondientes y al cual podíamos indicarle el número máximo de ficheros a adjuntar y el tamaño máximo para cada uno de ellos. El siguiente paso sería el de ilustrar su uso y la rutina que nos va a permitir almacenar estos archivos de forma estática en la base de datos de Salesforce.

Objeto para el almacenamiento

Existen varios objetos estándar de Salesforce para representar archivos: Attachment, FeedAttachment, ContentVersion, etc. En esta entrada hemos utilizado el objeto Attachment para nuestros ficheros. Salesforce impone que para el almacenamiento de Attachments es necesario especificar un parentId, es decir el registro al cual hagan referencia. En este caso hemos escogido el Account del usuario actual.

Uso del componente

Nuestro componente FileInputLoader necesita ser utilizado dentro de otro componente padre (FilesUploader) que reciba los archivos seleccionado y gestione la subida de los mismos. La forma de que ambos componentes posean la lista de ficheros de forma reactiva es haciendo que el atributo que compartan ambos se corresponda con el atributo de salida del hijo (fileList).

FilesUploader

Nuestro componente padre se compondrá de un markup, controller y helper. Además necesitaremos desarrollar un controlador en APEX (FilesUploaderController) para gestionar las llamadas DML para el proceso de almacenamiento.

Markup

En el siguiente fragmento de código podemos ver como integrar nuestro componente, nuestro controlador en APEX y cómo enlazar los atributos entre el padre y el hijo.

Controller

Para conseguir el Id del account asociado al usuario actual es necesario manejar el evento init para realizar una petición a nuestra clase APEX en el proceso de “inicialización” del componente.

Para iniciar el proceso de subida incluimos un botón cuya acción la definiremos en el controller del componente padre como una función (uploadFiles):

Desde uploadFiles se llamará a la función saveFiles en el helper que se encargará de leer los datos de los archivos y gestionar su subida.

Helper

La función getCurrentAccountId realizará una llamada al controlador en APEX que devolverá el Id del Account del usuario actual y que podremos usar como parentId a la hora de crear los objetos Attachment para nuestros ficheros.

En saveFiles creamos un objeto FileReader nativo de JavaScript para leer nuestros archivos. Con el atributo idx del helper especificamos el archivo a leer en el handler onload del objeto FileReader. Cuando hemos leído los datos del fichero necesitamos quedarnos con los datos en base64 y con esa cadena de caracteres llamar a la función uploadFile para gestionar la subida individual.

A partir de este momento debemos hacer frente a dos problemas que nos propone Salesforce:

  • El límite de datos de transferencia entre el controlador y el componente lightning.
  • El lifecycle del evento press del button que inicia la acción.

La solución sería limitar el tamaño de los archivos a subir. Esto limita bastante nuestro componente por lo que debemos plantearnos realizar la subida partida de archivos o mediante chunks.

Según la documentación de Lightning, todas las actions en cola se ejecutarán al finalizar el lifecycle que las engloba. Nuestra acción para la subida de cada chunk al llamarse en el marco de ejecución del evento onload del FileReader ha perdido el contexto del lifecycle del evento press original por lo que deberemos llamarla de otra forma y que se ejecute fuera de este ámbito. Para ello utilizamos la función $A.getCallback.

Este proceso quedaría de la siguiente manera en nuestro helper:

FilesUploaderController

Ya tenemos todo lo necesario en nuestro componente para realizar el proceso de subida. Ahora nos faltaría el desarrollo de los métodos de nuestro controlador en APEX.

Los métodos saveChunkFile y getAccountId poseen la cláusula @AuraEnabled para que el componente tenga acceso a ellas desde el controller y el helper.

Desde saveChunkFile se llamaría a la función saveAttachment si todavía no se ha creado un Attachment o a la función appendToAttachment para añadir el siguiente chunk de datos al body del Attachment que ya existe para el fichero en contexto. Los archivos harían referencia al Account de nuestro usuario actual por lo que sólo tendríamos que visitar el detalle para poder ver el listado.

Ya tenemos nuestro sistema de subida de ficheros listo para usar en cualquier proyecto.

Que paséis una buena semana!