Angular2 - les variables privées doivent-elles être accessibles dans le modèle?


143

Si une variable est déclarée privatesur une classe de composant, dois-je pouvoir y accéder dans le modèle de ce composant?

@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
}

Réponses:


226

Non, vous ne devriez pas utiliser de variables privées dans vos modèles.

Bien que j'aime la réponse de Drewmoore et que j'y vois une logique conceptuelle parfaite, la mise en œuvre est erronée. Les modèles n'existent pas dans les classes de composants, mais en dehors d'elles. Jetez un oeil à ce repo pour la preuve.

La seule raison pour laquelle cela fonctionne est que le privatemot - clé de TypeScript ne rend pas vraiment le membre privé. La compilation juste à temps se produit dans un navigateur au moment de l'exécution et JS n'a pas (encore?) De concept de membres privés. Le mérite revient à Sander Elias de m'avoir mis sur la bonne voie.

Avec ngcet la compilation Ahead-of-Time, vous obtiendrez des erreurs si vous essayez d'accéder aux membres privés du composant à partir du modèle. Clonez le dépôt de démonstration, changez MyComponentla visibilité des membres en privé et vous obtiendrez des erreurs de compilation lors de l'exécution ngc. Voici également la réponse spécifique pour la compilation Ahead-of-Time.


6
c'est le meilleur commentaire et imo devrait être la réponse acceptée. Ce n'est pas que vous puissiez utiliser des variables privées une fois transpilées, que vous devriez. Gardez le code propre!
Sam Vloeberghs

2
C'est la seule réponse valable! Codelyzer vous avertit désormais lorsque vous utilisez une variable privée dans votre modèle.
maxime1992

7
Mon seul problème avec cela est de savoir comment différencier les membres réels exposés publiquement tels que @Inputs et Outputs aux membres que nous voulons exposer uniquement à notre modèle et non au monde extérieur. Si vous créez des composants réutilisables où vous souhaitez que les méthodes / membres soient accessibles au modèle mais pas aux autres composants. Je pense que la réponse initiale est correcte. Les modèles font partie du composant.
Ashg

1
Je suis d'accord avec @Ashg - et pas seulement avec les entrées et les sorties. Et quand je veux communiquer entre des composants, par exemple en injectant un composant parent dans son enfant. Le composant enfant peut alors voir tout ce que le parent expose à son modèle, au lieu de simplement les méthodes que le parent souhaite exposer au monde extérieur. Dans les limites d'Angular, cette réponse reste la bonne, mais je ne pense pas que cette conception ait été bien pensée.
Dan King du

C'est une bonne réponse car elle aborde les limitations de la compilation AoT d'Angular et comment les contourner. Cependant, l'OMI la question était conceptuelle (intentionnellement ou non). Conceptuellement, les modèles font partie des définitions de classe. Les modèles n'étendent ni n'héritent des classes et n'accèdent pas aux objets instanciés de manière externe ... c'est l'inverse. Les modèles sont définis dans la classe elle-même, donc, conceptuellement, ils font partie de la classe et devraient avoir accès aux membres privés.
A-Diddy

85

Edit: Cette réponse est maintenant incorrecte. Il n'y avait pas d'orientation officielle sur le sujet lorsque je l'ai posté, mais comme expliqué dans la réponse de @ Yaroslov (excellente et correcte), ce n'est plus le cas: Codelizer avertit maintenant et la compilation AoT échouera sur les références aux variables privées dans les modèles de composants . Cela dit, sur le plan conceptuel, tout ici reste valable, je vais donc laisser cette réponse car elle semble avoir été utile.


Oui, c'est prévu.

Gardez à l'esprit que les privateautres modificateurs d'accès sont des constructions Typescript, alors que Component / controller / template sont des constructions angulaires dont Typescript ne sait rien. Les modificateurs d'accès contrôlent la visibilité entre les classes: créer un champ privateempêche les autres classes d'y avoir accès, mais les modèles et les contrôleurs sont des éléments qui existent dans les classes.

Ce n'est pas techniquement vrai, mais (au lieu de comprendre comment les classes se rapportent aux décorateurs et à leurs métadonnées), il pourrait être utile de penser à cela de cette façon, car l'important (IMHO) est de ne plus penser au modèle et au contrôleur comme séparés. les entités en les considérant comme des parties unifiées de la construction Component - c'est l'un des aspects majeurs du modèle mental ng2.

En y réfléchissant de cette façon, nous nous attendons évidemment à ce que les privatevariables d'une classe de composant soient visibles dans son modèle, pour la même raison nous nous attendons à ce qu'elles soient visibles dans les privateméthodes de cette classe.


3
D'abord, j'ai pensé comme vous avez dessiné. Mais j'ai mis à niveau tslint vers 4.02 et codelyzer vers 2.0.0-beta.1 et j'ai eu des erreurs disant que je ne peux pas utiliser private lors de l'accès aux variables en vue. La réponse de @ Yaroslav semble donc plus appropriée.
maxime1992

8
Je conviens qu'il n'a pas de sens pour un modèle de composant de ne pas pouvoir voir ses variables privées, elles devraient probablement être écrasées dans une même classe lors de la compilation, je veux dire, vous devez exposer des caractéristiques, des objets et des fonctions spécifiques au composant à tous les autres composants afin que vous puissiez les utiliser dans votre modèle, sans parler des ajustements externes ou des appels à ceux-ci pourraient provoquer un comportement inattendu potentiel sur le composant fini
Felype

