Angolare2: le variabili private dovrebbero essere accessibili nel modello?


143

Se una variabile viene dichiarata privatesu una classe di componente, dovrei essere in grado di accedervi dal modello di quel 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
}

Risposte:


226

No, non dovresti usare variabili private nei tuoi modelli.

Mentre mi piace la risposta di Drewmoore e vedo la perfetta logica concettuale in essa, implementalmente è sbagliata. I modelli non esistono all'interno delle classi dei componenti, ma al di fuori di essi. Dai un'occhiata a questo repository per la prova.

L'unico motivo per cui funziona è perché la privateparola chiave di TypeScript non rende il membro privato. La compilazione just-in-time avviene in un browser in fase di runtime e JS non ha alcun concetto di membri privati ​​(ancora?). Il merito va a Sander Elias per avermi messo sulla strada giusta.

Con una ngccompilazione anticipata, otterrai errori se provi ad accedere ai membri privati ​​del componente dal modello. Clona il repository dimostrativo, modifica MyComponentla visibilità dei membri in privato e otterrai errori di compilazione durante l'esecuzione ngc. Ecco anche una risposta specifica per la compilazione Ahead-of-Time.


6
questo è il miglior commento e imo dovrebbe essere la risposta accettata. Non è che puoi usare le variabili private una volta compilate, che dovresti .. Mantenere il codice pulito!
Sam Vloeberghs,

2
Questa è l'unica risposta valida! Codelyzer ora ti avverte quando usi var privato nel tuo modello.
maxime1992,

7
Il mio unico problema è come distinguere tra membri effettivamente esposti pubblicamente come @Inputs e Output ai membri che vogliamo esporre solo al nostro modello e non al mondo esterno. Se si creano componenti riutilizzabili in cui si desidera che i metodi / membri siano accessibili al modello ma non ad altri componenti. Penso che la risposta originale sia corretta. I modelli fanno parte del componente.
Ashg,

1
Sono d'accordo con @Ashg - e non solo per gli input e gli output. Che dire di quando voglio comunicare tra i componenti, ad esempio iniettando un componente genitore nel suo figlio. Il componente figlio può quindi vedere tutto ciò che il genitore sta esponendo al suo modello, anziché solo i metodi che il genitore vuole esporre al mondo esterno. Nei limiti di Angular, questa risposta rimane quella corretta, ma non credo che questo progetto sia stato ben studiato.
Dan King,

Questa è una buona risposta poiché affronta i limiti della compilazione AoT di Angular e come aggirarli. Tuttavia, IMO la domanda era concettuale (intenzionalmente o no). Concettualmente, i modelli fanno parte delle definizioni di classe. I modelli non estendono né ereditano le classi e non accedono agli oggetti istanziati esternamente ... è il contrario. I modelli sono definiti all'interno della classe stessa, quindi concettualmente fanno parte della classe e concettualmente dovrebbero avere accesso ai membri privati.
A-Diddy,

85

Modifica: questa risposta ora non è corretta. Non vi era alcuna guida ufficiale sull'argomento quando l'ho pubblicato, ma come spiegato nella risposta (eccellente e corretta) di @ Yaroslov, questo non è più il caso: Codelizer ora avverte e la compilazione di AoT fallirà sui riferimenti a variabili private nei modelli di componenti . Detto questo, a livello concettuale tutto qui rimane valido, quindi lascerò questa risposta come sembra essere stata utile.


Sì, questo è previsto.

Tieni presente che privatee altri modificatori di accesso sono costrutti Typescript, mentre Componente / controller / modello sono costrutti angolari di cui Typescript non sa nulla. I modificatori di accesso controllano la visibilità tra le classi: la creazione di un campo privateimpedisce ad altre classi di accedervi, ma modelli e controller sono elementi che esistono all'interno delle classi.

Questo non è tecnicamente vero, ma (al posto di capire come le classi si relazionano con i decoratori e i loro metadati), potrebbe essere utile pensarlo in questo modo, perché l'importante (IMHO) è passare dal pensare a template e controller come separati le entità nel pensare a loro come parti unificate del costrutto Componente - questo è uno dei principali aspetti del modello mentale ng2.

Pensandolo in questo modo, ovviamente ci aspettiamo che le privatevariabili su una classe componente siano visibili nel suo modello, per lo stesso motivo per cui ci aspettiamo che siano visibili nei privatemetodi su quella classe.


3
In primo luogo, ho pensato proprio come te Drewmoore. Ma ho aggiornato tslint a 4.02 e codelyzer a 2.0.0-beta.1 e ho avuto errori che dicevano che non potevo usare il privato quando accedevo alle variabili in vista. Quindi la risposta di @ Yaroslav sembra più appropriata.
maxime1992,

8
Sono d'accordo che non ha senso per un modello di componente non essere in grado di vedere le sue variabili private, probabilmente dovrebbero essere schiacciate in una stessa classe durante la compilazione, voglio dire, devi esporre tratti, oggetti e funzioni specifici del componente a tutti gli altri componenti in modo da poter utilizzare quelli nel modello, per non parlare di modifiche esterne o chiamate a quelli potrebbero causare potenziali comportamenti imprevisti sul componente finito
Felype,

