简体   繁体   中英

Share service API data between initial components in Angular 6

I'm trying to have a navbar with categories and a home component that also uses those categories. I don't want to have to call my API twice and I will use that same categories variable in other places. I tried doing the following:

Data Service

This service gets the data from the api url and returns the subscribable object.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class DataService {

  api_url: string = "https://apiurlhere";
  categories: Object;

  constructor(private http: HttpClient) { }

  getCategories(){
    return this.http.get(this.api_url+'/categorylisting/?z=1');
  }

  getZones(){
    return this.http.get(this.api_url+'/zones/');
  }

}

Navbar Component

The Navbar component makes use of the categories variable to show the different options, this works fine since the subscribe is in this component.

import { Component, OnInit } from '@angular/core';
import { trigger, state, transition, animate, style } from '@angular/animations';
import { DataService } from '../data.service';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss'],
  animations: [
    trigger('slideInOut', [
      state('in', style({
        overflow: 'hidden',
        height: '*'
      })),
      state('out', style({
        overflow: 'hidden',
        height: '0px'
      })),
      transition('in => out', animate('400ms ease-in-out')),
      transition('out => in', animate('400ms ease-in-out'))
    ])
  ]
})
export class NavbarComponent implements OnInit {

  categories: Object;

  constructor(private data:DataService) { }

  ngOnInit() {
    this.data.getCategories().subscribe( data => {
      this.categories = data
      for(let category in this.categories){
        this.categories[category].productsOpen='out';
        for(let product in this.categories[category].product){
          this.categories[category].products[product].active = false;
        }
      }
      this.data.categories = this.categories;
    });
  }

  openProducts(index){
    this.categories[index].productsOpen = this.categories[index].productsOpen === 'out' ? 'in' : 'out';
  }

  setActiveProduct(index, productIndex){
    for(let category in this.categories){
      for(let product in this.categories[category].products){
        this.categories[category].products[product].active = false;
      }
    }
    this.categories[index].products[productIndex].active = true;
  }

}

Home Component

My Home component also makes use of the categories variable, so I want to know how I can get it here since it is always undefined even if it changes in the service.

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

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {

  categories: Object;

  constructor(private data:DataService) { }

  ngOnInit() {
    this.categories = this.data.categories;
  }

}

Am I doing this right? I'm used to react and redux and in there the render method would run every time a setState was called to change the state, when does angular know when the component's variables have changed? I just want to save a global variable with my data so I can reuse it without calling the API every time. Thank You.

You can cache the observable in your service like:

export class DataService {

someProperty;

  api_url: string = "https://apiurlhere";
  categories: Object;

  constructor(private http: HttpClient) { }

  getCategories(){
   if(!this.someProperty) {
     this.someProperty = this.http.get(this.api_url+'/categorylisting/?z=1');
   }
     return this.someProperty;
  }
}

You can also go for angular Http interceptors else you can also opt for rxjs operator shareReplay

You could try calling your API in the constructor of the DataService

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class DataService {

  api_url: string = "https://apiurlhere";
  categories: Object;

  constructor(private http: HttpClient) { 
    this.getCategories().subscribe(data => this.categories = data);
  }

  getCategories(){
    return this.http.get(this.api_url+'/categorylisting/?z=1');
  }

  getZones(){
    return this.http.get(this.api_url+'/zones/');
  }

}

and then just get the categories in the NavBar component just as you did in the Home component.

  ngOnInit() {
    this.categories = this.data.categories;
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM