Mostrando entradas con la etiqueta Fórmulas en código. Mostrar todas las entradas
Mostrando entradas con la etiqueta Fórmulas en código. Mostrar todas las entradas

jueves, 17 de diciembre de 2020

Insertar logo en pestaña (código y proceso extraño)

Estoy haciendo una aplicación para crear actas y necesito que en la pestaña de cada acta aparezca como encabezado el logo del centro.

Quiero, además, que la imagen del logo esté en drive.

Como cada pestaña con cada acta se crea por código, no me vale el menú insertar-imagen-en celda, ya que, que yo sepa, no hay forma de hacerlo desde código.

Pero si puedo utilizar la función "image(url;[]) 

Pero la url que nos da drive de una imagen, utilizando "conseguir enlace" no funciona con esta función. 

Me funciona, sin embargo, la combinación de https://drive.google.com/uc?export=view&id= con el id de cada imagen.

Para hacerle la vida más fácil al usuario, le pido la url de "conseguir enlace" y mediante este trozo de código la convierto al tipo de enlace que he descrito en el anterior párrafo:

  

  var herramienta = SpreadsheetApp.getActiveSpreadsheet()

  var imagen_url = herramienta.getRangeByName('imagen').getValue()
  var imagen_primera_parte = "https://drive.google.com/uc?export=view&id="       
  var imagen_id =  imagen_url.match(/[-\w]{25,}/)
  var imagen = imagen_primera_parte+imagen_id

pestana.getRange('A1').setValue('=image("'+imagen+'";1)')

 

El código funciona perfectamente: desde la url extrae el id de la imagen y después la añade al enlace especial. Con la última fila del código, insertamos la imagen en la celda A1 con la función image.


Pero, me he encontrado con la SORPRESA que hay veces que la imagen aparece y otras que no.

Después de investigar y probar diferentes situaciones, me he encontrado con que aparece siempre la imagen si utilizamos un proceso muy particular.

 El proceso funciona así:

  1. Debemos subir la imagen desde el ordenador
  2. Debemos darle permiso público a la imagen(cualquiera con el enlace)

Sorprendentemente, no me ha funcionado con imágenes que ya estaban de antemano en mi Drive y, por supuesto, ninguna imagen que no tenga dado el permiso público de antemano.

domingo, 20 de mayo de 2018

Crear formulario de varias líneas dentro de una hoja de cálculo

 Este código nos va a servir para poder tener los datos que vienen de un formulario (grabados en una pestaña normalmente llamada 'Respuestas de formulario') en una pestaña diferente a la que los recoge  y que podamos cambiarlos, de tal forma que se cambien a la vez en la pestaña 'Respuestas de formulario'.
Google Script tiene alguna función configurada por defecto. Una de ellas es onEdit(event)
La función onEdit(event) tiene una potencia muy grande, tanta que necesita llenarla con condicionales que la frenen. Esta función se dispara en cuanto se cambia el contenido de cualquier celda de la hoja de cálculo. Por lo tanto para domarla podemos hacer esto:

// Primero pillamos la referencia de la celda que se ha editado
  var celda_cambiada= event.source.getActiveRange().getA1Notation();
// Y luego creamos un condicional como este
   if (celda_cambiada=="B4") {}

Así, solamente correrá el código que metamos dentro del condicional y en el caso que editemos B4

Imaginaros que en B4 ponemos una lista desplegable de poblaciones. Y en la pestaña de respuestas de formulario tenemos datos sobre centros públicos y una de las columnas (La B) nos da la población donde está dicho centro. Si escribimos lo siguiente:

function onEdit(event){
   var celda_cambiada= event.source.getActiveRange().getA1Notation();
   if (celda_cambiada=="B4") {
       formulario.getRange('A7').setValue('=filter('Respuestas de formulario'!a:h;datos!B:B=B4)')
                                             }
               } 

... conseguimos un filtro con los datos de la población elegida en B4. No muy sorprendente.
Pero, una vez conseguidos los datos, como estamos en la función onEdit, cualquier cambio que hagamos en estos datos podemos pillarlos y, con código, hacer que cambien también en la pestaña respuestas de formulario, con lo que tendríamos en una segunda pestaña la posibilidad de cambiar datos en todos los sitios a la vez, como si fuera un formulario interno.

