web-dev-qa-db-fra.com

Angular 4 - Passe un objet d’un composant à un autre (pas de hiérarchie parent - enfant)

Ma situation:

J'ai un composant affichant des mosaïques, chaque mosaïque représentant un objet d'un tableau auquel on a ajouté un ngfor . Quand je clique sur une mosaïque, je souhaite transmettre l'objet à un autre composant, responsable de l'affichage de toutes les propriétés de cet objet dans les champs qui peuvent être modifiés.

Ce que j'ai essayé:

Après avoir effectué des recherches et découvert plusieurs messages me montrant comment y parvenir pour une hiérarchie parent-enfant et certains expliquant qu’il est nécessaire d’utiliser un service partagé pour obtenir la fonctionnalité recherchée, j’ai décidé de mettre en place un tel système. un service.

Cependant, ce que je ne semble pas avoir, c'est quand je devrais naviguer vers un itinéraire différent. Il semble que la navigation trouve sa place trop tôt car l'objet transmis au service n'est pas défini lors de l'extraction dans le composant de détail.

Mon code:

Le composant affichant les tuiles a la fonction suivante pour transmettre l'objet sur lequel le clic a été fait au service partagé:

editPropertyDetails(property: Property) {
    console.log('Edit property called');

    return new Promise(resolve => {
      this.sharedPropertyService.setPropertyToDisplay(property);
      resolve();
    }).then(
      () => this.router.navigate(['/properties/detail'])
    )
  }

Le service partagé a une fonction pour définir un objet de propriété et un pour le récupérer et se présente comme suit:

@Injectable()
export class SharedPropertyService {
  // Observable
  public propertyToDisplay = new Subject<Property>();

  constructor( private router: Router) {}

  setPropertyToDisplay(property: Property) {
    console.log('setPropertyToDisplay called');
    this.propertyToDisplay.next(property);
  }

  getPropertyToDisplay(): Observable<Property> {
    console.log('getPropertyToDisplay called');
    return this.propertyToDisplay.asObservable();
  }
}

Enfin, le composant de détail qui doit recevoir l'objet sur lequel l'utilisateur a cliqué mais obtient un objet indéfini:

export class PropertyDetailComponent implements OnDestroy {

  property: Property;
  subscription: Subscription;

  constructor(private sharedPropertyService: SharedPropertyService) {
        this.subscription = this.sharedPropertyService.getPropertyToDisplay()
          .subscribe(
            property => { this.property = property; console.log('Detail Component: ' + property.description);}
          );
  }

  ngOnDestroy() {
    // When view destroyed, clear the subscription to prevent memory leaks
    this.subscription.unsubscribe();
  }
}

Merci d'avance!

6
DennisN

J'ai résolu le problème en transmettant l'identifiant de l'objet de la tuile sur lequel vous avez cliqué, comme dans les extras de navigation de l'itinéraire, puis en utilisant un service dans le composant de détail pour récupérer l'objet en fonction de l'identifiant transmis par l'itinéraire.

Je vais fournir le code ci-dessous, donc j'espère que plus personne ne devra subir tout cela à nouveau.

Le composant montrant les tuiles sur lesquelles on peut cliquer afin de voir les détails de l'objet qu'elles contiennent:

  editPropertyDetails(property: Property) {
    console.log('Edit property called');

    let navigationExtras: NavigationExtras = {
            queryParams: {
                "property_id": property.id
            }
        };

    this.router.navigate(['/properties/detail'], navigationExtras);
  }

le composant de détail recevant l'objet sur lequel l'utilisateur a cliqué

  private sub: any;
  propertyToDisplay: Property;

  constructor
  (
    private sharedPropertyService: SharedPropertyService,
    private router: Router,
    private route: ActivatedRoute
  ) {}

  ngOnInit() {
  this.sub = this.route.queryParams.subscribe(params => {
        let id = params["property_id"];

        if(id) {
          this.getPropertyToDisplay(id);
        }

    });
  }

  getPropertyToDisplay(id: number) {
    this.sharedPropertyService.getPropertyToDisplay(id).subscribe(
            property => {
              this.propertyToDisplay = property;
            },
            error => console.log('Something went wrong'));
  }

  // Prevent memory leaks
  ngOnDestroy() {
    this.sub.unsubscribe();
  }

