Angular2 - czy w szablonie powinny być dostępne zmienne prywatne?

143

Jeśli zmienna jest zadeklarowana privatew klasie komponentu, czy powinienem mieć do niej dostęp w szablonie tego komponentu?

@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
źródło

Odpowiedzi:

226

Nie, nie powinieneś używać prywatnych zmiennych w swoich szablonach.

Chociaż podoba mi się odpowiedź drewmoore'a i widzę w niej doskonałą logikę koncepcyjną, pod względem implementacji jest źle. Szablony nie istnieją w klasach komponentów, ale poza nimi. Spójrz na to repozytorium, aby uzyskać dowód.

Jedynym powodem, dla którego to działa, jest to, że privatesłowo kluczowe TypeScript nie sprawia, że ​​element członkowski jest prywatny. Kompilacja Just-in-Time odbywa się w przeglądarce w czasie wykonywania, a JS nie ma żadnej koncepcji prywatnych członków (jeszcze?). Chwała Sanderowi Eliasowi za skierowanie mnie na właściwy tor.

Dzięki ngckompilacji i kompilacji z wyprzedzeniem wystąpią błędy, jeśli spróbujesz uzyskać dostęp do prywatnych członków komponentu z szablonu. Sklonuj repozytorium demonstracyjne, zmień MyComponentwidoczność członków na prywatną, a podczas uruchamiania wystąpią błędy kompilacji ngc. Tutaj jest również odpowiedź specyficzna dla kompilacji Ahead-of-Time.

Jarosław Admin
źródło
6
to jest najlepszy komentarz, a imo powinno być akceptowaną odpowiedzią. Nie chodzi o to, że po transpozycji można używać zmiennych prywatnych, tak powinno się ... Utrzymywać kod w czystości!
Sam Vloeberghs
2
To jedyna ważna odpowiedź! Codelyzer ostrzega teraz, kiedy używasz prywatnych zmiennych w swoim szablonie.
maxime1992
7
Mój jedyny problem z tym polega na tym, jak odróżnić rzeczywiste publicznie ujawnione elementy członkowskie, takie jak @Inputs i Outputs dla członków, które chcemy ujawnić tylko naszemu szablonowi, a nie światu zewnętrznemu. Jeśli budujesz komponenty wielokrotnego użytku, w których chcesz, aby metody / elementy były dostępne dla szablonu, ale nie dla innych komponentów. Myślę, że pierwotna odpowiedź jest poprawna. Szablony są częścią komponentu.
Ashg
1
Zgadzam się z @Ashg - i nie tylko wrt Inputs and Outputs. A co w sytuacji, gdy chcę się komunikować między komponentami, np. Poprzez wstrzyknięcie komponentu rodzica swojemu dziecku. Komponent potomny może wtedy zobaczyć wszystko, co rodzic ujawnia w swoim szablonie, zamiast tylko metod, które rodzic chce ujawnić światu zewnętrznemu. W ramach ograniczeń Angulara ta odpowiedź pozostaje poprawna, ale nie sądzę, aby ten projekt został dobrze przemyślany.
Dan King,
To dobra odpowiedź, ponieważ dotyczy ograniczeń w kompilacji AoT Angulara i sposobu ich obejścia. Jednak IMO pytanie było koncepcyjne (celowo lub nie). Koncepcyjnie szablony są częścią definicji klas. Szablony nie rozszerzają ani nie dziedziczą klas i nie mają zewnętrznego dostępu do obiektów, do których utworzono instancję ... jest na odwrót. Szablony są zdefiniowane w samej klasie, więc koncepcyjnie są częścią klasy i koncepcyjnie powinny mieć dostęp do prywatnych członków.
A-Diddy
85

Edycja: ta odpowiedź jest teraz nieprawidłowa. Nie było oficjalnych wskazówek na ten temat, kiedy to opublikowałem, ale jak wyjaśniono w odpowiedzi @ Yaroslova (doskonała i poprawna), to już nie ma miejsca: Codelizer ostrzega teraz i kompilacja AoT nie powiedzie się w przypadku odwołań do zmiennych prywatnych w szablonach komponentów . To powiedziawszy, na poziomie koncepcyjnym wszystko tutaj pozostaje aktualne, więc zostawię tę odpowiedź, ponieważ wydaje się być pomocna.


