Angular 4 - Pass an object from one component to another (no parent - child hierarchy)

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-04 04:51:23

I solved the problem by passing the id of the object of the tile that was clicked as in the navigation extras of the route and then use a service in the detail component to fetch the object based on the id passed through the route.

I will provide the code below so hopefully nobody has to go through all of this ever again.

The component showing the tiles that can be clicked in order to see the details of the object they contain:

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

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

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

the detail component that receives the object that was clicked on

  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();
  }

The 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);
      }
  }

Please Try with below sample:

Step 1: Create 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)
  }
}

Step 2: Set value in login component

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); 
  } 
}

Step 3 : Get value in another component

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);
    });
  }
 }

Note: On page refresh the value will lost.

Using service first you create one funtion on service. call that funtion and use subject to other component. write this code

 this.handleReq.handlefilterdata.subscribe(() => {
                this.ngDoCheck(); 
            });

here, handleReq is service. handlefilterdata is rxjs subject.

try like this :

try to subscribe this.sharedPropertyService.propertyToDisplay instead of this.sharedPropertyService.getPropertyToDisplay()

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

and send the object like below :

editPropertyDetails(property: Property) {
    this.sharedPropertyService.setPropertyToDisplay(property);
}
Prashanti.D

I was working on similar functionality and came across same issue(as undefined). You could initialize like this.

public propertyToDisplay = new BehaviorSubject<Property>(undefined);

After making a change like this. I am able to get the value from Observable in service file and as well as in the component where I am trying to use this service.

JBoothUA

What does your console output? Is this.property ever set on the child component?

I would try to get rid of this function:

getPropertyToDisplay(): Observable<Property>

And try to just access propertyToDisplay directly.

Also .navigate can take data as a second param, so you might try passing the data in the route change.

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

  ngOnInit() {
    this.property = this.route
      .variableYouPassedIntoNavigator
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!