0

I trying some hands on in angular. I tried using the same component for edit as well create product. I used an if statement in the component to distinguish between the edit and create. But the code inside if doesn't get executed when the request url is http://localhost:4200/product/Edit/Redmond?edit=true. I have code to handle the route parameters. I removed it for brevity. I'm not sure what I'm missing here

export class ProductEditComponent implements OnInit {
isEdit= false;
uiProduct:ProductModel;
ngOnInit() {
this.activatedRoute.queryParams.subscribe(queryParams=>{
  this.isEdit=queryParams['edit']      
  console.log(this.isEdit); // it's true here for the Edit Route
})
if (this.isEdit ==true) {      
  this.productService.
    GetProductByName(this.name)
    .subscribe((response: ProductModel) => {
      this.uiProduct = response;          
    });
}
}
Raida Adn
  • 405
  • 1
  • 6
  • 17
  • 1
    You need to move the if logic inside this.activatedRoute.queryParams.subscribe – lissettdm Nov 08 '20 at 15:54
  • You can access the parameters both directly and not async But think carefully if it fits your case: this.activatedRoute.snapshot.queryParams... – Miri Gold Nov 11 '20 at 05:54

3 Answers3

0

this.activatedRoute.queryParams.subscribe is an async function, so your isEdit recieves a value only after you check it. You could move their into the subscribe method or await the subscribe..

audzzy
  • 721
  • 1
  • 4
  • 12
  • I moved the code of the ``if``` statement inside the subscribe but still the request for edit doesn't happen. And I don't know exactly how to await the subscribe – Raida Adn Nov 08 '20 at 11:56
  • does it enter the if? I think you may be comparinh the string "true" to the boolean value true.. `try if(this.isEdit =="true")` – audzzy Nov 08 '20 at 12:49
0

The isEdit variable is assigned asynchronously. For inter dependent observables you could use RxJS higher order mapping operators (like switchMap) to map between them and filter operator to emit only if the edit parameter is true.

Try the following

export class ProductEditComponent implements OnInit {
  uiProduct: ProductModel;

  ngOnInit() {
    this.activatedRoute.queryParams.pipe(
      filter((queryParams: any) => (!!queryParams['edit'])), // <-- proceed only if `edit` is true
      switchMap(_ => this.productService.GetProductByName(this.name))
    ).subscribe({
      next: (response: ProductModel) => {
        this.uiProduct = response;
      },
      error: (error: any) => {
        // handle error
      }
    });
  }
}

Update: use async query param elsewhere

Expanding from my comment, you need to maintain the async nature of the data to reuse it elsewhere in the code. You could use RxJS ReplaySubject with buffer 1. Also you need to make sure to close all open subscriptions when component is closed. I'm using takeUntil for it.

import { ReplaySubject, Subject } from 'rxjs';
import { tap, filter, switchMap, takeUntil } from 'rxjs/operators';

export class ProductEditComponent implements OnInit, OnDestroy {
  uiProduct: ProductModel;
  editSrc = new ReplaySubject<any>(1);
  edit$ = this.editSrc.asObservable();
  closed$ = new Subject<any>();

  ngOnInit() {
    this.activatedRoute.queryParams.pipe(
      tap({ next: (queryParams: any) => { this.editSrc.next(queryParams['edit']) } }),
      filter((queryParams: any) => (!!queryParams['edit'])), // <-- proceed only if `edit` is true
      switchMap(_ => this.productService.GetProductByName(this.name))
    ).subscribe({
      next: (response: ProductModel) => {
        this.uiProduct = response;
      },
      error: (error: any) => {
        // handle error
      }
    });
  }

  someFunc() {
    this.edit$.pipe(
      takeUntil(this.closed$)
    ).subscribe({
      next: (edit) => {
        if (edit) {
          // do something
        } else {
          // do something else
        }
      }
    });
  }


  someOtherFunc() {
    this.edit$.pipe(
      takeUntil(this.closed$)
    ).subscribe({
      next: (edit) => {
        if (edit) {
          // do something
        } else {
          // do something else
        }
      }
    });
  }

  ngOnDestroy() {
    this.closed$.next();  // <-- close open subscriptions when component is closed
  }
}
ruth
  • 29,535
  • 4
  • 30
  • 57
  • This works but I'm not sure how could I extract the value of the ``edit`` query parameter if I have to utilize it somewhere down the code – Raida Adn Nov 08 '20 at 11:55
  • @RaidaAdn: Short answer is you _cannot_. Atleast not synchronously like you were attempting. If you try to access it outside of the subscription, it may be `undefined` and there is no way to know when it'll be assigned the value. See [here](https://stackoverflow.com/q/14220321/6513921) to learn more about how asynchronous data works. Any statement that directly depends on the async data must be inside the subscription. Or you need to maintain the async nature using RxJS multicasts like `Subject` or `ReplaySubject`. – ruth Nov 08 '20 at 11:59
  • Understood the async nature. The link is very informational. Thanks – Raida Adn Nov 08 '20 at 12:09
  • I'm not sure how the call to ``GetProductByName`` happens though the edit is false in case of create route ``/product/Create?edit=false`` – Raida Adn Nov 10 '20 at 16:52
  • Replace the `filter` with `filter((queryParams: any) => { console.log(queryParams['edit']); return (!!queryParams['edit']) })`. Now you can see in the browser console what exactly is the `edit` value. – ruth Nov 11 '20 at 07:44
0

I like to create 2 routers, and load the same component:

 const routes: Routes = [
      { path: 'edit/:id', component: RequestReportComponent },
      { path: 'add', component: RequestReportComponent },
     ];

And in the component, check in this way:

isEditMode:boolean;
  constructor(private route: ActivatedRoute) {
             this.isEditMode = this.route.snapshot.params.id;
   
  }
Miri Gold
  • 370
  • 1
  • 9