Construir su primera aplicación de Studio
Objetivo
Construir desde cero una aplicación que funcione: una tabla que contenga los registros, una pantalla que los muestre, una barra de herramientas que actúe sobre el que marque y un panel que vuelva a escribir un registro nuevo.
La primera vez lleva unos cuarenta minutos. Nada de esto es un juguete: cada paso es el que daría para una aplicación real, y lo que obtiene al final es, a grandes rasgos, el ejemplo Support desk.
studio-starter-app en samples/solutions es esta aplicación, ya dibujada. Impórtela desde
Soluciones → Importar, ábrala y pulse cosas. Volver aquí después de eso acorta cada uno de los
pasos siguientes.
Antes de empezar
- Ha iniciado sesión como creador.
- Hay un entorno y una solución seleccionados en los selectores de la parte superior de la página. Nada de lo que cree a continuación existe fuera de ellos.
- Conoce el prefijo del editor de su solución: las dos o tres letras que van delante de cada
nombre lógico. Esta página escribe
par; el suyo puede ser distinto.
1. Una tabla que contenga los registros
Una aplicación que no muestra nada es un dibujo. Cree primero la tabla.
Tablas → Nuevo, y rellene:
| Campo | Valor |
|---|---|
| Nombre para mostrar | Case |
| Nombre en plural | Cases |
| Nombre lógico | par_case (el prefijo se agrega automáticamente) |
| Campo principal | Summary |
Guarde y después agregue tres campos más en la pestaña Campos:
| Nombre para mostrar | Nombre lógico | Tipo |
|---|---|---|
| Priority | par_priority | Opción: nuevo conjunto de opciones par_case_priority, con las opciones Low, Normal, High |
| Urgent | par_urgent | Sí/No |
| Notes | par_notes | Texto multilínea |
Un registro creado sin tocar Urgent no tiene ningún valor para él, y ningún valor no es un
booleano. Así que una expresión como record.par_urgent ? "Yes" : "No" falla con Only booleans are
allowed in this expression precisamente en esos registros. Escriba (record.par_urgent ?? false)
allí donde lea un campo opcional, y el problema desaparece. Es la sorpresa más habitual en una
primera aplicación.
2. La aplicación
Aplicaciones de Studio → Nuevo:
| Campo | Valor |
|---|---|
| Nombre para mostrar | Support desk |
| Nombre lógico | par_support |
| Descripción | Una frase. Es lo que muestra el mosaico del iniciador bajo el nombre. |
| Icono | Pulse el selector y elija uno: LifeBuoy encaja con una aplicación de soporte |
| Mostrada en el Shell | activado |
Pulse Guardar y después Diseñar. Se abre el lienzo.
3. La pantalla, y qué es una pantalla
Dibuje un marco que ocupe el lienzo —unos 1200 × 760 es un tamaño de dibujo cómodo— y, con él seleccionado, abra la pestaña Pantalla del inspector de la derecha:
┌─ Inspector ───────────────────────┐
│ Graphic │ Screen │ Code │
├───────────────────────────────────┤
│ This object is … │
│ ┌─────────────────────────────┐ │
│ │ The screen ▾ │ │ ← choose this
│ └─────────────────────────────┘ │
│ │
│ Content that does not fit │
│ ┌─────────────────────────────┐ │
│ │ Show it — it spills out ▾ │ │
│ └─────────────────────────────┘ │
└───────────────────────────────────┘
Cambie el nombre del marco a Cases en el panel
Capas. Ese nombre es el nombre de la pantalla: es lo que pedirá después navigate("Cases").
El tamaño que dibujó no es el tamaño final. Todo lo que hay dentro está anclado a los bordes del marco, y el marco llena la ventana en la que se abra la aplicación, sea cual sea.
4. La memoria propia de la pantalla
Una pantalla recuerda cosas: en qué página de la lista está, qué se escribió en el cuadro de búsqueda, qué filas están marcadas. Esa memoria es el estado de la pantalla, y se declara una vez en el marco de la pantalla.
Con el marco de la pantalla seleccionado, en la pestaña Pantalla, agregue lo siguiente en Estado:
| Nombre | Empieza como |
|---|---|
cases | [] |
caseTotal | 0 |
page | 0 |
pageSize | 20 |
picked | "" |
pickedCount | 0 |
pickedId | "" |
form | { par_name: "", par_urgent: false, par_notes: "" } |
Declare la forma de form; no lo deje en {}. Un enlace que lee un miembro que un objeto no
tiene produce un error, y la primera evaluación de la pantalla se ejecuta antes de que nada haya
rellenado el formulario.
5. Rellenar la lista
Todavía en el marco de la pantalla, en la pestaña Pantalla, busque Controladores y ponga esto en Cargado:
loadRecords("par_case", "cases", {
top: getState("pageSize"),
skip: getState("page") * getState("pageSize"),
orderBy: "par_name",
countInto: "caseTotal"
});
Una línea de consulta es toda la paginación: top y skip son la página, y countInto devuelve
cuántas filas hay en total, algo que una página de veinte no puede decir y que un botón Siguiente
tiene que saber. Consulte Mostrar una lista página a página para el
resto.
Todavía no se ve nada. No hay nada dibujado en lo que mostrarlo.
6. Una fila, dibujada una vez
Este es el paso que sorprende a la gente, así que merece la pena decirlo claramente: usted dibuja una fila, y la plataforma dibuja una por registro.
-
Dibuje un marco dentro de la pantalla para la lista: todo el ancho del contenido y unos cientos de píxeles de alto. Llámelo
Rows. En la pestaña Pantalla establezca Este objeto es → Una lista y Contenido que no cabe → Desplazarse hasta él, y después En qué dirección se desplaza → Hacia abajo. Un cuadro dibujado para seis filas contiene cien en cuanto tiene detrás una tabla real. -
Dele diseño automático, vertical, en la pestaña Gráfico. Sin él, cada copia de la fila cae encima de la primera.
-
Dibuje un marco dentro de
Rows, de todo el ancho y 64 de alto. LlámeloCase rowy establezca Este objeto es → Un elemento de lista. -
Con
Case rowseleccionado, busque Repetir para cada en la pestaña Pantalla y escriba:state.cases -
Dibuje un objeto de texto dentro de la fila para el resumen. Selecciónelo y, en Enlaces, establezca Texto:
row.par_name
row es el registro de esta copia. Guarde y pulse Vista previa: una fila por caso, desde la
tabla, sin nada repetido a mano.
┌─ Rows ────────────────────────────────────────────────┐
│ ☐ 1 Sample case 1 Normal │ ← Case row, drawn once
│ ☐ 2 Sample case 2 High Urgent │
│ ☐ 3 Sample case 3 Low │
│ … │
└───────────────────────────────────────────────────────┘
7. La marca, y una sola idea de qué está elegido
Dibuje un marco pequeño al principio de la fila, de 20 × 20, y establezca Control → Casilla. Después:
-
Enlaces → Valor:
state.picked.includes(row.id) -
Controladores → Cambiado:
var ids = "";var count = 0;var firstId = "";var i = 0;for (i = 0; i < state.cases.length(); i = i + 1) {var id = state.cases[i].id;var on = state.picked.includes(id);if (id == row.id) { on = !on; }if (on) {ids = ids + id + "|";count = count + 1;if (count == 1) { firstId = id; }}}setState("picked", ids);setState("pickedCount", count);setState("pickedId", firstId);
El valor es una comparación, no un campo. Cada casilla vuelve a leer la única lista, así que vaciar la lista desmarca todas a la vez, cosa que un indicador por fila nunca podría hacer, porque nada sabría dónde estaban las demás filas.
8. Una barra de herramientas que se activa
Dibuje una barra encima de la lista —un marco, de todo el ancho y 56 de alto, Este objeto es → Una región— y ponga tres botones en ella. Para cada uno: dibuje un marco, establezca Control → Botón y dibuje dentro un objeto de texto para el rótulo.
Ponga un glifo en cada uno. Seleccione el botón y use el selector de iconos de la pestaña
Gráfico: Plus, Pencil, Trash2. Lo que llega es un trazado dibujado normal dentro del botón,
y el botón terminado dispone por sí mismo el glifo, el espacio y el rótulo.
| Botón | Enlaces → Habilitado | Controladores → Pulsado |
|---|---|---|
| Nuevo | (déjelo vacío) | setState("form", { par_name: "", par_urgent: false, par_notes: "" });openEndDrawer("New case"); |
| Editar | state.pickedCount == 1 | openStartDrawer("Edit case"); |
| Eliminar | state.pickedCount > 0 | showModal("Confirm delete"); |
Enlace Habilitado en lugar de escribir código para atenuar las cosas. Un enlace se vuelve a evaluar cada vez que cambia el estado, así que la barra se activa y se desactiva por sí sola.
Pinte el texto y el borde del botón Eliminar con el token color.error, no con un rojo que haya
elegido usted. Un token sigue el modo de color del lector; un valor hexadecimal es correcto para
quien lo dibujó y erróneo para todos aquellos cuyo tema es distinto.
9. El panel lateral, y qué es una tarjeta superpuesta
Una superposición no es una pantalla. Es un componente que usted marca como tarjeta, y un controlador decide dónde se abre.
- Dibuje el formulario en algún lugar alejado de la pantalla: un marco de unos 420 de ancho, con un título, los campos y dos botones. No importa en qué parte del lienzo esté; una tarjeta se compila en el origen, y solo se conserva su ancho.
- Seleccione el marco, pulse Crear componente y llámelo
New case. - En el panel del componente, marque Una tarjeta superpuesta.
┌─ Inspector · Component ───────────┐
│ ☑ An overlay card │
│ Show it with showModal("New │
│ case") … Its drawn width is │
│ the panel's width. │
│ │
│ ☐ It has to be answered │
│ Clicking outside, Escape and │
│ the close button all stop │
│ working while it is open. │
└──── ───────────────────────────────┘
Dentro de ella, para cada campo: dibuje un marco, establezca Control → Cuadro de texto (o Área
de texto para las notas) y enlace Valor a la ruta de estado que edita: state.form.par_name,
state.form.par_notes. Un control enlazado a una ruta de estado simple escribe de vuelta en ella,
así que no hay nada más que conectar.
Después, el Pulsado del botón Guardar:
if (getState("form").par_name == "") {
notifyError("A case needs a summary.");
} else {
createRecord("par_case", {
par_name: getState("form").par_name,
par_urgent: getState("form").par_urgent,
par_notes: getState("form").par_notes
});
notify("Case created.");
closeEndDrawer();
setState("page", 0);
loadRecords("par_case", "cases", { top: getState("pageSize"), skip: 0,
orderBy: "par_name", countInto: "caseTotal" });
}
Toda escritura termina volviendo a leer la lista. Nada se actualiza por sí solo: la pantalla muestra lo que contiene su estado, y el estado contiene lo que puso ahí la última consulta.
Una pregunta que hay que responder
Dibuje la confirmación de eliminación de la misma manera, marque Una tarjeta superpuesta y después
marque también Hay que responderla. Hacer clic fuera, pulsar Esc y el botón de cerrar dejan de
funcionar, así que dibuje su propia salida: un botón Cancelar que ejecute closeModal().
Deje esa segunda marca desactivada en todos los demás casos. Una superposición que alguien abrió por accidente debe cerrarse igual que se abrió; la única que debe negarse es aquella en la que hacer clic al lado no es una respuesta.
10. Guardar, y abrirla de verdad
Pulse Guardar. Aparecen advertencias en la parte superior si el compilador notó algo: un botón sin palabras, un marco de pantalla que falta, un enlace que no es una expresión pura. Nombran el objeto, así que corríjalas seleccionándolo.
Después salga del diseñador y abra la aplicación desde la lista de aplicaciones del Shell. La vista previa no es lo mismo: representa las mismas pantallas sin ningún entorno detrás, así que lo que no puede mostrarle son sus datos. Todo lo demás —los paneles laterales, las casillas, la barra de herramientas— se comporta igual.
Qué hacer a continuación
- Una segunda pantalla. Dibuje otro marco junto al primero, etiquételo como La pantalla y
póngale nombre. En cuanto hay dos, aparece un selector Se abre en en la barra de título.
navigate("Board")se mueve entre ellas. - Pestañas. Una tira de pestañas no es un control: es un campo de estado y un recuadro por valor.
Dibuje los recuadros en el mismo rectángulo, enlace el Se muestra de cada uno a
state.tab == "notes"y dé a los botones de pestaña un enlace Seleccionado con la misma comparación. Use Dibujar solo en este en la fila de una capa para llegar a un recuadro que está debajo de los demás. - Controles que usted no dibujó. El ejemplo
studio-component-libraryincluye una lista desplegable, una búsqueda y un interruptor. Marque Publica componentes en esa aplicación y aparecerán en su paleta; consulte Usar un componente en otra aplicación. - Un panel. El mismo lienzo dibuja uno: consulte Poner un panel en una pantalla dibujada.
Solución de problemas
| Lo que ve | Qué es |
|---|---|
| Only booleans are allowed in this expression | Un campo opcional leído como condición. Envuélvalo: (state.x.par_urgent ?? false). |
| El enlace de una fila se lee vacío | row solo existe dentro del elemento que lleva Repetir para cada y sus hijos. |
| Las filas se amontonan unas encima de otras | El cuadro que rodea la fila repetida necesita diseño automático. |
| El texto se sale por la parte inferior de un cuadro | Póngalo en un marco configurado con Desplazarse hasta él → Hacia abajo, y ancle las palabras a la parte superior. |
| Una lista desplegable cierra el panel desde el que se abrió | Corregido en 0.31. Actualice, o saque el selector del panel. |
| Guardar está deshabilitado | Nada ha cambiado desde el último guardado. |