Aguarde até que o Angular 2 carregue / resolva o modelo antes de renderizar a visualização / modelo

No Angular 1.x, o UI-Router foi minha principal ferramenta para isso. Ao retornar uma promise de valores de “resolução“, o roteador simplesmente esperaria a promise ser concluída antes de renderizar as diretivas.

Como alternativa, no Angular 1.x, um object nulo não trava um template – então, se eu não me importar com uma renderização temporariamente incompleta, posso usar $digest para renderizar após a promise.then() preenche um object de modelo inicialmente vazio .

Das duas abordagens, se possível, prefiro esperar para carregar a exibição e cancelar a navegação de rota, se o recurso não puder ser carregado. Isso me poupa do trabalho de “não navegar”. EDIT: Observe isso especificamente significa que essa pergunta solicita um método compatível com futuros ou práticas recomendadas do Angular 2 para fazer isso e pede para evitar o “operador de Elvis” se possível! Assim, não selecionei essa resposta.

No entanto, nenhum desses dois methods funciona no Angular 2.0. Certamente há uma solução padrão planejada ou disponível para isso. Alguém sabe o que é isso?

 @Component() { template: '{{cats.captchans.funniest}}' } export class CatsComponent { public cats: CatsModel; ngOnInit () { this._http.get('/api/v1/cats').subscribe(response => cats = response.json()); } } 