Tak, jest to oczekiwane.

Należy pamiętać, że privatei inne modyfikatory dostępu są konstrukcjami Typescript, podczas gdy komponent / kontroler / szablon to konstrukcje kątowe, o których Typescript nic nie wie. Modyfikatory dostępu kontrolują widoczność między klasami: utworzenie pola privateuniemożliwia innym klasom dostęp do niego, ale szablony i kontrolery to elementy, które istnieją w klasach.

To nie jest technicznie prawda, ale (zamiast rozumieć, w jaki sposób klasy odnoszą się do dekoratorów i ich metadanych), warto pomyśleć o tym w ten sposób, ponieważ ważne jest (IMHO) odejście od myślenia o szablonie i kontrolerze jako osobnych by traktować je jako zjednoczone części konstrukcji komponentu - jest to jeden z głównych aspektów modelu mentalnego ng2.

Myśląc o tym w ten sposób, oczywiście oczekujemy, że privatezmienne w klasie komponentów będą widoczne w jej szablonie, z tego samego powodu, dla którego oczekujemy, że będą widoczne w privatemetodach tej klasy.

Drew Moore
źródło
3
Po pierwsze, pomyślałem, tak jak ty rysowałeś. Ale zaktualizowałem tslint do 4.02, a codelyzer do 2.0.0-beta.1 i wystąpiły błędy mówiące, że nie mogę używać private podczas uzyskiwania dostępu do zmiennych w widoku. Tak więc odpowiedź @ Yaroslava wydaje się bardziej odpowiednia.
maxime1992
8
Zgadzam się, że nie ma sensu, aby model składowy nie był w stanie zobaczyć swoich prywatnych zmiennych, prawdopodobnie powinny one zostać zmiksowane w tę samą klasę podczas kompilacji, to znaczy, musisz ujawnić specyficzne cechy, obiekty i funkcje komponentu wszystkie inne komponenty, abyś mógł użyć tych w swoim szablonie, nie wspominając o zewnętrznych poprawkach lub wywołaniach do nich, które mogą spowodować potencjalne nieoczekiwane zachowanie gotowego komponentu
Felype
1
@drewmoore, cześć. Piszę angular tylko od kilku miesięcy. Miałem do czynienia z tym problemem. Czy jest jakaś dalsza debata na ten temat? Ponieważ nie znajduję nic konkretnego na temat tego, jaki wzór mam naśladować. imo, ponieważ jest tego warte, wydaje się, że narusza separację kodu.
Edgar
2
@drewmoore, muszę powiedzieć, że całkowicie zgadzam się z twoją logiką anser. i obawiam się, że zespół Angular trochę namieszał. w trybie AOT nie pozwalają członkom prywatnym, podczas gdy w dokumentach twierdzą, że jest inaczej, co w przypadku członków prywatnych absolutnie wzmacnia twój punkt widzenia i tylko dodaje więcej chaosu do tego tematu. From Docs: „Angular traktuje szablon komponentu jako należący do komponentu. Komponent i jego szablon niejawnie ufają sobie nawzajem. Dlatego własny szablon komponentu może wiązać się z dowolną właściwością tego komponentu, z dekoratorem * @ * Input lub bez niego. "
Orel Eraki
@drewmoore, Link do dokumentów: angular.io/guide/attribute-directives#appendix-why-add-input (wiem, że koncentruje się głównie na dekoratorze danych wejściowych, ale wiele z tego, o czym mówią, nie jest tylko it)
Orel Eraki,
16

Mimo że przykładowy kod wskazuje, że pytanie dotyczy języka TypeScript, nie ma rozszerzenia etykietka. Angular2 jest również dostępny dla Dart i jest to znacząca różnica w stosunku do Dart.

W Dart szablon nie mogą odwoływać się do zmiennych prywatnych klasy komponentów, ponieważ w przeciwieństwie do darta maszynopis skutecznie uniemożliwia dostęp prywatnych członków z zewnątrz.

Wciąż jednak popieram sugestię @drewmoores, aby pomyśleć o komponencie i jego szablonie jako jednej jednostce.

