Angular2: ¿deberían ser accesibles las variables privadas en la plantilla?

143

Si se declara una variable privateen una clase de componente, ¿debería poder acceder a ella en la plantilla de ese componente?

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>{{title}}</h2>
      <h2>Hello {{userName}}</h2> // I am getting this name
    </div>
  `,
})
export class App {
  public title = 'Angular 2';
  private userName = "Test Name"; //declared as private
}
3gwebtrain
fuente

Respuestas:

226

No, no deberías usar variables privadas en tus plantillas.

Si bien me gusta la respuesta de drewmoore y veo una lógica conceptual perfecta en ella, la implementación es incorrecta. Las plantillas no existen dentro de las clases de componentes, sino fuera de ellas. Echa un vistazo a este repositorio para la prueba.

La única razón por la que funciona es porque la privatepalabra clave de TypeScript realmente no hace que los miembros sean privados. La compilación Just-in-Time ocurre en un navegador en tiempo de ejecución y JS no tiene ningún concepto de miembros privados (¿todavía?). El crédito es para Sander Elias por ponerme en el camino correcto.

Con una ngccompilación anticipada, obtendrá errores si intenta acceder a miembros privados del componente desde la plantilla. Clone el repositorio de demostración, cambie MyComponentla visibilidad de los miembros a privada y obtendrá errores de compilación cuando se ejecute ngc. Aquí también hay una respuesta específica para la compilación anticipada.

Administrador Yaroslav
fuente
66
Este es el mejor comentario e IMO debe ser la respuesta aceptada. No es que pueda usar variables privadas una vez que se transpiló, sino que debería ... ¡Mantener el código limpio!
Sam Vloeberghs
2
¡Esta es la única respuesta válida! Codelyzer ahora le advierte cuando utiliza var privado en su plantilla.
maxime1992
77
Mi único problema con esto es cómo diferenciar entre los miembros expuestos públicamente, como @Inputs y Outputs, a los miembros que queremos exponer solo a nuestra plantilla y no al mundo exterior. Si está creando componentes reutilizables donde desea que los métodos / miembros sean accesibles para la plantilla pero no para otros componentes. Creo que la respuesta original es correcta. Las plantillas son parte del componente.
Ashg
1
Estoy de acuerdo con @Ashg, y no solo con las entradas y salidas de wrt. ¿Qué pasa cuando quiero comunicarme entre componentes, por ejemplo, inyectando un componente padre en su hijo? El componente hijo puede ver todo lo que el padre está exponiendo a su plantilla, en lugar de solo los métodos que el padre quiere exponer al mundo exterior. Dentro de las limitaciones de Angular, esta respuesta sigue siendo la correcta, pero no creo que este diseño haya sido bien pensado.
Dan King
Esta es una buena respuesta ya que aborda las limitaciones dentro de la compilación de AoT de Angular y cómo sortearlas. Sin embargo, en mi opinión, la pregunta era conceptual (intencionalmente o no). Conceptualmente, las plantillas son parte de las definiciones de clase. Las plantillas no se extienden ni heredan clases y no acceden a objetos instanciados externamente ... es al revés. Las plantillas se definen dentro de la propia clase, por lo que, conceptualmente, son parte de la clase y conceptualmente deberían tener acceso a miembros privados.
A-Diddy
85

Editar: esta respuesta ahora es incorrecta. No había una guía oficial sobre el tema cuando lo publiqué, pero como se explica en la respuesta (excelente y correcta) de @ Yaroslov, este ya no es el caso: Codelizer ahora advierte y la compilación de AoT fallará en las referencias a variables privadas en plantillas de componentes . Dicho esto, a nivel conceptual, todo aquí sigue siendo válido, por lo que dejaré esta respuesta, ya que parece haber sido útil.


Sí, esto se espera.

Tenga en cuenta que privatey otros modificadores de acceso son construcciones mecanografiadas, mientras que Componente / controlador / plantilla son construcciones angulares de las que no sabe nada. Los modificadores de acceso controlan la visibilidad entre clases: hacer un campo privateevita que otras clases tengan acceso a él, pero las plantillas y los controladores son cosas que existen dentro de las clases.

Eso no es técnicamente cierto, pero (en lugar de comprender cómo las clases se relacionan con los decoradores y sus metadatos), podría ser útil pensar de esta manera, porque lo importante (en mi humilde opinión) es dejar de pensar en la plantilla y el controlador como algo separado entidades para pensar en ellas como partes unificadas de la construcción Componente: este es uno de los principales aspectos del modelo mental ng2.

Pensando en ello de esa manera, obviamente esperamos que las privatevariables en una clase de componente sean visibles en su plantilla, por la misma razón que esperamos que sean visibles en los privatemétodos de esa clase.

dibujó más
fuente
3
Primero, pensé igual que tú dibujaste más. Pero actualicé tslint a 4.02 y codelyzer a 2.0.0-beta.1 y tuve errores que decían que no puedo usar private cuando accedo a las variables a la vista. Entonces, la respuesta de @ Yaroslav parece más apropiada.
maxime1992
8
Estoy de acuerdo en que no tiene sentido que un modelo de componentes no pueda ver sus variables privadas, probablemente deberían mezclarse en una misma clase durante la compilación, es decir, debe exponer rasgos, objetos y funciones específicos de los componentes a todos los demás componentes para que pueda usarlos en su plantilla, sin mencionar ajustes externos o llamadas a ellos, podrían causar un comportamiento inesperado potencial en el componente terminado
Felype
1
@drewmoore, hola, he estado codificando angular solo durante algunos meses. Me enfrenté a este problema. ¿Hay algún debate adicional sobre esto? Como no encuentro nada específico sobre qué patrón seguir. OMI, ya que vale lo que es, parece violar la separación del código.
Edgar
2
@drewmoore, debo decir que estoy totalmente de acuerdo con tu lógica de respuesta. y me temo que el equipo de Angular se ha equivocado un poco. en el modo AOT, no permiten miembros privados, mientras que en los documentos afirman lo contrario, lo que en el caso de los miembros privados fortalece absolutamente su punto y solo agrega más caos a este tema. De Docs: "Angular trata la plantilla de un componente como perteneciente al componente. El componente y su plantilla confían entre sí implícitamente. Por lo tanto, la propia plantilla del componente puede unirse a cualquier propiedad de ese componente, con o sin el decorador de entrada * @ *. "
Orel Eraki
@drewmoore, Enlace para los documentos: angular.io/guide/attribute-directives#appendix-why-add-input (Sé que se centra principalmente en el decorador de entrada, pero mucho de lo que están hablando no solo está relacionado con it)
Orel Eraki
16

Aunque el ejemplo de código indica que la pregunta es sobre TypeScript, no tiene el etiqueta. Angular2 también está disponible para Dart y esta es una diferencia notable para Dart.

En Dart, la plantilla no puede hacer referencia a variables privadas de la clase de componente, porque Dart, en contraste con TypeScript, impide efectivamente el acceso de miembros privados desde el exterior.

Todavía respaldo la sugerencia de @drewmoores de pensar en el componente y su plantilla como una sola unidad.

Actualización (TS) Parece que con el acceso de compilación fuera de línea a las propiedades privadas será más limitado en Angular2 TS también https://github.com/angular/angular/issues/11422

Günter Zöchbauer
fuente
2
¿Es posible tener el compilador de mecanografiado para limitar el acceso de las variables privadas a la vista?
Matthew Harwood
No lo sé. Supongo que no.
Günter Zöchbauer
2
Creo que tenerlos en privado podría afectar lo comprobable que es el componente. Por ejemplo, si creo un componente en el contexto de una prueba, no podría llamar a esos métodos privados desde mi prueba para confirmar que la interacción plantilla / clase está funcionando. Todavía no he probado esto, así que perdóname si esto es obvio :)
Sam Storie
En Dart no puedes acceder a miembros privados en las pruebas. Se discute mucho (independientemente del idioma) si esto debería ser compatible y si la API privada debería probarse. Probar la API pública debería poder llegar a cada ruta de código. Creo que esto es razonable en general. En Dart, privado es por biblioteca (que puede constar de varios archivos), lo que hace que la API pública sea bastante amplia, en mi humilde opinión, demasiado amplia para la prueba unitaria.
Günter Zöchbauer
3

Las variables privadas se pueden usar dentro de la plantilla del componente. Consulte la hoja de referencia angular2 para obtener una guía: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Puede encontrar una explicación más detallada sobre los miembros públicos / privados de las clases en mecanografiado aquí: https://www.typescriptlang.org/docs/handbook/classes.html .

Todos los miembros por defecto son públicos. Se puede acceder a los miembros públicos desde fuera de la clase de componente junto con la instancia de clase. Pero solo se puede acceder a los miembros privados dentro de las funciones de miembro de la clase.

anusreemn
fuente
Miré el primer enlace ( angular.io/guide/component-interaction#!#parent-to-child-setter ) y no veo en ningún lado que sugiera que usar variables privadas en plantillas está bien. Por el contrario, usan getters y setters para acceder a las variables privadas desde la plantilla.
Sebastien Chartier
3

Una solución alternativa podría ser usar variables privadas en el archivo ts y usar getters.

private _userName = "Test Name";
get userName() {
  return this._userName;
}

Este es un buen enfoque porque el archivo ts y el html siguen siendo independientes. Incluso si cambia el nombre de la variable _userName en el archivo ts, no tiene que hacer ningún cambio en el archivo de plantilla.

Franklin Pious
fuente
Creo que si cambia _userName a _clientName, por ejemplo, para mantener la coherencia, debe cambiar getter para obtener clientName ... para que no haya ninguna victoria
LeagueOfJava
Es una mala práctica subrayar el usuario para variables privadas.
Florian Leitgeb
1
@FlorianLeitgeb ¿Por qué lo hacen los documentos oficiales de Angular ? private _name = '';
ruffin
Entonces este fragmento de código no se revisó correctamente. Siguen una convención de estilo, que se declara en la guía de estilo aquí . Y también en la sección Clases de mecanografiado en su página aquí no se usa el guión bajo.
Florian Leitgeb
1
@FlorianLeitgeb Entonces, ¿cuál sería la solución propuesta para la intercepción de los métodos de establecimiento como se muestra en el enlace publicado por ruffin? es decir, ¿cómo se llama el campo de respaldo privado de su setter?
El Ronnoco
1

La respuesta corta es no, no debería poder acceder a miembros privados desde la plantilla porque está técnicamente separada del archivo TS.

Aplicadores de Ivens
fuente
0

En tsconfig.app.json, si proporciona la opción 'fullTemplateTypeCheck' en las opciones del compilador, puede ver todas las referencias no válidas en los archivos html de su proyecto en el momento de la construcción del proyecto.

"angularCompilerOptions": {
"enableIvy": true,
"fullTemplateTypeCheck": true

}

Khushbu Suryavanshi
fuente