Oi Meu nome é romano e não sou o inventor das bicicletas. Gosto da estrutura Angular e do ecossistema em torno dela e desenvolvo meus aplicativos da Web com ela. Do meu ponto de vista, a principal vantagem do Angular a longo prazo se baseia na separação de código entre HTML e TypeScript, que foi descrita em detalhes por um de seus desenvolvedores
por que-angular-renders-components-with.html Essa vantagem tem uma desvantagem: a necessidade de compilação em princípio e a complexidade de compilar componentes dinamicamente em tempo de execução. Então, eu quero usar a familiar sintaxe de modelo Angular para dar ao usuário seus aplicativos a capacidade de personalizar modelos de cartas, gerar relatórios e planilhas para impressão ou definir o formato de exportação para arquivos xml! Para descobrir como fazer isso, seja bem-vindo ao gato!
Desafio
Em geral, o uso de modelos angulares pelo usuário pode ser assim: temos um determinado conjunto de dados:
const data = { project: 'MySuperProject', userName: 'Roman', role: 'admin', projectLink: 'https://example.com/my-super-projectproject' }
É necessário dar a oportunidade de personalizar o texto da carta, que será enviada ao usuário após a edição do projeto. Usando um modelo Angular, pode ficar assim:
<body> ! {{project}} <a href="{{projectLink}}">3D </a> <div *ngIf="role == 'admin'"> <a href="{{projectLink}}?mode=edit"></a> </div> </body>
Biblioteca de modelos Ng
Esse problema pode ser resolvido usando o compilador Angular no cliente (ou mesmo no lado do servidor), mas consome muito tempo e requer a arrastação de muitos megabytes de código para o cliente. Por que o compilador Angular é tão grande? Isso se deve ao fato de que ele suporta um mar de diversas funcionalidades para compor componentes e módulos e também contém seu próprio analisador de HTML! Então, decidi escrever um conversor angular de modelo mínimo que usará o analisador de HTML incorporado ao navegador. Foi possível fazer isso em apenas 200 com algumas linhas de código em algumas horas. Decidi compartilhar o resultado com o público no
GitHubUsar a biblioteca ng-template é bastante simples:
Instalar dependência do npm
npm install --save @quanterion/ng-template
ou através de fios
yarn add @quanterion/ng-template
E use-o da seguinte maneira:
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); }
Sintaxe suportada
- Expressões {{expression}} com capacidade de acessar variáveis e chamar funções
- Ng-templates
- Recipiente Ng
- Condições * ngIf + * ngIf as
- Ciclos * ngFor
- Estilos [style.xxx] = "valor" e [style.xxx.px] = "valor"
- Classes condicionais [class.xxx] = "value"
- Observáveis {{name $}} com assinatura automática de um valor (como um canal assíncrono)
Veja
os testes
ng-template.spec.ts para mais detalhes.
Usando Eval
Para avaliar expressões em modelos, eval é usado com preferência e cortesãs. O fato é que, nos modelos Angular, o acesso às variáveis é usado sem o prefixo JavaScript usual, isso. Portanto, você precisa chamar eval (), que possui todas as variáveis do objeto de dados no escopo. Não consegui gerar esse código para eval (), porque ver código
const data = { a: 1, b: () => 4 }; const expression = 'a+b()'; eval('a =1; b = ??;' + expression);
não permite a passagem de funções
A solução foi encontrada criando uma função cujos parâmetros possuem os nomes de campo do objeto com dados:
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);
PS: Espero que, no futuro, quando a API do novo compilador Ivy se estabilizar, seja possível gerar um conjunto de operadores para o Ivy e criar componentes completos em dinâmica!
Link para fonte