Dans Angular 1.x, UI-Router était mon principal outil pour cela. En renvoyant une promesse pour les valeurs "résoudre", le routeur attendrait simplement que la promesse soit terminée avant de rendre les directives.
Sinon, dans Angular 1.x, un objet null ne plantera pas un modèle. Par conséquent, si un rendu temporairement incomplet ne me dérange pas, je peux simplement utiliser $digest
pour restituer après que promise.then()
ait rempli un objet modèle initialement vide.
Parmi les deux approches, si possible, je préférerais attendre pour charger la vue et annuler la navigation par route si la ressource ne peut pas être chargée. Cela me sauve le travail de "dé-navigation". EDIT: Notez que cela signifie spécifiquement que cette question demande une méthode compatible avec les futures ou angular 2 pour ce faire, et demande d’éviter si possible "l’opérateur Elvis"! Ainsi, je n'ai pas choisi cette réponse.
Cependant, aucune de ces deux méthodes ne fonctionne dans Angular 2.0. Il existe sûrement une solution standard prévue ou disponible pour cela. Est-ce que quelqu'un sait ce que c'est?
@Component() {
template: '{{cats.captchans.funniest}}'
}
export class CatsComponent {
public cats: CatsModel;
ngOnInit () {
this._http.get('/api/v1/cats').subscribe(response => cats = response.json());
}
}
La question suivante peut refléter le même problème: Modèle de rendu angulaire 2 après le chargement de la PROMISE avec les données . Notez que cette question n’a pas de code ni de réponse acceptée.
Le package @angular/router
a la propriété Resolve
pour les itinéraires. Ainsi, vous pouvez facilement résoudre les données avant de rendre une vue d'itinéraire.
Voir: https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html
Exemple tiré de la documentation à compter d'aujourd'hui, le 28 août 2017:
class Backend {
fetchTeam(id: string) {
return 'someTeam';
}
}
@Injectable()
class TeamResolver implements Resolve<Team> {
constructor(private backend: Backend) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<any>|Promise<any>|any {
return this.backend.fetchTeam(route.params.id);
}
}
@NgModule({
imports: [
RouterModule.forRoot([
{
path: 'team/:id',
component: TeamCmp,
resolve: {
team: TeamResolver
}
}
])
],
providers: [TeamResolver]
})
class AppModule {}
Désormais, votre itinéraire ne sera activé que lorsque les données auront été résolues et renvoyées.
Accès aux données résolues dans votre composant
Pour accéder aux données résolues depuis votre composant au moment de l'exécution, il existe deux méthodes. Donc, selon vos besoins, vous pouvez utiliser soit:
route.snapshot.paramMap
qui retourne une chaîne, ou le route.paramMap
qui renvoie un observable auquel vous pouvez .subscribe()
. Exemple:
// 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);
J'espère que ça aide.
Essayez {{model?.person.name}}
, cela devrait attendre que le modèle ne soit pas undefined
et ensuite le rendre.
Angular 2 désigne cette syntaxe ?.
en tant qu'opérateur Elvis . Il est difficile de s'y référer dans la documentation. En voici une copie au cas où ils changeraient/le déplaceraient:
Les chemins de propriétés Elvis Operator (?.) Et null
L'opérateur angulaire «Elvis» (?.) Est un moyen efficace et simple de se prémunir contre les valeurs nulles et non définies dans les chemins de propriétés. Voilà, la protection contre une vue rend échec si le currentHero est null.
The current hero's name is {{currentHero?.firstName}}
Expliquons le problème et cette solution particulière.
Que se passe-t-il lorsque la propriété title liée aux données suivante est null?
The title is {{ title }}
La vue est toujours restituée mais la valeur affichée est vide. nous voyons seulement "Le titre est" avec rien après. C'est un comportement raisonnable. Au moins, l'application ne plante pas.
Supposons que l’expression de modèle implique un chemin de propriété, comme dans l’exemple suivant, où nous affichons le prénom d’un héros nul.
The null hero's name is {{nullHero.firstName}}
JavaScript génère une erreur de référence nulle et Angular également:
TypeError: Cannot read property 'firstName' of null in [null]
Pire encore, la vue entière disparaît.
Nous pourrions affirmer qu'il s'agit d'un comportement raisonnable si nous pensions que la propriété du héros ne doit jamais être nulle. Si elle ne doit jamais être nulle et pourtant, elle est nulle, nous avons commis une erreur de programmation qui devrait être interceptée et corrigée. Lancer une exception est la bonne chose à faire.
D'autre part, les valeurs NULL dans le chemin de la propriété peuvent être correctes de temps en temps, en particulier lorsque nous savons que les données arriveront éventuellement.
Pendant que nous attendons des données, la vue doit être générée sans réclamation et le chemin de la propriété null doit être affiché aussi vierge que la propriété title.
Malheureusement, notre application se bloque lorsque le currentHero est null.
Nous pourrions coder ce problème avec NgIf
<!--No hero, div not displayed, no error -->
<div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>
Nous pouvons également essayer d’enchaîner des parties du chemin de la propriété avec &&, sachant que l’expression s’arrache quand elle rencontre le premier null.
The null hero's name is {{nullHero && nullHero.firstName}}
Ces approches ont du mérite, mais elles peuvent être lourdes, surtout si le chemin de la propriété est long. Imaginez que vous vous protégiez contre un null quelque part dans un chemin d'accès de propriété long tel que a.b.c.d.
L'opérateur angulaire «Elvis» (?.) Est un moyen plus fluide et plus pratique de se prémunir des valeurs nulles dans les chemins de propriété. L'expression échoue lorsqu'elle atteint la première valeur NULL. L'affichage est vide, mais l'application continue de rouler et il n'y a pas d'erreur.
<!-- No hero, no problem! -->
The null hero's name is {{nullHero?.firstName}}
Cela fonctionne aussi parfaitement avec les longs chemins de propriété:
a?.b?.c?.d
EDIT: L'équipe angulaire a sorti le décorateur @Resolve. Il faut encore des éclaircissements sur son fonctionnement, mais en attendant, je vais prendre la réponse connexe de quelqu'un d'autre ici et fournir des liens vers d'autres sources:
EDIT: Cette réponse ne fonctionne que pour Angular 2 BETA. Le routeur n'est pas disponible pour Angular 2 RC à la date de cette modification. Lorsque vous utilisez Angular 2 RC, remplacez plutôt les références à router
par router-deprecated
pour continuer à utiliser le routeur bêta.
Angular2-future sera implémenté via le décorateur @Resolve. Jusque-là, le fac-similé le plus proche est CanActivate
Décorateur de composants, selon Brandon Roberts. voir https://github.com/angular/angular/issues/6611
Bien que la version bêta 0 ne prenne pas en charge la fourniture de valeurs résolues au composant, cela est prévu et une solution de contournement est décrite ici: Utilisation de la résolution dans les itinéraires angulaires2
Un exemple de beta 1 peut être trouvé ici: http://run.plnkr.co/BAqA98lphi4rQZAd/#/resolved . Il utilise une solution de contournement très similaire, mais utilise légèrement plus précisément l'objet RouteData
plutôt que RouteParams
.
@CanActivate((to) => {
return new Promise((resolve) => {
to.routeData.data.user = { name: 'John' }
Notez également qu’il existe également un exemple de solution de contournement pour accéder aux valeurs "résolues" de la route parent/imbriquée, ainsi que d’autres fonctionnalités que vous attendez si vous avez utilisé 1.x UI-Router.
Notez que vous devrez également injecter manuellement les services nécessaires, car la hiérarchie de l'injecteur angulaire n'est actuellement pas disponible dans le décorateur CanActivate. Le simple fait d'importer un injecteur crée une nouvelle instance d'injecteur, sans accès aux fournisseurs de bootstrap()
; vous souhaiterez donc probablement stocker une copie de l'injecteur démarré à l'échelle de l'application. Le second lien Plunk de Brandon sur cette page est un bon point de départ: https://github.com/angular/angular/issues/4112
Définir une valeur locale avec l'observateur
... n'oubliez pas d'initialiser la valeur avec des données factices pour éviter les erreurs 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);
);
}
}
Ceci suppose que Modèle est un modèle de données représentant la structure de vos données.
Un modèle sans paramètre doit créer une nouvelle instance avec toutes les valeurs initialisées (mais vides). Ainsi, si le modèle est rendu avant la réception des données, il ne générera pas d'erreur.
Idéalement, si vous souhaitez conserver les données pour éviter les requêtes HTTP inutiles, vous devez les placer dans un objet disposant de son propre observateur auquel vous pouvez vous abonner.
Implémentez la routerOnActivate
dans votre @Component
et retournez votre promesse:
https://angular.io/docs/ts/latest/api/router/OnActivate-interface.html
EDIT: Cela ne fonctionne explicitement PAS, bien que la documentation actuelle puisse être un peu difficile à interpréter sur ce sujet. Voir le premier commentaire de Brandon ici pour plus d'informations: https://github.com/angular/angular/issues/6611
EDIT: les informations associées sur le site Auth0, qui est sinon généralement exact, ne sont pas correctes: https://auth0.com/blog/2016/01/25/angular-2-series-part-4-component-router- en profondeur/
EDIT: L’équipe angulaire prépare un décorateur @Resolve à cet effet.
Une solution intéressante que j'ai trouvée consiste à faire sur l'interface utilisateur quelque chose comme:
<div *ngIf="vendorServicePricing && quantityPricing && service">
...Your page...
</div
Seulement lorsque: vendorServicePricing
, quantityPricing
et service
sont chargés, la page est rendue.
j'utilise Angular 6 avec Universal Add-on J'ai lu les réponses spécialement la deuxième. Mais je n'ai pas encore compris le point. J'ai un résolveur qui appelle et demande HttpClient XHR et envoie au composant et le composant sur ngOnInit liera les données à la vue. Mais le problème réside dans le mode d'affichage de la source. Il n'y a pas de données provenant de la réponse XHR affichée dans la vue.