Hola Mi nombre es romano y no soy el inventor de las bicicletas. Me gusta el marco angular y el ecosistema que lo rodea, y desarrollo mis aplicaciones web con él. Desde mi punto de vista, la principal ventaja de Angular a largo plazo se basa en la separación de código entre HTML y TypeScript, que fue descrito en detalle por uno de sus desarrolladores
why-angular-renders-components-with.html Esta ventaja tiene una desventaja: la necesidad de compilación en principio y la complejidad de compilar dinámicamente componentes en tiempo de ejecución. ¡Y por eso quiero usar la sintaxis de plantilla Angular familiar para dar al usuario sus aplicaciones la capacidad de personalizar plantillas de cartas, generar informes y hojas de cálculo para imprimir, o establecer el formato de exportación para archivos xml! Para saber cómo hacer esto, ¡bienvenido a cat!
Desafío
En general, el uso de plantillas angulares por parte del usuario puede verse así: tenemos un cierto conjunto de datos:
const data = { project: 'MySuperProject', userName: 'Roman', role: 'admin', projectLink: 'https://example.com/my-super-projectproject' }
Es necesario dar la oportunidad de configurar el texto de la carta, que se enviará al usuario después de editar el proyecto. Usando una plantilla angular, podría verse así:
<body> ! {{project}} <a href="{{projectLink}}">3D </a> <div *ngIf="role == 'admin'"> <a href="{{projectLink}}?mode=edit"></a> </div> </body>
Biblioteca de plantillas ng
Este problema se puede resolver utilizando el compilador Angular en el cliente (o incluso en el lado del servidor), pero lleva mucho tiempo y requerirá arrastrar muchos megabytes de código al cliente. ¿Por qué es tan grande el compilador angular? ¡Esto se debe al hecho de que admite un mar de diversas funciones para componer componentes y módulos, y también contiene su propio analizador HTML! Así que decidí escribir un convertidor de plantilla angular mínimo que utilizará el analizador HTML integrado en el navegador. Fue posible hacer esto en solo 200 con unas pocas líneas de código en un par de horas. Decidí compartir el resultado con el público en
GitHubUsar la biblioteca ng-template es bastante simple:
Instalar dependencia de npm
npm install --save @quanterion/ng-template
o a través de hilo
yarn add @quanterion/ng-template
Y úsalo de la siguiente manera:
import { compileTemplate, htmlToElement } from '@quanterion/ng-template'; async test() { let data = { name: 'Roman' }; let element = htmlToElement(`<div>{{name}}</div>`); await compileTemplate(element, data); alert(element.outerHTML); }
Sintaxis soportada
- Expresiones {{expresión}} con la capacidad de acceder a variables y funciones de llamada
- Ng-templates
- Contenedor ng
- Condiciones * ngIf + * ngIf as
- Ciclos * ng Para
- Styles [style.xxx] = "value" y [style.xxx.px] = "value"
- Clases condicionales [class.xxx] = "valor"
- Observables {{name $}} con suscripción automática a un valor (como canalización asíncrona)
Vea
las pruebas
ng-template.spec.ts para más detalles.
Usando Eval
Para evaluar expresiones en plantillas, eval se usa con preferencia y cortesanas. El hecho es que en las plantillas angulares, el acceso a las variables se usa sin el prefijo JavaScript habitual. Por lo tanto, debe llamar a eval (), que tiene todas las variables del objeto de datos en su alcance. No logré generar dicho código para eval (), porque ver código
const data = { a: 1, b: () => 4 }; const expression = 'a+b()'; eval('a =1; b = ??;' + expression);
no permite pasar funciones
La solución se encontró creando una función cuyos parámetros tienen los nombres de campo del objeto con datos:
const data = { a: 1, b: () => 4 }; let entries = [] for (let property in data ) { entries.push([property, data[property]]) } const params = entries.map(e => e[0]); const fun = new Function('code', ...params, `return eval(code)`); const args = entries.map(e => e[1]); const expression = 'a+b()'; const result = fun.call(undefined, expression , ...args);
PD: ¡Espero que en el futuro, cuando la API del nuevo compilador Ivy se estabilice, sea posible generar un conjunto de operadores para Ivy y crear componentes completos en dinámica!
Enlace a la fuente