En este artículo hablaremos sobre como creamos identificadores dinámicos (generar el valor según alguna especificación) en los componentes y su reflejo en el DOM tanto en modo debug (apareciendo con el prefijo ng-reflect) como en producción (desaparecen) y cómo solucionarlo (apareciendo el atributo “id”).
El motivo de su uso es para identificar un elemento y así poder poner el foco, manipular el elemento, o incluso para ser encontrado por los tests End-To-End (E2E).
Identificadores
Por identificadores nos referimos al atributo “id” de un elemento del DOM. Siempre interesa que este identificador sea único en todo el documento aunque es tan flexible que pueden existir varios y no hay queja aparente. Este identificador ha de tener como mínimo un carácter sin espacios.
Sintaxis:
<elemento id="id" />
Por identificadores dinámicos serán aquellos valores que se vayan a generar en función de alguna casuística concreta, sea de forma aleatoria, concatenaciones, u otra regla de aplicación.
Resultado esperado
Vamos a poner el ejemplo en nuestro artículo de un componente (“component-outer”) que a su vez contiene otro componente (“component-inner”) y que el resultado final sea de la siguiente forma:
<component-outer id="componentOuter">
<component-inner id="componentOuter_componentInner"></component-inner>
</component-outer>
Caso 1
La primera propuesta sería una concatenación del id del componente padre con otra cadena de caracteres. Quedando el componente “component-outer” de la siguiente forma:
Vista de component-outer (html):
<component-inner id="{{id}}_componentInner"></component-inner>
Código de component-outer (ts):
private _id: string = null;
public get id(): string {
return this._id;
}
@Input()
public set id(value: string) {
this._id = value;
}
Código de component-inner (ts):
private _id: string = null;
public get id(): string {
return this._id;
}
@Input()
public set id(value: string) {
this._id = value;
}
Si ejecutamos este código en modo debug encontraremos el siguiente código resultante:
<component-outer ng-reflect-id="componentOuter">
<component-inner ng-reflect-id="componentOuter_componentInner"></component-inner>
</component-outer>
Vemos que ha generado correctamente el valor del identificador pero por contra el nombre del atributo id tiene un prefijo “ng-reflect-” y esto no es lo deseado.
Si ejecutamos en modo producción “enableProdMode()” el resultado es que desaparecen los identificadores (y su valor), resultando de la siguiente manera:
<component-super>
<component-inner></component-inner>
</component-super>
Caso 2
La segunda propuesta sería generar el identificador en el código typescript del component-outer y darle el resultado a component-inner de la siguiente manera:
Vista de component-outer (html):
<component-inner [id]="resultId"></component-inner>
Código de component-outer (ts):
private _id: string = null;
public get id(): string {
return this._id;
}
@Input()
public set id(value: string) {
this._id = value;
}
public get resultId(): string {
return `${this._id}_componentInner`;
}
Código de component-inner (ts):
private _id: string = null;
public get id(): string {
return this._id;
}
@Input()
public set id(value: string) {
this._id = value;
}
El resultado final tampoco es satisfactorio.
Caso 3
La tercera y última propuesta es añadir al component-inner el siguiente atributo:
[attr.id]="resultId"
Vista de component-outer (html):
<component-inner [attr.id]="resultId" [id]="resultId"></component-inner>
El resto del código sería igual al del Caso 2.
En modo debug se obtiene el siguiente código:
<component-outer id="componentOuter" ng-reflect-id="componentOuter">
<component-inner id="componentOuter_componentInner" ng-reflect-id="componentOuter_componentInner"></component-inner>
</component-outer>
En modo producción:
<component-outer id="componentOuter">
<component-inner id="componentOuter_componentInner"></component-inner>
</component-outer>
De esta forma sí que se obtiene el atributo «id» tanto en debug como producción.
Puedes descargar el código en GitHub