Secuencias de comandos del cliente

Las secuencias de comandos del cliente se ejecutan en los navegadores de las computadoras de los usuarios, en los entornos de ejecución de JavaScript. Son excelentes para controlar los eventos de IU y cambiar los elementos de DOM y las propiedades de widgets.

Las secuencias de comandos del cliente también pueden provocar interacciones con el servidor a través de las API de App Maker. Por ejemplo, las secuencias de comandos del cliente pueden obtener y modificar datos de una base de datos o invocar secuencias de comandos del servidor.

Operaciones asíncronas y funciones de devolución de llamada

Las secuencias de comandos del cliente se pueden ejecutar de forma asíncrona en App Maker para mantener la interfaz de usuario (IU) de la app responsiva. En algunas apps de navegador, cuando una operación necesita esperar a un recurso externo, la app completa espera. La IU también espera y no responde.

Con un código asíncrono, la IU y otras operaciones de la app permanecen responsivas, sin embargo, puede que tus secuencias de comandos no se ejecuten en el orden en que están escritas. Para ejecutar una secuencia de comandos después de que finalice una operación asíncrona, por ejemplo, un código que maneja los resultados de la operación, usa una función de devolución de llamada.

Las funciones de devolución de llamada son secuencias de comandos del cliente que se ejecutan cuando se completan las operaciones. Puedes especificar funciones que se ejecuten cuando la operación sea exitosa o un objeto que ejecute diferentes funciones en caso de éxito o falla.

Funciones de devolución de llamada solo para situaciones exitosas

Cuando incluyes una función de devolución de llamada solo para situaciones exitosas, esta función solo se ejecuta si la operación se realiza con éxito. Si la operación falla, no sucede nada. Por ejemplo, puedes crear un registro de forma asincrónica con createItem() y enviar una alerta al respecto:

widget.datasource.createItem(function (record) {
  alert('Record with ID ' + record.id + ' was created in the database.');
});

Funciones de devolución de llamada de éxito y fracaso

Esta es una extensión del caso anterior. Usa este método para recibir notificaciones de fallas y realizar informes de errores, limpiezas o reversiones.

widget.datasource.createItem({
  success: function (record) {
    alert('Record with ID ' + record.id + ' was created in the database.');  // executes if record was created
  },
  failure: function (error) {
    console.info("No new record for you!"); // executes if record wasn't created
  }
});

Sin función de devolución de llamada

Si omites la devolución de llamada o la pasas como un valor nulo, el código continuará sin esperar a que la operación finalice. Por ejemplo:

    widget.datasource.createItem();
    console.info("warning, record is probably not yet created!");

Solución de problemas

A continuación, se muestran algunas estrategias para solucionar los problemas de las secuencias de comandos del cliente y encontrar y corregir errores:

  • Encuentra errores de sintaxis en el editor de secuencias de comandos. El editor de secuencias de comandos de App Maker te advierte sobre los problemas de sintaxis de forma automática a medida que escribes. Busca las etiquetas de advertencia a la izquierda de los números de línea de tu secuencia de comandos. Las advertencias detectan errores comunes como paréntesis faltantes.

  • Encuentra errores de entorno de ejecución en la consola de JavaScript de tu navegador. Abre una instancia de vista previa o una versión implementada de tu app y abre la consola de JavaScript de tu navegador. En Chrome, abre la consola de JavaScript con la combinación de teclas Ctrl+Shift+j o Alt-Cmd-j. Algunas excepciones comunes de entorno de ejecución son las desreferencias null o las declaraciones throw sin detectar. Puedes agregar declaraciones debugger; a tu secuencia de comandos para detener la ejecución de la secuencia de comandos y, luego, identificar el área problemática (DevTools debe estar abierto para que las declaraciones debugger; hagan efecto). Para obtener más instrucciones de depuración, consulta Comienza con la depuración de JavaScript en Chrome DevTools.

  • Sigue la ejecución de tu secuencia de comandos con registros y alertas. Usa la función console.log() incorporada del navegador para enviar registros a la consola de JavaScript. De forma alternativa, puedes usar alert() para abrir un cuadro de alerta que interrumpa la ejecución de tu secuencia de comandos hasta que la descartes.

Ejemplos de secuencias de comandos del cliente

Usa secuencias de comandos en expresiones de vinculación

Puedes usar JavaScript para realizar cálculos en expresiones de vinculación. Por ejemplo, la siguiente expresión en la propiedad enabled de un botón lo inhabilita si el campo de Name está en blanco o si el campo de Age posee un valor menor que 18:

(@widget.parent.children.NameTextBox.value).length != 0 &&
@widget.parent.children.AgeTextBox.value >= 18