A pergunta a seguir pode refletir o mesmo problema: O modelo de renderização Angular 2 após o PROMISE com dados é carregado . Note que a pergunta não tem código ou resposta aceita.

    O pacote @angular/router tem a propriedade Resolve para rotas. Assim, você pode facilmente resolver os dados antes de renderizar uma visualização de rota.

    Veja: https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html

    Exemplo de documentos a partir de hoje, 28 de agosto de 2017:

     class Backend { fetchTeam(id: string) { return 'someTeam'; } } @Injectable() class TeamResolver implements Resolve { constructor(private backend: Backend) {} resolve( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable|Promise|any { return this.backend.fetchTeam(route.params.id); } } @NgModule({ imports: [ RouterModule.forRoot([ { path: 'team/:id', component: TeamCmp, resolve: { team: TeamResolver } } ]) ], providers: [TeamResolver] }) class AppModule {} 

    Agora sua rota não será ativada até que os dados sejam resolvidos e devolvidos.

    Acessando Dados Resolvidos em Seu Componente

    Para acessar os dados resolvidos de dentro de seu componente em tempo de execução, existem dois methods. Então, dependendo das suas necessidades, você pode usar:

    1. route.snapshot.paramMap que retorna uma string, ou o
    2. route.paramMap que retorna um Observable você pode .subscribe() para.

    Exemplo:

      // the no-observable method this.dataYouResolved= this.route.snapshot.paramMap.get('id'); // console.debug(this.licenseNumber); // or the observable method this.route.paramMap .subscribe((params: ParamMap) => { // console.log(params); this.dataYouResolved= params.get('id'); return params.get('dataYouResolved'); // return null }); console.debug(this.dataYouResolved); 

    Espero que isso ajude.

    Tente o {{model?.person.name}} isso deve esperar que o modelo não seja undefined e depois renderizado.

    Angular 2 refere-se a isso ?. syntax como o operador de Elvis . Referência a ele na documentação é difícil de encontrar, então aqui está uma cópia do mesmo, caso eles mudem / movam:

    O Operador Elvis (?.) E caminhos de propriedades nulos

    O operador Angular “Elvis” (?.) É uma maneira fluente e conveniente de proteger contra valores nulos e indefinidos em caminhos de propriedade. Aqui está, protegendo contra uma falha de renderização de exibição se o currentHero for nulo.

    The current hero's name is {{currentHero?.firstName}}

    Vamos elaborar o problema e essa solução específica.

    O que acontece quando a seguinte propriedade de título do limite de dados é nula?

    The title is {{ title }}

    A exibição ainda renderiza, mas o valor exibido está em branco; vemos apenas “O título é” sem nada depois. Isso é um comportamento razoável. Pelo menos o aplicativo não falha.

    Suponha que a expressão de modelo envolva um caminho de propriedade, como no próximo exemplo, onde estamos exibindo o primeiroNome de um herói nulo.

    The null hero's name is {{nullHero.firstName}}

    JavaScript lança um erro de referência nula e o mesmo acontece com o Angular:

    TypeError: Cannot read property 'firstName' of null in [null]

    Pior, toda a visão desaparece.

    Poderíamos afirmar que esse é um comportamento razoável se acreditarmos que a propriedade do herói nunca deve ser nula. Se nunca deve ser nulo e, no entanto, é nulo, fizemos um erro de programação que deve ser capturado e corrigido. Jogar uma exceção é a coisa certa a fazer.

    Por outro lado, valores nulos no caminho da propriedade podem ser OK de tempos em tempos, especialmente quando sabemos que os dados chegarão eventualmente.

    Enquanto esperamos pelos dados, a visualização deve renderizar sem reclamar e o caminho da propriedade nula deve ser exibido em branco, assim como a propriedade de título.

    Infelizmente, nosso aplicativo trava quando o currentHero é nulo.

    Nós poderíamos codificar em torno desse problema com NgIf

    The null hero's name is {{nullHero.firstName}}

    Ou poderíamos tentar encadear partes do caminho da propriedade com &&, sabendo que a expressão fica suspensa quando encontra o primeiro nulo.

    The null hero's name is {{nullHero && nullHero.firstName}}

    Essas abordagens têm mérito, mas podem ser pesadas, especialmente se o caminho da propriedade for longo. Imagine guardar contra um nulo em algum lugar em um caminho de propriedade longo como abcd

    O operador Angular “Elvis” (?.) É uma maneira mais fluente e conveniente de se proteger contra nulos em caminhos de propriedade. A expressão é suspensa quando atinge o primeiro valor nulo. A canvas está em branco, mas o aplicativo continua rolando e não há erros.

    The null hero's name is {{nullHero?.firstName}}

    Ele funciona perfeitamente com caminhos de propriedade longos também:

    a?.b?.c?.d

    EDIT: A equipe angular lançou o decorador @Resolve. Ele ainda precisa de algum esclarecimento, em como funciona, mas até lá eu vou pegar a resposta relacionada de outra pessoa aqui, e fornecer links para outras fonts:

    • StackOverflow: usando resolver em rotas Angular2
    • StackOverflow: Amostra de uso por Günter Zöchbauer
    • Resolver documentação
    • O patch do roteador no GitHub
    • RC4 ChangeLog
    • Lançamento RC4 Tweet

    EDIT: esta resposta funciona apenas para Angular 2 BETA. O roteador não é liberado para o Angular 2 RC a partir desta edição. Em vez disso, ao usar o Angular 2 RC, substitua as referências ao router-deprecated para continuar usando o roteador beta.

    A maneira futura do Angular2 de implementar isso será através do decorador @Resolve. Até lá, o fac-símile mais próximo é o decorador do componente CanActivate , por Brandon Roberts. veja https://github.com/angular/angular/issues/6611

    Embora o beta 0 não suporte o fornecimento de valores resolvidos para o componente, ele é planejado e há também uma solução descrita aqui: Usando as rotas de resolver em Angular2

    Um exemplo do beta 1 pode ser encontrado aqui: http://run.plnkr.co/BAqA98lphi4rQZAd/#/resolved . Ele usa uma solução alternativa muito semelhante, mas usa um pouco mais precisamente o object RouteData vez de RouteParams .

     @CanActivate((to) => { return new Promise((resolve) => { to.routeData.data.user = { name: 'John' } 

    Além disso, observe que há também uma solução alternativa para acessar valores “resolvidos” de rota aninhada / pai e outros resources que você espera se tiver usado o 1.x UI-Router.

    Observe que você também precisará injetar manualmente quaisquer serviços necessários para realizar isso, pois a hierarquia do Injetor Angular não está disponível no momento no decorador CanActivate. Simplesmente importar um Injector criará uma nova instância de injetor, sem access aos provedores de bootstrap() , então você provavelmente desejará armazenar uma cópia de todo o aplicativo do injetor bootstrap. O segundo link do Brandon em Plunk nesta página é um bom ponto de partida: https://github.com/angular/angular/issues/4112

    Definir um valor local com o observador

    … também, não se esqueça de inicializar o valor com dados fictícios para evitar erros uninitialized .

     export class ModelService { constructor() { this.mode = new Model(); this._http.get('/api/v1/cats') .map(res => res.json()) .subscribe( json => { this.model = new Model(json); }, error => console.log(error); ); } } 

    Isso pressupõe Model, é um modelo de dados que representa a estrutura de seus dados.

    Modelo sem parâmetros deve criar uma nova instância com todos os valores inicializados (mas vazios). Dessa forma, se o modelo renderizar antes de os dados serem recebidos, ele não lançará um erro.

    Idealmente, se você quiser persistir os dados para evitar requisições http desnecessárias, você deve colocar isso em um object que tenha seu próprio observador no qual você possa se inscrever.

    Implemente o routerOnActivate no seu @Component e retorne sua promise:

    https://angular.io/docs/ts/latest/api/router/OnActivate-interface.html

    EDIT: Isso explicitamente não funciona, embora a documentação atual pode ser um pouco difícil de interpretar sobre esse tópico. Veja o primeiro comentário de Brandon aqui para mais informações: https://github.com/angular/angular/issues/6611

    EDIT: As informações relacionadas sobre o site Auth0 de outra maneira geralmente precisas não estão corretas: https://auth0.com/blog/2016/01/25/angular-2-series-part-4-component-router-in- profundidade/

    EDIT: A equipe angular está planejando um decorador @Resolve para essa finalidade.

    Uma boa solução que eu encontrei é fazer na interface do usuário algo como:

     
    ...Your page...

    Somente quando: vendorServicePricing , quantityPricing e service são carregados, a página é renderizada.

    Eu estou usando o Angular 6 com o Universal add-on Eu li as respostas especialmente o segundo. Mas eu não entendi o ponto ainda. Eu tenho um resolvedor que chama e HttpClient XHR solicitar e enviar para o componente e o componente no ngOnInit vinculará dados para o modo de exibição. Mas o problema está no modo de fonte de visualização, não há dados da resposta XHR que é exibida na visão.

    Uma correção fácil é inicializar as propriedades do object no init / construtor

    cats.captchans.funniest

    Uma vez que a promise seja resolvida, ela vinculará os valores reais.