One place for hosting & domains

      Comment utiliser ViewChild dans Angular pour accéder à un composant enfant, à une directive ou un élément DOM


      Introduction

      Dans cet article, vous allons vous expliquer ce qu’est un décorateur ViewChild d’Angular.

      Il se peut que dans certaines situations vous souhaitiez accéder à une directive, un composant enfant ou un élément DOM à partir d’une catégorie de composants parent. Le décorateur ViewChild renvoie le premier élément qui correspond à un sélecteur de référence de directive, de composant ou de modèle donné.

      Utilisation de ViewChild avec des directives

      ViewChild permet d’accéder aux directives.

      Supposons que nous ayons une SharkDirective.

      L’idéal serez que vous puissiez utiliser @angular/cli pour générer votre directive :

      • ng generate directive shark

      Ou alors, il vous faudra l’ajouter manuellement à app.module.ts :

      app.module.ts

      import { SharkDirective } from './shark.directive';
      ...
      @NgModule({
        declarations: [
          AppComponent,
          SharkDirective
        ],
        ...
      })
      

      Notre directive recherchera les éléments avec l’attribut appShark et ajoutera le texte dans l’élément avec le terme Shark :

      shark.directive.ts

      import {
        Directive,
        ElementRef,
        Renderer2
      } from '@angular/core';
      
      @Directive(
        { selector: '[appShark]' }
      )
      export class SharkDirective {
        creature="Dolphin";
      
        constructor(elem: ElementRef, renderer: Renderer2) {
          let shark = renderer.createText('Shark ');
          renderer.appendChild(elem.nativeElement, shark);
        }
      }
      

      Ensuite, nous allons ajouter un Shark à Fin en l’utilisant dans le modèle de composant :

      app.component.html

      <span appShark>Fin!</span>
      

      Lorsque vous visualiserez l’application dans un navigateur, l’affichage sera le suivant :

      Output

      Shark Fin!

      Maintenant, nous pouvons accéder à la variable d’instance creature de SharkDirective. Elle configurera une variable extraCreature avec sa valeur :

      app.component.ts

      import {
        Component,
        ViewChild,
        AfterViewInit
      } from '@angular/core';
      import { SharkDirective } from './shark.directive';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.css']
      })
      export class AppComponent implements AfterViewInit {
        extraCreature: string;
      
        @ViewChild(SharkDirective)
        set appShark(directive: SharkDirective) {
          this.extraCreature = directive.creature;
        };
      
        ngAfterViewInit() {
          console.log(this.extraCreature); // Dolphin
        }
      }
      

      Ici, nous avons utilisé une méthode de réglage pour configurer la variable extraCreature. Notez que nous attendons que le hook de cycle de vie AfterViewInit ait accès à notre variable, car c’est à ce moment-là que les composants et les directives enfant seront disponibles.

      Lorsque nous consultons l’application dans un navigateur, nous voyons encore apparaître "Shark Fin!" . Cependant, dans le journal de la console, il s’affichera de la manière suivante :

      Output

      Dolphin

      Le composant parent a pu accéder à la valeur depuis la directive.

      Utilisation de ViewChild avec les éléments DOM

      ViewChild permet d’accéder aux éléments DOM natifs qui ont une variable de référence de modèle.

      Supposons que nous ayons un <input> dans notre modèle avec la variable de référence #someInput :

      app.component.html

      <input #someInput placeholder="Your favorite sea creature">
      

      Maintenant, nous pouvons accéder à <input> avec ViewChild et configurer la value :

      app.component.ts

      import {
        Component,
        ViewChild,
        AfterViewInit,
        ElementRef
      } from '@angular/core';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.css']
      })
      export class AppComponent implements AfterViewInit {
        @ViewChild('someInput') someInput: ElementRef;
        ngAfterViewInit() {
          this.someInput.nativeElement.value="Whale!";
        }
      }
      

      Lorsque ngAfterViewInit se déclenche, la valeur de notre <input> sera configurée :

      Output

      Whale!

      Le composant parent a réussi à configurer la valeur de l’élément DOM enfant.

      Utilisation de ViewChild avec des composants enfant

      ViewChild permet d’accéder à un composant enfant et appeler des méthodes ou d’accéder à des variables d’instance qui sont disponibles pour l’enfant.

      Supposons que nous ayons un ChildComponent. L’idéal serez que vous puissiez utiliser @angular/cli pour générer votre composant :

      • ng generate component child --flat

      Ou alors, il vous faudra créer les fichiers child.component.css et child.component.html et l’ajouter manuellement à app.module.ts :

      app.module.ts

      import { ChildComponent } from './child.component';
      ...
      @NgModule({
        declarations: [
          AppComponent,
          ChildComponent
        ],
        ...
      })
      

      Nous allons ajouter une méthode whoAmI à ChildComponent qui renverra le message suivant :

      child.component.ts

      whoAmI() {
        return 'I am a child component!';
      }
      

      Ensuite, nous allons référencer le composant dans notre modèle d’application :

      app.component.html

      <app-child>child works!</app-child>
      

      Maintenant, nous pouvons appeler la méthode whoAmI de notre catégorie de composants parent avec ViewChild de la manière suivante :

      app.component.ts

      import {
        Component,
        ViewChild,
        AfterViewInit
      } from '@angular/core';
      import { ChildComponent } from './child.component';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.css'],
      })
      export class AppComponent implements AfterViewInit {
        @ViewChild(ChildComponent) child: ChildComponent;
        ngAfterViewInit() {
          console.log(this.child.whoAmI()); // I am a child component!
        }
      }
      

      Lorsque vous visualiserez l’application dans un navigateur, le journal de la console s’affichera :

      Output

      I am a child component!

      Le composant parent a réussi à appeler la méthode whoAmI du composant enfant.

      Conclusion

      Vous avez appris à utiliser ViewChild pour accéder à une directive, à un composant enfant et à un élément DOM dans une catégorie de composants parent.

      Si la référence est remplacée de manière dynamique par un nouvel élément, ViewChild mettra à jour automatiquement sa référence.

      Dans le cas où vous souhaitez accéder à plusieurs composants enfant, utilisez plutôt ViewChildren.

      Si vous souhaitez en savoir plus sur Angular, consultez notre page thématique Angular pour des exercices et des projets de programmation.



      Source link

      Comment utiliser les paramètres de requête dans Angular


      Introduction

      Dans Angular, les paramètres de requête permettent de faire passer des paramètres optionnels par n’importe quel itinéraire dans l’application. Les paramètres de requête sont différents des paramètres d’itinéraire ordinaires, qui ne sont disponibles que sur un seul itinéraire et ne sont pas facultatifs (par exemple, /product/:id).

      Dans cet article, nous ferons référence à un exemple d’application qui affiche une liste de produits. Nous fournirons des valeurs order et price-range facultatives, que l’élément récepteur pourra lire et sur lesquelles il pourra agir. Les valeurs fournies affecteront l’ordre et le filtrage de la liste de produits.

      Utiliser les paramètres de requête avec Router.navigate

      Si vous naviguez vers l’itinéraire en utilisant impérativement Router.navigate, vous passerez dans les paramètres de requête avec queryParams.

      Dans notre exemple, si nous voulons guider les visiteurs vers les produits grâce à une liste ordonnée par popularité, cela donnerait quelque chose comme :

      goProducts() {
        this.router.navigate(["https://www.digitalocean.com/products"], { queryParams: { order: 'popular' } });
      }
      

      Cela donnera lieu à une URL ressemblant à celle-ci :

      http://localhost:4200/products?order=popular
      

      Il est également possible de fournir plusieurs paramètres de requête. Dans notre exemple, si nous voulons guider les visiteurs vers les produits grâce à une liste ordonnée par popularité et filtrée en fonction d’une fourchette de prix élevée, cela ressemblerait à ceci :

      goProducts() {
        this.router.navigate(["https://www.digitalocean.com/products"], { queryParams: { order: 'popular', 'price-range': 'not-cheap' } });
      }
      

      Cela donnera lieu à une URL ressemblant à celle-ci :

      http://localhost:4200/products?order=popular&price-range=not-cheap
      

      Vous avez désormais une idée claire de la façon dont queryParams peut être utilisé pour définir les paramètres de requête.

      Préserver ou fusionner les paramètres de requête avec queryParamsHandling

      Par défaut, les paramètres de requête sont perdus sur toute action de navigation ultérieure. Pour éviter que cela se produise, vous pouvez faire en sorte que queryParamsHandling les 'preserve' ou les 'merge'.

      Dans notre exemple, si nous voulons guider les visiteurs depuis une page avec le paramètre de requête { order: 'popular' } jusqu’à la page /users tout en conservant les paramètres de la requête, nous utiliserons 'preserve':

      goUsers() {
        this.router.navigate(['/users'], { queryParamsHandling: 'preserve' });
      }
      

      Cela donnera lieu à une URL ressemblant à celle-ci :

      http://localhost:4200/users?order=popular
      

      Dans notre exemple, si nous voulons guider les visiteurs depuis une page avec le paramètre de requête { order: 'popular' } jusqu’à la page /users en admettant le paramètre de requête { filter : 'new' }, nous utiliserons 'merge' :

      goUsers() {
        this.router.navigate(['/users'], { queryParams: { filter: 'new' }, queryParamsHandling: 'merge' });
      }
      

      Cela donnera lieu à une URL ressemblant à celle-ci :

      http://localhost:4200/users?order=popular&filter=new
      

      Remarque : la préservation des paramètres de requête se faisait auparavant avec preserveQueryParams réglé sur true, mais cela est maintenant déprécié dans Angular 4+ en faveur de queryParamsHandling.

      Vous avez désormais une idée claire de la façon dont queryParamsHandling peut être utilisé pour préserver ou fusionner les paramètres de requête.

      Dans notre exemple, si vous utilisez plutôt la directive RouterLink pour naviguer vers l’itinéraire, vous utiliserez queryParams de cette manière :

      <a [routerLink]="["https://www.digitalocean.com/products"]" [queryParams]="{ order: 'popular'}">
        Products
      </a>
      

      Et dans notre exemple, si vous souhaitez 'preserve' ou 'merge' les paramètres de requête lors d’une navigation ultérieure, vous utiliserez la fonction queryParamsHandling de cette manière :

      <a [routerLink]="['/users']"
         [queryParams]="{ filter: 'new' }"
         queryParamsHandling="merge">
        Users
      </a>
      

      Vous savez désormais comment queryParams et queryParamsHandling peuvent être utilisés avec RouterLink.

      Accéder aux valeurs des paramètres de requête

      Maintenant que nous savons comment faire adopter des paramètres de requête facultatifs à un itinéraire, voyons comment accéder à ces valeurs sur les itinéraires résultants. La classe ActivatedRoute dispose d’une propriété queryParams qui renvoie un compte-rendu des paramètres de requêtes disponibles dans l’URL en cours.

      Compte tenu de l’URL de l’itinéraire suivante :

      http://localhost:4200/products?order=popular
      

      Nous pouvons accéder au paramètre de requête order de cette manière :

      // ...
      import { ActivatedRoute } from '@angular/router';
      import 'rxjs/add/operator/filter';
      
      @Component({ ... })
      export class ProductComponent implements OnInit {
        order: string;
        constructor(private route: ActivatedRoute) { }
      
        ngOnInit() {
          this.route.queryParams
            .filter(params => params.order)
            .subscribe(params => {
              console.log(params); // { order: "popular" }
      
              this.order = params.order;
              console.log(this.order); // popular
            }
          );
        }
      }
      

      Dans le journal de la console, nous verrions l’objet params :

      Output

      { order: "popular" }

      Ainsi que la valeur params.order :

      Output

      popular

      Il y a aussi queryParamMap, qui renvoie un compte-rendu avec un objet paramMap.

      Compte tenu de l’URL de l’itinéraire suivante :

      http://localhost:4200/products?order=popular&filter=new
      

      Nous pouvons accéder au paramètre de requête de cette manière :

      this.route.queryParamMap
        .subscribe((params) => {
          this.orderObj = { ...params.keys, ...params };
        }
      );
      

      Ici, nous avons utilisé l’opérateur de diffusion d’objet, et voici la forme résultante des données dans orderObj :

      {
        "0": "order",
        "1": "filter",
        "params": {
          "order": "popular",
          "filter": "new"
        }
      }
      

      Vous savez désormais comment queryParams et queryParamMap peuvent être utilisés pour accéder à des valeurs sur les itinéraires ainsi obtenus.

      Conclusion

      Dans cet article, vous avez utilisé différents exemples pour définir et obtenir des paramètres de requête dans Angular. Vous avez été initié à queryParams et queryParamsHandling avec Router.navigate et RouterLink. Vous avez également été initié à queryParams et queryParamMap avec ActivatedRoute.

      Si vous souhaitez en savoir plus sur Angular, consultez notre page thématique Angular pour des exercices et des projets de programmation.



      Source link

      Quatre méthodes de recherche dans les tableaux en JavaScript


      Il existe de nombreux moyens permettant de trouver des objets dans Arrays en JavaScript. Vous pouvez toujours recourir à la basique for pour boucler, mais avec l’ES6+, il existe de nombreuses méthodes pour boucler le tableau et trouver facilement ce dont vous avez besoin.

      Avec autant de méthodes différentes, laquelle utilisez-vous et dans quel cas ? Par exemple, lorsque vous effectuez une recherche dans un tableau, voulez-vous savoir si l’élément se trouve dans le tableau ? Avez-vous besoin de l’index de l’élément ou de l’élément lui-même ?

      Pour chaque méthode différente que nous aborderons, il est important de comprendre qu’il s’agit de méthodes intégrées au prototype Array. Cela signifie que vous devez simplement les enchaîner sur n’importe quel tableau avec la notation par points. Cela signifie également que ces méthodes ne sont pas disponibles sur les objets ou tout autre objet que les Arrays (bien qu’il y ait un chevauchement avec les Strings).

      Nous allons examiner les méthodes Array suivantes :

      includes

      const alligator = ["thick scales", 80, "4 foot tail", "rounded snout"];
      
      alligator.includes("thick scales"); // returns true
      

      La méthode .includes() renvoie une valeur booléenne et est parfaite pour vous indiquer si un élément existe ou non dans un tableau. Elle vous offre simplement réponse true ou false. Ceci est la syntaxe de base :

      arr.includes(valueToFind, [fromIndex]);
      

      Or, comme vous le voyez dans notre exemple, nous n’avions qu’un seul paramètre : la valeur ToFind. C’est la valeur à faire correspondre dans le tableau. L’optionnelle fromIndex est un nombre, indiquant à partir de quel index vous voulez commencer à chercher (la valeur par défaut est 0, donc le tableau entier est inspecté). Ainsi, puisque dans notre exemple, l’élément “thick scales” est à l’index 0, ce qui suit serait faux : alligator.includes('thick scales', 1) ; puisqu’il commence la recherche à partir de l’index 1 et plus.

      Il y a toutefois quelques points importants à noter. Cette méthode .includes() utilise une comparaison stricte. Cela signifie, d’après l’exemple ci-dessus, que le résultat suivant serait faux : alligator.includes('80') ; en effet, si 80 == '80' est vrai, 80 === '80' est faux : les différents types ne se prêtent pas à une comparaison stricte.

      find

      En quoi .find() est-elle différente de la méthode includes() ? Si, dans notre exemple, nous ne modifions que le texte “includes” pour le remplacer par “find”, nous obtiendrons cette erreur :

      Uncaught TypeError: thick scales is not a function
      

      C’est parce que la méthode find nécessite qu’une fonction soit admise. C’est parce que la méthode find ne va pas utiliser un simple opérateur de comparaison comme le fait “includes()”. À la place, il passera chaque élément dans votre fonction et verra si elle renvoie vrai ou faux. Donc, bien que cela fonctionne : alligator.find(() => 'thick scales');, vous voudrez probablement mettre votre propre opérateur de comparaison dans la fonction pour qu’elle renvoie tout ce qui est pertinent.

      const alligator = ["thick scales", 80, "4 foot tail", "rounded snout"];
      
      alligator.find(el => el.length < 12); // returns '4 foot tail'
      

      Cette fonction simple de notre méthode find examine chaque élément du tableau, avec l’alias “el” que nous lui avons attribué, et s’arrête lorsqu’elle trouve le premier élément qui est vrai. Dans notre cas, ce qui est vrai doit avoir une propriété de longueur inférieure à 12 (les nombres n’ont pas de propriété de longueur). Vous pouvez bien sûr rendre cette fonction aussi complexe que nécessaire, en faisant en sorte que votre condition true réponde à vos besoins.

      Remarquez également que cela n’a pas été renvoyé comme true. La méthode find ne renvoie pas un booléen mais le premier élément correspondant. S’il n’y a pas d’élément correspondant – car il n’existe rien qui réponde aux critères définis dans votre fonction – elle renverra undefined. Notez également qu’elle renvoie le premier, donc s’il y a plus d’un élément dans le tableau qui répond aux critères, elle ne prendra que la première instance. Dans notre exemple, s’il y avait une autre chaîne de moins de 12 après “4 feet tall”, cela ne changerait pas notre résultat.

      Dans notre exemple, nous avons utilisé le callback avec un paramètre seulement. Vous pouvez également ajouter des paramètres pour référencer l’index de l’élément en cours. L’ensemble du tableau lui-même peut être un autre paramètre mais je trouve que cela est rarement utilisé. Voici un exemple utilisant l’index :

      alligator.find((el, idx) => typeof el === "string" && idx === 2); // returns '4 foot tall'
      

      Nous savons que, dans notre tableau, 3 éléments différents remplissent la première condition (typeof el === ‘string’). Si c’était notre seule condition, elle nous renverrait la première, “thick scales”. Mais la différence, c’est qu’un seul d’entre eux a un indice de 2 qui signifie “4 foot tall”.

      En parlant d’index,.findIndex() est une méthode de tableau similaire. Cette méthode reçoit également une fonction, mais comme vous pouvez le deviner, elle renvoie l’index de l’élément correspondant au lieu de l’élément lui-même.

      indexOf

      const alligator = ["thick scales", 80, "4 foot tail", "rounded snout"];
      
      alligator.indexOf("rounded snout"); // returns 3
      

      De la même manière que la méthode .includes(), la méthode .indexOf() utilise une comparaison stricte et non une fonction comme nous l’avons vu avec la méthode .find(). Cependant, contrairement à includes(), elle renvoie l’index de l’élément plutôt qu’un booléen. Vous pouvez également indiquer à partir de quel index du tableau la recherche doit débuter.

      Je trouve la méthode indexOf() très utile. Elle est simple et rapide, peut vous dire où se trouve l’élément dans le tableau et peut également vous dire si l’élément existe. Comment vous indique-t-elle si l’élément existe ? Fondamentalement, nous pouvons savoir que l’élément existe si elle renvoie un nombre positif ; si elle renvoie -1, nous savons que l’élément n’existe pas.

      alligator.indexOf("soft and fluffy"); // returns -1
      alligator.indexOf(80); // returns 1
      alligator.indexOf(80, 2); // returns -1
      

      Et comme vous pouvez le voir, bien que nous aurions pu utiliser les méthodes find() ou findIndex() pour obtenir les mêmes informations, celle-ci est beaucoup moins longue à écrire. Nous n’avons pas besoin d’écrire une fonction pour la comparaison, car elle se trouve déjà dans la méthode indexOf.

      Cependant, comme les autres, indexOf() renvoie également l’index du premier élément correspondant qu’elle trouve. JavaScript nous donne une méthode de tableau alternative .lastIndexOf(). Comme vous pouvez le deviner, elle fait la même chose que indexOf() mais en partant du dernier index du tableau et en travaillant à rebours. Vous pouvez également spécifier un second paramètre, mais n’oubliez pas que les index ne changent pas simplement parce que vous utilisez une méthode différente.

      const alligator = ["thick scales", 80, "4 foot tail", "rounded snout", 80];
      
      alligator.indexOf(80); // returns 1
      alligator.lastIndexOf(80); // returns 4
      alligator.indexOf(80, 2); // returns 4
      alligator.lastIndexOf(80, 4); // returns 4
      alligator.lastIndexOf(80, 3); // returns 1
      

      Bonus : filter

      const alligator = ["thick scales", 80, "4 foot tail", "rounded snout", 80];
      
      alligator.filter(el => el === 80); //returns [80, 80]
      

      La méthode filter() est semblable à la méthode find(), en ce sens qu’elle nécessite une fonction passée et une condition pour ce qui sera renvoyé. La principale différence est que filter() renvoie toujours un tableau, même s’il n’y a qu’un seul élément correspondant. Mais elle renvoie tous les éléments correspondants, alors que find() ne renvoie que la première correspondance.

      La chose importante à savoir sur la méthode filter est qu’elle renvoie tous les éléments correspondant à vos critères. Cela ne concerne peut-être que moi, mais il est probable que je m’emmêle les pinceaux en pensant “ce sont les éléments que je veux filtrer en out”, alors qu’en vérité, vous indiquez les éléments que vous souhaitez filtrer en in.

      Conclusion

      D’après moi, la méthode la plus simple à utiliser quand on cherche quelque chose, est la méthode find(), mais comme vous pouvez le voir, cela dépend vraiment de votre cas.

      • Vous avez uniquement besoin de savoir si l’élément existe ? Dans ce cas, utilisez .includes().
      • Vous avez besoin d’obtenir l’élément lui-même ? Utilisez .find() ou .filter() pour plusieurs éléments.
      • Vous avez besoin de trouver l’index de l’élément ? Dans ce cas, utilisez .indexOf() ou findIndex() pour une recherche plus complexe.

      Les tableaux présentés dans les exemples ci-dessus étaient très simples. Vous pourriez vous retrouver avec un tableau d’objects. Voici quelques exemples très simples pour naviguer dans la jungle des objets imbriqués :

      const jungle = [
        { name: "frog", threat: 0 },
        { name: "monkey", threat: 5 },
        { name: "gorilla", threat: 8 },
        { name: "lion", threat: 10 }
      ];
      
      // break the object down in order to use .includes() or .indexOf()
      const names = jungle.map(el => el.name); // returns ['frog', 'monkey', 'gorilla', 'lion']
      console.log(names.includes("gorilla")); // returns true
      console.log(names.indexOf("lion")); // returns 3 - which corresponds correctly assuming no sorting was done
      
      // methods we can do on the array of objects
      console.log(jungle.find(el => el.threat == 5)); // returns object - {name: "monkey", threat: 5}
      console.log(jungle.filter(el => el.threat > 5)); // returns array - [{name: "gorilla", threat: 8}, {name: 'lion', threat: 10}]
      



      Source link