Angular2 - as variáveis ​​privadas devem estar acessíveis no modelo?

143

Se uma variável for declarada privateem uma classe de componente, devo acessá-la no modelo desse 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
fonte

Respostas:

226

Não, você não deve usar variáveis ​​privadas em seus modelos.

Embora eu goste da resposta do drewmoore e veja a lógica conceitual perfeita nela, na implementação, ela está errada. Os modelos não existem nas classes de componentes, mas fora delas. Dê uma olhada neste repositório para a prova.

A única razão pela qual ele funciona é porque a privatepalavra-chave do TypeScript realmente não torna o membro privado. A compilação Just-in-Time acontece em um navegador em tempo de execução e o JS ainda não tem nenhum conceito de membros privados (ainda?). O crédito é para Sander Elias por me colocar no caminho certo.

Com uma ngccompilação antecipada, você obterá erros se tentar acessar membros privados do componente a partir do modelo. Clone o repositório de demonstração, altere MyComponenta visibilidade dos membros para privado e você receberá erros de compilação ao executar ngc. Aqui também está a resposta específica para a compilação Antecipada.

Yaroslav Admin
fonte
6
este é o melhor comentário e imo deve ser a resposta aceita. Não é que você possa usar variáveis ​​privadas, uma vez transpiladas, que você deve .. Mantenha o código limpo!
Sam Vloeberghs
2
Esta é a única resposta válida! O Codelyzer agora avisa quando você usa var privado no seu modelo.
maxime1992
7
Meu único problema com isso é: como você diferencia entre membros reais expostos ao público, como @Inputs e Outputs, para membros que queremos expor apenas ao nosso modelo e não ao mundo externo. Se você estiver criando componentes reutilizáveis ​​onde deseja que os métodos / membros sejam acessíveis ao modelo, mas não a outros componentes. Eu acho que a resposta original está correta. Os modelos fazem parte do componente.
Ashg 04/10/19
1
Concordo com @Ashg - e não apenas com entradas e saídas erradas. E quando eu quero me comunicar entre componentes, por exemplo, injetando um componente pai em seu filho. O componente filho pode ver tudo o que o pai está expondo ao modelo, em vez de apenas os métodos que o pai deseja expor para o mundo externo. Dentro das restrições do Angular, essa resposta permanece a correta, mas não acho que esse design tenha sido bem pensado.
Dan King
Essa é uma boa resposta, pois aborda as limitações da compilação AoT do Angular e como contorná-las. No entanto, na IMO a questão era conceitual (intencionalmente ou não). Conceitualmente, os modelos fazem parte das definições de classe. Os modelos não estendem nem herdam classes e eles não acessam objetos instanciados externamente ... é o contrário. Os modelos são definidos na própria classe e, conceitualmente, fazem parte da classe e, conceitualmente, devem ter acesso a membros privados.
A-Diddy
85

Editar: Esta resposta está incorreta. Não havia orientação oficial sobre o tópico quando eu o publiquei, mas, como explicado na resposta de @ Yaroslov (excelente e correta), esse não é mais o caso: o Codelizer agora alerta e a compilação do AoT falhará nas referências a variáveis ​​privadas nos modelos de componentes . Dito isto, em um nível conceitual, tudo aqui permanece válido, então deixarei esta resposta como parece ter sido útil.


Sim, isso é esperado.

Lembre-se de que privatee outros modificadores de acesso são construções Typescript, enquanto Component / controller / template são construções angulares que a Typescript não conhece. Modificadores de acesso controlam a visibilidade entre classes: criar um campo privateimpede que outras classes tenham acesso a ele, mas modelos e controladores são coisas que existem dentro das classes.

Isso não é tecnicamente verdade, mas (em vez de entender como as classes se relacionam com os decoradores e seus metadados), pode ser útil pensar dessa maneira, porque o importante (IMHO) é deixar de pensar no modelo e no controlador como separados entidades pensem nelas como partes unificadas do construto Component - este é um dos principais aspectos do modelo mental ng2.

Pensando dessa maneira, obviamente esperamos que privatevariáveis ​​em uma classe de componente sejam visíveis em seu modelo, pelo mesmo motivo que esperamos que sejam visíveis nos privatemétodos dessa classe.

chamou moore
fonte
3
Primeiro, pensei como você desenhou. Mas atualizei o tslint para 4.02 e o codelyzer para 2.0.0-beta.1 e tive erros dizendo que não posso usar privado ao acessar variáveis ​​em exibição. Portanto, a resposta de @ Yaroslav parece mais apropriada.
maxime1992
8
Concordo que não faz sentido que um modelo de componente não consiga ver suas variáveis ​​privadas; elas provavelmente devem ser agrupadas em uma mesma classe durante a compilação; quero dizer, você precisa expor características, objetos e funções específicas de componentes para todos os outros componentes de modo que você pode usá-los em seu modelo, para não mencionar ajustes ou chamadas externas para aqueles poderia causar um comportamento inesperado potencial no componente acabado
Felype
1
@drewmoore, olá Eu tenho codificado angular apenas por alguns meses. Fui confrontado com esse problema. Existe algum debate adicional sobre isso? Como não encontro nada específico sobre qual padrão seguir. imo, como vale a pena o que é, parece violar a separação de código.
Edgar
2
@ Drewmoore, devo dizer que estou totalmente de acordo com a sua lógica anser. e temo que a equipe Angular tenha estragado um pouco. no modo AOT, eles não estão permitindo membros privados, enquanto nos documentos que afirmam em contrário, o que no caso de membros privados está absolutamente fortalecendo seu argumento e adicionando mais caos a este tópico. Do Docs: "Angular trata o modelo de um componente como pertencendo ao componente. O componente e seu modelo confiam um no outro implicitamente. Portanto, o próprio modelo do componente pode se vincular a qualquer propriedade desse componente, com ou sem o decorador * @ * Input. "
Orel Eraki
@drewmoore, Link para os documentos: angular.io/guide/attribute-directives#appendix-why-add-input (eu sei que ele se concentra principalmente no decorador de entradas, mas muito do que eles estão falando não está relacionado apenas a )
Orel Eraki
16