El analizador de App Maker primero resuelve las expresiones de vinculación, que comienzan con @, para encontrar el valor de Name y Age. Luego, sustituye esos valores por las expresiones y evalúa el resto del JavaScript.

Los paréntesis en la primera línea indican el final de la expresión de vinculación. Sin ellos, App Maker analizaría la propiedad length en busca de cambios, en lugar de la propiedad value.

Llama a una secuencia de comandos del servidor

Puedes llamar a las secuencias de comandos del servidor desde las secuencias de comandos del cliente con las API de App Maker. Llamar a las secuencias de comandos del servidor es una operación asíncrona, por lo que tienes que usar una devolución de llamada para procesar el resultado de la secuencia de comandos.

La siguiente secuencia de comandos del cliente llama a una secuencia de comandos del servidor para obtener el precio actual de las acciones de Google y, luego, muestra el resultado como un mensaje de alerta mediante una devolución de llamada.

Secuencia de comandos del cliente:

function getGoog() {
  google.script.run.withSuccessHandler(function(result) {
    var quote = result.trim().split("\n").pop().split(",").pop();
    alert(quote);
  }).getGoogleStockInfo();
}

Secuencia de comandos del servidor:

function getGoogleStockInfo() {
  var url = "https://www.google.com/finance/getprices?f=d,c&q=GOOG";
  var response = UrlFetchApp.fetch(url);
  return response.getContentText();
}

Carga dinámica de secuencias de comandos externas

Puedes cargar varias secuencias de comandos de terceros de forma síncrona mediante bibliotecas externas de JavaScript, sin embargo, algunas requieren un poco más de trabajo. Las bibliotecas que requieren un parámetro de devolución de llamada, como la biblioteca cliente de las API de Google, se deben cargar de manera dinámica con la adición de una secuencia de comandos Settings > General > onAppStart.

La siguiente secuencia de comandos carga la biblioteca de Google+:

// Suspends app loading until after the Google Client API loads.
loader.suspendLoad();
// Defines a callback function, for the client API. It must be global,
// so it's explicitly attached to the window object.
window.OnGapiClientLoad = function() {
  // Uses the Google Client API to load the Google+ library.
  gapi.client.load("plus", "v1", function() {
    // Continues loading the app once Google+ loads.
    loader.resumeLoad();
  });
};

var script = document.createElement("script");
script.setAttribute("type", "text/javascript");

// Specifies the name of the callback function in the "onload"
// parameter of the URL.
var url = "https://apis.google.com/js/client.js?onload=OnGapiClientLoad";
script.setAttribute("src", url);

document.getElementsByTagName("head")[0].appendChild(script);

Llama a las API de Google

Este último ejemplo es un poco más detallado y te dará una idea de cómo es una verdadera secuencia de comandos de App Maker. Se usa una API de JavaScript de Google.

La secuencia de comandos muestra un mapa de Google en una página y lo actualiza según los datos de entrada del usuario. La secuencia de comandos funciona con una página llamada Map que contiene los siguientes widgets:

  • Dos campos de texto, llamados Street y Zip
  • Una HtmlArea de 200x200 llamada MapDiv que tiene un evento onAttach que llama a loadMaps()
  • Un botón con un controlador onClick() que llama a updateMap()

Secuencia de comandos:

var map;
var geocoder;
var marker;

// Called by loadMaps() to set up widgets.
function createMap() {
  var div = app.pages.Map.descendants.MapDiv.getElement();
  map = new google.maps.Map(div, {
    center: new google.maps.LatLng(-34.397, 150.644),
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    zoom: 10,
  });
  geocoder = new google.maps.Geocoder();
  marker = new google.maps.Marker({map: map});
}

// Returns an address string from Street and Zip text fields.
function getAddress() {
  var page = app.pages.Map;
  var street = page.descendants.Street.value;
  var zip = page.descendants.Zip.value;
  return street + ", " + zip;
}

// Positions the map at the given location coordinates.
function showLocation(locations, status) {
  if (locations.length > 0) {
    var latLng = locations[0].geometry.location;
    map.panTo(latLng);
    marker.setPosition(latLng);
  }
}

// Sets up the Google Maps library.
function loadMaps() {
  google.load("maps", "3", {callback: createMap});
}

function updateMap() {
  geocoder.geocode({address: getAddress()}, showLocation);
}

Contenido destacado de la secuencia de comandos:

  • MapDiv usa su controlador onAttach() para configurar la API de Google Maps.
  • La secuencia de comandos usa getAddress() para acceder a los datos de entrada de los usuarios y extraer datos de los campos Street y Zip.