Angular2 - sollten private Variablen in der Vorlage zugänglich sein?


143

Wenn eine Variable für privateeine Komponentenklasse deklariert ist , sollte ich in der Vorlage dieser Komponente darauf zugreifen können?

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

Antworten:


226

Nein, Sie sollten keine privaten Variablen in Ihren Vorlagen verwenden.

Während ich die Antwort des Drawmoore mag und darin eine perfekte konzeptionelle Logik sehe, ist die Implementierung falsch. Vorlagen existieren nicht innerhalb von Komponentenklassen, sondern außerhalb von ihnen. Schauen Sie sich dieses Repo für den Beweis an.

Der einzige Grund, warum es funktioniert, ist, dass das privateSchlüsselwort von TypeScript das Mitglied nicht wirklich privat macht. Die Just-in-Time-Kompilierung erfolgt zur Laufzeit in einem Browser, und JS hat (noch?) Kein Konzept für private Mitglieder. Dank geht an Sander Elias , der mich auf den richtigen Weg gebracht hat.

Mit ngcund Ahead-of-Time-Kompilierung werden Fehler angezeigt, wenn Sie versuchen, über eine Vorlage auf private Mitglieder der Komponente zuzugreifen. Klonen Sie das Demonstrations-Repo, ändern Sie MyComponentdie Sichtbarkeit der Mitglieder in "Privat", und beim Ausführen werden Kompilierungsfehler angezeigt ngc. Hier finden Sie auch eine Antwort speziell für die Ahead-of-Time-Kompilierung.


6
Dies ist der beste Kommentar und imo sollte die akzeptierte Antwort sein. Es ist nicht so, dass Sie private Variablen verwenden können, wenn sie einmal transpiliert wurden, das sollten Sie. Halten Sie den Code sauber!
Sam Vloeberghs

2
Dies ist die einzige gültige Antwort! Codelyzer warnt Sie jetzt, wenn Sie private var in Ihrer Vorlage verwenden.
Maxime1992

7
Mein einziges Problem dabei ist, wie Sie zwischen tatsächlich öffentlich zugänglichen Mitgliedern wie @Inputs und Outputs für Mitglieder unterscheiden, die wir nur unserer Vorlage und nicht der Außenwelt zugänglich machen möchten. Wenn Sie wiederverwendbare Komponenten erstellen, bei denen Methoden / Mitglieder für die Vorlage zugänglich sein sollen, nicht jedoch für andere Komponenten. Ich denke, die ursprüngliche Antwort ist richtig. Vorlagen sind Teil der Komponente.
Ashg

1
Ich stimme @Ashg zu - und nicht nur für Ein- und Ausgänge. Was ist, wenn ich zwischen Komponenten kommunizieren möchte , z. B. indem ich eine übergeordnete Komponente in ihre untergeordnete Komponente einfüge ? Die untergeordnete Komponente kann dann alles sehen, was das übergeordnete Element seiner Vorlage zur Verfügung stellt, anstatt nur die Methoden, die das übergeordnete Element der Außenwelt zur Verfügung stellen möchte. Innerhalb der Einschränkungen von Angular bleibt diese Antwort die richtige, aber ich denke nicht, dass dieses Design gut durchdacht wurde.
Dan King

Dies ist eine gute Antwort, da hier die Einschränkungen in der AoT-Kompilierung von Angular und deren Umgehung behandelt werden. IMO war die Frage jedoch konzeptionell (absichtlich oder nicht). Konzeptionell sind Vorlagen Teil von Klassendefinitionen. Vorlagen erweitern oder erben keine Klassen und greifen nicht extern auf instanziierte Objekte zu ... es ist umgekehrt. Vorlagen werden innerhalb der Klasse selbst definiert, sodass sie konzeptionell Teil der Klasse sind und konzeptionell Zugriff auf private Mitglieder haben sollten.
A-Diddy

85

Bearbeiten: Diese Antwort ist jetzt falsch. Als ich es veröffentlichte, gab es keine offizielle Anleitung zu diesem Thema, aber wie in der Antwort von @ Yaroslov (ausgezeichnet und korrekt) erläutert, ist dies nicht mehr der Fall: Codelizer warnt jetzt und die AoT-Kompilierung schlägt bei Verweisen auf private Variablen in Komponentenvorlagen fehl . Auf konzeptioneller Ebene bleibt hier jedoch alles gültig, daher lasse ich diese Antwort offen, da sie hilfreich zu sein scheint.