Mesmo que o exemplo de código indique que a pergunta é sobre TypeScript, ele não tem o tag. O Angular2 também está disponível para o Dart e essa é uma diferença notável para o Dart.

No Dart, o modelo não pode fazer referência a variáveis ​​privadas da classe de componentes, porque o Dart, em contraste com o TypeScript, impede efetivamente o acesso de membros privados de fora.

Ainda apoio a sugestão do @drewmoores de pensar no componente e no modelo como uma unidade.

Atualização (TS) Parece que, com a compilação offline, o acesso a propriedades privadas também se tornará mais limitado no Angular2 TS https://github.com/angular/angular/issues/11422

Günter Zöchbauer
fonte
2
É possível ter o compilador Typescript para limitar as variáveis ​​privadas que estão acessíveis para a exibição?
Matthew Harwood
Eu não sei. Eu acho que não.
Günter Zöchbauer
2
Eu pensaria que tê-los em particular poderia afetar a testabilidade do componente, certo? Por exemplo, se eu criar um componente no contexto de um teste, não conseguiria chamar esses métodos particulares do meu teste para confirmar se a interação modelo / classe está funcionando. Eu não tentei isso ainda, então me perdoe se isso é óbvio :)
Sam Storie
No Dart, você não pode acessar membros particulares nos testes. Há muita discussão (independente do idioma) se isso deve ser suportado e se a API privada deve ser testada. O teste da API pública deve ser capaz de alcançar cada caminho de código. Eu acho que isso é razoável em geral. No Dart, o privado é por biblioteca (que pode consistir em vários arquivos), o que torna a API pública bastante ampla - o IMHO é amplo demais para teste de unidade.
Günter Zöchbauer
3

Variáveis ​​privadas podem ser usadas no modelo de componente. Consulte a folha de dicas angular2 para obter orientação: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Uma explicação mais detalhada sobre membros públicos / privados de classes em texto datilografado pode ser encontrada aqui: https://www.typescriptlang.org/docs/handbook/classes.html .

Todos os membros por padrão são públicos. Os membros públicos podem ser acessados ​​de fora da classe do componente junto com a instância da classe. Porém, membros privados podem ser acessados ​​somente dentro das funções de membro da classe.

anusreemn
fonte
Eu olhei para o primeiro link ( angular.io/guide/component-interaction#!#parent-to-child-setter ) e não vejo em nenhum lugar que ele sugira que o uso de variáveis ​​privadas em modelos esteja correto. Pelo contrário, eles usam getters e setters para acessar as variáveis ​​privadas do modelo.
Sebastien Chartier
3

Uma solução alternativa pode estar usando variáveis ​​privadas no arquivo ts e usando getters.

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

Essa é uma boa abordagem, porque o arquivo ts e o html permanecem independentes. Mesmo se você alterar o nome da variável _userName no arquivo ts, não será necessário fazer nenhuma alteração no arquivo de modelo.

Franklin Pious
fonte
Eu acho que se u mudar _username para _clientName, por exemplo, para a consistência, você precisa mudar getter para obter clientName ... por isso não há vitória
LeagueOfJava
É uma má prática o usuário sublinhar para variáveis ​​privadas.
Florian Leitgeb
1
@FlorianLeitgeb É por isso que os documentos oficiais da Angular fazem isso ? private _name = '';
Ruffin
Em seguida, esse snippet de código não foi revisado corretamente. Eles seguem uma convenção de estilo, que é declarada no guia de estilo aqui . E também na seção Classes de texto datilografado em sua página aqui, não está usando o sublinhado.
Florian Leitgeb
1
@FlorianLeitgeb Então, qual seria a solução proposta para a interceptação de métodos setter, como mostra o link postado por ruffin? ie Como você chama o campo de apoio privado do seu levantador?
El Ronnoco 14/01/19
1

A resposta curta é não, você não deve conseguir acessar membros privados do modelo porque ele é tecnicamente separado do arquivo TS.

Ivens Applyrs
fonte
0

No tsconfig.app.json, se você fornecer a opção 'fullTemplateTypeCheck' nas opções do compilador, poderá ver todas as referências inválidas nos arquivos html do seu projeto no momento da construção do projeto.

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

}

Khushbu Suryavanshi
fonte