1
@drewmoore, ciao sto programmando angolare solo da alcuni mesi. Mi sono trovato di fronte a questo problema. C'è altro dibattito su questo? Dato che non trovo nulla di specifico su quale modello seguire. imo, dal momento che vale quello che sembra, sembra violare la separazione del codice.
Edgar,

2
@drewmoore, devo dire che sono totalmente d'accordo con la tua logica di risposta. e temo che la squadra angolare abbia incasinato un po '. in modalità AOT, non stanno permettendo ai membri privati, mentre sui documenti sostengono diversamente, che nel caso dei membri privati ​​sta assolutamente rafforzando il tuo punto e aggiungendo solo più caos a questo argomento. Da Documenti: "Angolare considera il modello di un componente come appartenente al componente. Il componente e il suo modello si fidano reciprocamente implicitamente. Pertanto, il modello del componente stesso può legarsi a qualsiasi proprietà di quel componente, con o senza il decoratore di input * @ *. "
Orel Eraki,

@drewmoore, Link per i documenti: angular.io/guide/attribute-directives#appendix-why-add-input (So ​​che si concentra principalmente su Input decorator, ma molto di ciò di cui stanno parlando non è legato solo a it)
Orel Eraki l'

16

Anche se l'esempio di codice indica che la domanda riguarda TypeScript, non ha il etichetta. Angular2 è disponibile anche per Dart e questa è una differenza notevole rispetto a Dart.

In Dart il modello non può fare riferimento a variabili private della classe del componente, poiché Dart in contrasto con TypeScript impedisce efficacemente l'accesso di membri privati ​​dall'esterno.

Ritengo ancora il suggerimento di @drewmoores di pensare al componente e al suo modello come un'unità.

Aggiornamento (TS) Sembra che con la compilazione offline l'accesso alle proprietà private diventerà più limitato anche in Angular2 TS https://github.com/angular/angular/issues/11422


2
È possibile avere un compilatore Typescript per limitare l'accesso delle variabili private alla vista?
Matthew Harwood,

Non lo so. Non credo.
Günter Zöchbauer,

2
Penserei che averli privati ​​potrebbe influire su quanto sia testabile il componente è giusto? Ad esempio, se creo un componente nel contesto di un test, non sarei in grado di chiamare quei metodi privati ​​dal mio test per confermare che l'interazione modello / classe funziona. Non l'ho ancora provato, quindi perdonami se questo è ovvio :)
Sam Storie

In Dart non puoi accedere ai membri privati ​​nei test. Si discute molto (indipendentemente dalla lingua) se questo dovrebbe essere supportato e se l'API privata debba essere testata. Il test dell'API pubblica dovrebbe essere in grado di raggiungere ciascun percorso del codice. Penso che questo sia ragionevole in generale. In Dart private è per libreria (che può consistere in diversi file) che rende l'API pubblica abbastanza ampia - IMHO troppo ampia per unit test.
Günter Zöchbauer,

3

Le variabili private possono essere utilizzate nel modello del componente. Vedi il cheat-sheet angular2 per la guida: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Una spiegazione più dettagliata dei membri pubblici / privati ​​delle classi in dattiloscritto è disponibile qui: https://www.typescriptlang.org/docs/handbook/classes.html .

Tutti i membri per impostazione predefinita sono pubblici. È possibile accedere ai membri pubblici dall'esterno della classe componente insieme all'istanza di classe. Ma i membri privati ​​sono accessibili solo all'interno delle funzioni dei membri della classe.


Ho guardato il primo link ( angular.io/guide/component-interaction#!#parent-to-child-setter ) e non vedo da nessuna parte che suggerisce che l'uso di variabili private nei template sia ok. Al contrario, usano getter e setter per accedere alle variabili private dal modello.
Sebastien Chartier,

3

Una soluzione alternativa potrebbe essere l'utilizzo di variabili private nel file ts e l'utilizzo di getter.

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

Questo è un buon approccio perché il file ts e l'html rimangono indipendenti. Anche se si modifica il nome della variabile _userName nel file ts, non è necessario apportare alcuna modifica al file modello.


penso che se cambi _userName in _clientName, ad esempio, per coerenza, devi cambiare getter per ottenere clientName ... quindi non c'è vittoria
LeagueOfJava

È una cattiva pratica la sottolineatura dell'utente per le variabili private.
Florian Leitgeb,

1
@FlorianLeitgeb Qual è il motivo per cui i documenti angolari ufficiali lo fanno ? private _name = '';
ruffin,

Quindi questo frammento di codice non è stato rivisto correttamente. Seguono una convenzione di stile, che è dichiarata nella guida di stile qui . E anche nella sezione Classi dattiloscritte sulla loro pagina qui non sta usando il trattino basso.
Florian Leitgeb,

1
@FlorianLeitgeb Quindi quale sarebbe la soluzione proposta per l'intercettazione dei metodi setter come mostrato nel link pubblicato da ruffin? cioè come si chiama il campo di supporto privato del setter?
El Ronnoco,

1

La risposta breve è no, non dovresti essere in grado di accedere ai membri privati ​​dal modello perché è tecnicamente separato dal file TS.


0

In tsconfig.app.json se fornisci l'opzione 'fullTemplateTypeCheck' nelle opzioni del compilatore puoi vedere tutti i riferimenti non validi nei file html del tuo progetto al momento della creazione del progetto.

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

}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.