Ja, das wird erwartet.

Beachten Sie, dass privateund andere Zugriffsmodifikatoren Typescript-Konstrukte sind, während Component / Controller / Template eckige Konstrukte sind, von denen Typescript nichts weiß. Zugriffsmodifikatoren steuern die Sichtbarkeit zwischen Klassen: Durch das Erstellen eines Felds wird privateverhindert, dass andere Klassen darauf zugreifen können. Vorlagen und Controller sind jedoch in Klassen vorhanden.

Das ist technisch nicht wahr, aber (anstatt zu verstehen, wie Klassen sich auf Dekorateure und ihre Metadaten beziehen), könnte es hilfreich sein, dies so zu betrachten, da es wichtig ist (IMHO), nicht mehr getrennt von Vorlage und Controller zu denken Entitäten, die sie als einheitliche Teile des Komponentenkonstrukts betrachten - dies ist einer der Hauptaspekte des ng2-Mentalmodells.

Wenn wir so denken, erwarten wir natürlich, dass privateVariablen in einer Komponentenklasse in ihrer Vorlage sichtbar sind, aus demselben Grund, aus dem wir erwarten, dass sie in den privateMethoden in dieser Klasse sichtbar sind .


3
Zuerst dachte ich genau wie du. Aber ich habe tslint auf 4.02 und codelyzer auf 2.0.0-beta.1 aktualisiert und es gab Fehler, dass ich beim Zugriff auf Variablen in der Ansicht nicht privat verwenden kann. Die Antwort von @ Yaroslav scheint also angemessener zu sein.
maxime1992

8
Ich bin damit einverstanden, dass es für ein Komponentenmodell keinen Sinn macht, seine privaten Variablen nicht sehen zu können. Sie sollten beim Kompilieren wahrscheinlich in dieselbe Klasse eingeteilt werden. Ich meine, Sie müssen komponentenspezifische Merkmale, Objekte und Funktionen aussetzen Alle anderen Komponenten, damit Sie diese in Ihrer Vorlage verwenden können, ganz zu schweigen von externen Optimierungen oder Aufrufen dieser Komponenten, können zu potenziell unerwartetem Verhalten der fertigen Komponente führen
Felype,

1
@rewmoore, hallo ich habe nur seit einigen Monaten eckig codiert. Ich wurde mit diesem Problem konfrontiert. Gibt es eine weitere Debatte darüber? Da ich nichts Spezielles finde, welchem ​​Muster ich folgen soll. Imo, da es das wert ist, was es ist, scheint es die Codetrennung zu verletzen.
Edgar

2
@rewmoore, ich muss sagen, ich stimme deiner Anser-Logik voll und ganz zu. und ich fürchte, das Angular-Team hat ein bisschen durcheinander gebracht. Im AOT-Modus erlauben sie keine privaten Mitglieder, während sie in den Dokumenten etwas anderes behaupten, was im Fall von privaten Mitgliedern Ihren Standpunkt absolut stärkt und diesem Thema nur mehr Chaos hinzufügt. Aus Dokumenten: "Angular behandelt die Vorlage einer Komponente als zur Komponente gehörend. Die Komponente und ihre Vorlage vertrauen sich implizit. Daher kann die eigene Vorlage der Komponente mit oder ohne den Eingabe-Dekorator * @ * an jede Eigenschaft dieser Komponente gebunden werden. ""
Orel Eraki

@drewmoore, Link für die Dokumente: angle.io/guide/attribute-directives#appendix-why-add-input (Ich weiß, dass es hauptsächlich um Input Decorator geht, aber vieles, worüber sie sprechen, hängt nicht nur damit zusammen it)
Orel Eraki

16

Obwohl das Codebeispiel angibt, dass es sich bei der Frage um TypeScript handelt, verfügt sie nicht über die Etikett. Angular2 ist auch für Dart verfügbar und dies ist ein bemerkenswerter Unterschied zu Dart.

In Dart kann die Vorlage nicht auf private Variablen der Komponentenklasse verweisen , da Dart im Gegensatz zu TypeScript den Zugriff privater Mitglieder von außen effektiv verhindert.

Ich unterstütze immer noch den Vorschlag von @drewmoores, über die Komponente und ihre Vorlage als eine Einheit nachzudenken.