Aktualizacja (TS) Wygląda na to, że dostęp do kompilacji offline do prywatnych właściwości stanie się bardziej ograniczony również w Angular2 TS https://github.com/angular/angular/issues/11422

Günter Zöchbauer
źródło
2
Czy jest możliwe, aby kompilator Typescript ograniczał dostęp do zmiennych prywatnych w widoku?
Matthew Harwood
Nie wiem Nie sądzę.
Günter Zöchbauer
2
Myślę, że posiadanie ich prywatnych może wpłynąć na to, jak testowalny jest ten komponent? Na przykład, jeśli utworzę komponent w kontekście testu, nie byłbym w stanie wywołać tych prywatnych metod z mojego testu, aby potwierdzić, że interakcja szablon / klasa działa. Jeszcze tego nie próbowałem, więc wybacz mi, jeśli to oczywiste :)
Sam Storie
W Dart nie możesz uzyskać dostępu do prywatnych członków w testach. Istnieje wiele dyskusji (niezależnie od języka), czy powinno to być obsługiwane i czy w ogóle należy testować prywatne API. Testowanie publicznego interfejsu API powinno móc dotrzeć do każdej ścieżki kodu. Myślę, że ogólnie jest to rozsądne. W Dart prywatne jest na bibliotekę (która może składać się z kilku plików), co sprawia, że ​​publiczne API jest dość szerokie - IMHO jest zbyt szerokie dla testów jednostkowych.
Günter Zöchbauer
3

Zmienne prywatne mogą być używane w szablonie komponentu. Zobacz poradnik dotyczący angular2: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Bardziej szczegółowe wyjaśnienie na temat publicznych / prywatnych członków klas w maszynopisie można znaleźć tutaj: https://www.typescriptlang.org/docs/handbook/classes.html .

Wszyscy członkowie są domyślnie publicznymi. Dostęp do członków publicznych można uzyskać spoza klasy komponentów wraz z instancją klasy. Dostęp do członków prywatnych można jednak uzyskać tylko w ramach funkcji składowych klasy.

anusreemn
źródło
Spojrzałem na pierwszy link ( angular.io/guide/component-interaction#!#parent-to-child-setter ) i nigdzie nie widzę, że sugeruje to używanie prywatnych zmiennych w szablonach. Wręcz przeciwnie, używają metod pobierających i ustawiających, aby uzyskać dostęp do zmiennych prywatnych z szablonu.
Sebastien Chartier
3

Obejściem może być użycie zmiennych prywatnych w pliku ts i użycie metod pobierających.

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

To dobre podejście, ponieważ plik ts i html pozostają niezależne. Nawet jeśli zmienisz nazwę zmiennej _userName w pliku ts, nie musisz dokonywać żadnych zmian w pliku szablonu.

Franklin Pious
źródło
myślę, że jeśli zmienisz _userName na _clientName, na przykład, dla spójności, musisz zmienić getter, aby uzyskać clientName ... więc nie ma wygranej
LeagueOfJava
Podkreślanie przez użytkownika dla zmiennych prywatnych jest złą praktyką.
Florian Leitgeb
1
@FlorianLeitgeb Dlaczego oficjalne dokumenty Angular to robią ? private _name = '';
ruffin
Wtedy ten fragment kodu nie został poprawnie sprawdzony. Są one zgodne z konwencją styl, który jest zadeklarowany w przewodniku redakcyjnym tutaj . A także w sekcji klas maszynopisu na ich stronie tutaj nie używa się podkreślenia.
Florian Leitgeb
1
@FlorianLeitgeb Jakie byłoby więc proponowane rozwiązanie przechwytywania metod ustawiających, jak pokazano w linku opublikowanym przez ruffin? tj. jak nazywasz prywatne pole wspierające swojego ustawiającego?
El Ronnoco,
1

Krótka odpowiedź brzmi: nie, nie powinieneś mieć dostępu do prywatnych członków z szablonu, ponieważ jest on technicznie oddzielony od pliku TS.

Ivens Applrs
źródło
0

W tsconfig.app.json, jeśli podasz opcję „fullTemplateTypeCheck” w opcjach kompilatora, zobaczysz wszystkie nieprawidłowe odwołania w plikach html projektu w czasie tworzenia projektu.

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

}

Khushbu Suryavanshi
źródło