Uno de los problemas de esta técnica es que nos molesta la fórmula que hemos puesto en A7. Nos vendría bien tener los datos filtrados, pero sin la fórmula.
¿Cómo? Metemos los datos dados por la fórmula en una variable, limpiamos la fórmula y pegamos los datos otra vez. El código quedaría algo así:
function onEdit(event){
var pestana = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('pestana')
   var celda_cambiada= event.source.getActiveRange().getA1Notation();
   if (celda_cambiada=="B4") {
pestana.getRange('A7:H').clearContent() // Hay que limpiar antes, ya que si no da error
       pestana.getRange('A7').setValue('=filter('Respuestas de formulario'!a:h;datos!B:B=B4)')
var valores = pestana.getRange('A7:H').getValues()
pestana.getRange('A7:H').setValues(valores)
                                              }
               }

Ahora vamos al proceso de conseguir cambiar en respuestas de formulario justo el mismo dato que cambiamos en donde hemos hecho el filtro. Necesitamos saber la fila donde está en respuestas de formulario el dato que queremos cambiar. Se me ocurre meter en respuestas de formulario una columna que gracias a la fórmula row() nos escriba el número de cada fila y que recuperemos este número dentro del filtro.
 Con el siguiente código ya tendríamos hecho todo, siempre que las columnas de una y otra pestaña (datos y respuestas de formulario) coincidan:
//Conseguimos lo que hemos cambiado
var dato_cambiado=event.source.getActiveRange().getValue()
// Pillamos la columna que se ha cambiado
 var Col_celda_cambiada=event.source.getActiveRange().getColumn()
//  Pillamos la fila donde se ha cambiado algo, que nos servirá para conseguir el valor de la fila donde está el mismo contenido en respuesta de formulario
 var Fila_celda_cambiada=event.source.getActiveRange().getRow()
 var fila_resp_formulario=pestana.getRange(Fila_celda_cambiada,8).getValue() //ya que el número de fila lo tenemos, en este caso, en la columna H ú 8

// con los estos datos ya podemos apuntar a respuestas de formulario y cambiar el contenido adecuado
var datos =SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Respuestas de formulario')
datos.getRange(fila_resp_formulario,Col_celda_cambiada).setValue(dato_cambiado)


jueves, 17 de mayo de 2018

Utilizar las fórmulas dentro del código

Quizás hay otra forma de hacerlo... La que voy a mostrar es rápida y sencilla.

Imaginaros que en un formulario tenemos un lista de tutores y que el profesor elije uno. Gracias al código queremos que le llegue por correo al tutor elegido la información que manda el profesor.

En la hoja de cálculo tendremos una lista con dos columnas. En la columna A los nombres de los tutores y en la columna B los correos correspondientes.
Dentro de la hoja de cálculo tenemos la fórmula VLOOKUP para, a partir de un tutor dado, nos dé el correo correspondiente. Por ejemplo: =VLOOKUP("Mateo Rodriguez";A:B;2;false). Así la fórmula busca a Mateo en la toda la columna A y nos devuelve lo que hay en la columna 2 (la B) a la derecha de Mateo (osea su correo).

Pero en código, que yo sepa no se pueden utilizar las fórmulas y, hasta ahora, para conseguir lo que hace la fórmula hemos utilizado un bucle y un condicional interno.

La solución que propongo son simplemente dos líneas de código:
var tutor ="Mateo Rodriguez"
var busco_correo = SpreadsheetApp.getRangeByName('datos').getRange('C1').setValue('=VLOOKUP("Mateo Rodriguez";A:B;2;false)')

var correo =SpreadsheetApp.getRangeByName('datos').getRange('C1').getValue()

En la primera variable escribo la fórmula en C1 por ejemplo.
En la segunda consiguo justamente el valor que hay en C1,  que la fórmula acaba de calcular.

Realmente la primera variable (busco_correo) quedaría así:
 var tutor = e.Values[1]
var busco_correo = SpreadsheetApp.getRangeByName('datos').getRange('C1').setValue('=VLOOKUP("'+tutor+'";A:B;2;false)')

Crear PDF horizontal

El código que vamos a mostrar aquí no ha sido creado por nosotros, sino que lo hemos encontrado en Internet. Objetivo: Publicar una pesta...