Update (TS) Mit der Offline-Kompilierung scheint der Zugriff auf private Eigenschaften auch in Angular2 TS eingeschränkt zu werden. Https://github.com/angular/angular/issues/11422


2
Ist es möglich, einen Typescript-Compiler zu haben, um den Zugriff privater Variablen auf die Ansicht einzuschränken?
Matthew Harwood

Ich weiß es nicht. Ich denke nicht.
Günter Zöchbauer

2
Ich würde denken, dass eine private Darstellung Einfluss darauf haben könnte, wie testbar die Komponente ist. Wenn ich beispielsweise eine Komponente im Kontext eines Tests erstelle, kann ich diese privaten Methoden aus meinem Test nicht aufrufen, um zu bestätigen, dass die Interaktion zwischen Vorlage und Klasse funktioniert. Ich habe das noch nicht ausprobiert, also vergib mir, wenn das offensichtlich ist :)
Sam Storie

In Dart können Sie in Tests nicht auf private Mitglieder zugreifen. Es wird viel diskutiert (unabhängig von der Sprache), ob dies unterstützt werden sollte und ob die private API überhaupt getestet werden sollte. Das Testen der öffentlichen API sollte in der Lage sein, jeden Codepfad zu erreichen. Ich denke, das ist im Allgemeinen vernünftig. In Dart ist privat pro Bibliothek (die aus mehreren Dateien bestehen kann), was die öffentliche API ziemlich breit macht - IMHO zu breit für Unit-Tests.
Günter Zöchbauer

3

Private Variablen können innerhalb der Vorlage der Komponente verwendet werden. Eine Anleitung finden Sie im Angular2-Spickzettel: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Eine ausführlichere Erklärung zu öffentlichen / privaten Mitgliedern von Klassen in Typoskript finden Sie hier: https://www.typescriptlang.org/docs/handbook/classes.html .

Alle Mitglieder sind standardmäßig öffentlich. Auf öffentliche Mitglieder kann von außerhalb der Komponentenklasse zusammen mit der Klasseninstanz zugegriffen werden. Auf private Mitglieder kann jedoch nur innerhalb der Klassenmitgliedsfunktionen zugegriffen werden.


Ich habe mir den ersten Link angesehen ( angle.io/guide/component-interaction#!#parent-to-child-setter ) und sehe nirgendwo, dass die Verwendung privater Variablen in Vorlagen in Ordnung ist. Im Gegenteil, sie verwenden Getter und Setter, um über die Vorlage auf die privaten Variablen zuzugreifen.
Sebastien Chartier

3

Eine Problemumgehung könnte darin bestehen, private Variablen in der ts-Datei und Getter zu verwenden.

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

Dies ist ein guter Ansatz, da die ts-Datei und der HTML-Code unabhängig bleiben. Selbst wenn Sie den Variablennamen _userName in der Datei ts ändern, müssen Sie keine Änderungen an der Vorlagendatei vornehmen.


Ich denke, wenn Sie _userName in _clientName ändern, zum Beispiel aus Gründen der Konsistenz, müssen Sie Getter ändern, um clientName zu erhalten ... also gibt es keinen Gewinn
LeagueOfJava

Es ist eine schlechte Praxis, Benutzer für private Variablen zu unterstreichen.
Florian Leitgeb

1
@FlorianLeitgeb Welches ist der Grund, warum die offiziellen Angular-Dokumente dies tun ? private _name = '';
Ruffin

Dann wurde dieses Code-Snippet nicht richtig überprüft. Sie folgen einer Stilkonvention, die hier im Styleguide deklariert ist . Und auch im Abschnitt Typescript-Klassen auf ihrer Seite hier kein Unterstrich verwendet.
Florian Leitgeb

1
@FlorianLeitgeb Also, was wäre die vorgeschlagene Lösung für das Abfangen von Setter-Methoden, wie in dem von Ruffin geposteten Link gezeigt? dh Wie nennt man das private Hintergrundfeld Ihres Setters?
El Ronnoco

1

Die kurze Antwort lautet: Nein, Sie sollten nicht über die Vorlage auf private Mitglieder zugreifen können, da diese technisch von der TS-Datei getrennt ist.


0

Wenn Sie in tsconfig.app.json die Option 'fullTemplateTypeCheck' in den Compileroptionen angeben, werden alle ungültigen Verweise in HTML-Dateien Ihres Projekts zum Zeitpunkt der Projekterstellung angezeigt.

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

}}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.