Le service

  properties: Property[];

  constructor( private propertyService: PropertyService) {}

  public getPropertyToDisplay(id: number): Observable<Property> {
    if (this.properties) {
      return this.findPropertyObservable(id);
    } else {
            return Observable.create((observer: Observer<Property>) => {
                this.getProperties().subscribe((properties: Property[]) => {
                    this.properties = properties;
                    const prop = this.filterProperties(id);
                    observer.next(prop);
                    observer.complete();
                })
            }).catch(this.handleError);
    }
  }

  private findPropertyObservable(id: number): Observable<Property> {
    return this.createObservable(this.filterProperties(id));
  }

  private filterProperties(id: number): Property {
        const props = this.properties.filter((prop) => prop.id == id);
        return (props.length) ? props[0] : null;
    }

  private createObservable(data: any): Observable<any> {
        return Observable.create((observer: Observer<any>) => {
            observer.next(data);
            observer.complete();
        });
    }

  private handleError(error: any) {
      console.error(error);
      return Observable.throw(error.json().error || 'Server error');
  }

  private getProperties(): Observable<Property[]> {
    if (!this.properties) {
    return this.propertyService.getProperties().map((res: Property[]) => {
      this.properties = res;
      console.log('The properties: ' + JSON.stringify(this.properties));
      return this.properties;
    })
      .catch(this.handleError);
    } else {
      return this.createObservable(this.properties);
      }
  }
3
DennisN

Veuillez essayer avec l'échantillon ci-dessous:

Étape 1: Créer un service [DataService]

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class DataService {
  private userIdSource = new BehaviorSubject<number>(0);
  currentUser = this.userIdSource.asObservable();

  private orderNumSource = new BehaviorSubject<number>(0);
  currentOrder = this.orderNumSource.asObservable();

  constructor() { }

  setUser(userid: number) {
    this.userIdSource.next(userid)
  }

   setOrderNumber(userid: number) {
    this.orderNumSource.next(userid)
  }
}

Étape 2: Définir la valeur dans le composant de connexion

import { Component } from '@angular/core';
import { DataService } from "../services/data.service";

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css'] 
})
export class LoginComponent {
  constructor( private dataService:DataService) {     }
   onSubmit() {
        this.dataService.setUser(1); 
  } 
}

Étape 3: Obtenir de la valeur dans un autre composant

import { Component, OnInit } from '@angular/core';
import { DataService } from "../services/data.service";

@Component({
  selector: 'app-shopping-cart',
  templateUrl: './shopping-cart.component.html',
  styleUrls: ['./shopping-cart.component.css']
})
export class ShoppingCartComponent implements OnInit {
  userId: number = 0;
  constructor(private dataService: DataService) { }
  ngOnInit() {
    this.getUser();
 }
  getUser() {
    this.dataService.currentUser.subscribe(user => {
      this.userId = user
    }, err => {
      console.log(err);
    });
  }
 }

Remarque : Sur la page d'actualisation, la valeur sera perdue.

2
Sanjay Katiyar

que sort votre console? this.property est-il déjà défini sur le composant enfant?

Je voudrais essayer de me débarrasser de cette fonction

getPropertyToDisplay (): observable

et essayez d’accéder directement à propertyToDisplay.

également .navigate peut prendre les données en tant que deuxième paramètre, vous pouvez donc essayer de transmettre les données lors du changement de route.

constructor(
    private route: ActivatedRoute,
    private router: Router) {}

  ngOnInit() {
    this.property = this.route
      .variableYouPassedIntoNavigator
0
JBoothUA

essayez comme ça:

essayez de vous abonner this.sharedPropertyService.propertyToDisplay au lieu de this.sharedPropertyService.getPropertyToDisplay()

this.sharedPropertyService.propertyToDisplay.subscribe((property) => {
    this.property = property;
    console.log('Detail Component: ' + property.description);
});

et envoyez l'objet comme ci-dessous:

editPropertyDetails(property: Property) {
    this.sharedPropertyService.setPropertyToDisplay(property);
}
0
Chandru