1
@drewmoore, bonjour je ne codifie angular que depuis quelques mois. J'ai été confronté à ce problème. Y a-t-il d'autres débats à ce sujet? Comme je ne trouve rien de précis sur le schéma à suivre. imo, comme cela vaut ce que c'est, il semble violer la séparation du code.
Edgar

2
@drewmoore, je dois dire que je suis totalement d'accord avec votre logique Anser. et j'ai peur que l'équipe Angular ait un peu gâché. en mode AOT, ils n'autorisent pas les membres privés, alors que sur les documents qu'ils prétendent le contraire, ce qui dans le cas des membres privés renforce absolument votre point de vue et ne fait qu'ajouter plus de chaos à ce sujet. From Docs: "Angular traite le modèle d'un composant comme appartenant au composant. Le composant et son modèle se font confiance implicitement. Par conséquent, le propre modèle du composant peut être lié à n'importe quelle propriété de ce composant, avec ou sans le décorateur d'entrée * @ *. "
Orel Eraki

@drewmoore, Lien pour les documents: angular.io/guide/attribute-directives#appendix-why-add-input (je sais que c'est principalement axé sur le décorateur d'entrée, mais beaucoup de ce dont ils parlent ne sont pas seulement liés à it)
Orel Eraki

16

Même si l'exemple de code indique que la question concerne TypeScript, il n'a pas le marque. Angular2 est également disponible pour Dart et c'est une différence notable avec Dart.

Dans Dart, le modèle ne peut pas référencer les variables privées de la classe de composant, car Dart contrairement à TypeScript empêche effectivement l'accès des membres privés de l'extérieur.

Je soutiens toujours la suggestion de @drewmoores de penser au composant et à son modèle comme une seule unité.

Mise à jour (TS) Il semble qu'avec la compilation hors ligne, l'accès aux propriétés privées deviendra plus limité dans Angular2 TS également https://github.com/angular/angular/issues/11422


2
Est-il possible d'avoir un compilateur Typescript pour limiter l'accès des variables privées à la vue?
Matthew Harwood

Je ne sais pas. Je suppose que non.
Günter Zöchbauer

2
Je pense que les avoir privés pourrait avoir un impact sur le degré de testabilité du composant. Par exemple, si je crée un composant dans le contexte d'un test, je ne pourrais pas appeler ces méthodes privées à partir de mon test pour confirmer que l'interaction modèle / classe fonctionne. Je n'ai pas encore essayé cela, alors pardonnez-moi si cela est évident :)
Sam Storie

Dans Dart, vous ne pouvez pas accéder aux membres privés dans les tests. Il y a beaucoup de discussions (indépendamment du langage) pour savoir si cela doit être pris en charge et si l'API privée doit être testée du tout. Le test de l'API publique doit pouvoir atteindre chaque chemin de code. Je pense que c'est raisonnable en général. Dans Dart, le privé est par bibliothèque (qui peut se composer de plusieurs fichiers), ce qui rend l'API publique assez large - IMHO trop large pour le test unitaire.
Günter Zöchbauer

3

Les variables privées peuvent être utilisées dans le modèle du composant. Voir la feuille de triche angular2 pour le guide: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Une explication plus détaillée sur les membres publics / privés des classes en typographie peut être trouvée ici: https://www.typescriptlang.org/docs/handbook/classes.html .

Tous les membres par défaut sont publics. Les membres publics sont accessibles depuis l'extérieur de la classe de composant avec l'instance de classe. Mais les membres privés ne sont accessibles que dans les fonctions des membres de la classe.


J'ai regardé le premier lien ( angular.io/guide/component-interaction#!#parent-to-child-setter ) et je ne vois nulle part cela suggère que l'utilisation de variables privées dans les modèles est correcte. Au contraire, ils utilisent des getters et des setters pour accéder aux variables privées à partir du modèle.
Sebastien Chartier le

3

Une solution de contournement pourrait être l'utilisation de variables privées dans le fichier ts et l'utilisation de getters.

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

C'est une bonne approche car le fichier ts et le html restent indépendants. Même si vous modifiez le nom de la variable _userName dans le fichier ts, vous ne devez apporter aucune modification au fichier modèle.


Je pense que si vous changez _userName en _clientName, par exemple, pour la cohérence, vous devez changer getter pour obtenir clientName ... donc il n'y a pas de victoire
LeagueOfJava

Il est déconseillé d'utiliser le trait de soulignement des variables privées.
Florian Leitgeb

1
@FlorianLeitgeb Quelle est la raison pour laquelle les documents officiels Angular le font ? private _name = '';
ruffin

Ensuite, cet extrait de code n'a pas été examiné correctement. Ils suivent une convention de style, qui est déclarée dans le guide de style ici . Et aussi dans la section classes Typescript sur leur page, ici n'utilise pas le trait de soulignement.
Florian Leitgeb

1
@FlorianLeitgeb Alors, quelle serait la solution proposée à l'interception des méthodes setter comme indiqué dans le lien posté par ruffin? ie Comment appelez-vous le champ de sauvegarde privé de votre passeur?
El Ronnoco le

1

La réponse courte est non, vous ne devriez pas pouvoir accéder aux membres privés du modèle car il est techniquement séparé du fichier TS.


0

Dans tsconfig.app.json, si vous fournissez l'option 'fullTemplateTypeCheck' dans les options du compilateur, vous pouvez voir toutes les références non valides dans les fichiers html de votre projet au moment de la construction du projet.

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

}

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.