0

I am creating a angular project where i am getting API data which i am displaying to user. It has two components "Navigation" and "NewsBlock" and a service called "newsFetchService". API data is fetched by newsfetch service and used by both components.

NewsFetchService
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { NewsData } from './NewsData';
import { HttpClient,HttpHeaders } from '@angular/common/http';

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

  //Global variable storing All fetch data
  newsBlockData : NewsData[] = [];
  allNews : NewsData[] = [];

  constructor(
    private http:HttpClient
  ) { }

  private newsFetchURL = 'api/v1/topics';

  getNews() {
    return new Promise((resolve, reject) => {
    this.http.get<NewsData[]>(this.newsFetchURL).subscribe(res => {
    this.allNews = res;
    this.newsBlockData = res;
    resolve(true);
    })
    })
    }

    updateNewsBlock(selectedNews : NewsData){

      this.newsBlockData.length = 0;
       this.newsBlockData.push(selectedNews);
    }
}

navigation.component.ts
import { Component, OnInit } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
import { NewsfetchserviceService } from '../newsfetchservice.service';
import { NewsData } from '../NewsData';
@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit{

  sourcesList : NewsData[] = [];
  
  ngOnInit(): void {
    this.showAllSources();
  }

  isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
    .pipe(
      map(result => result.matches),
      shareReplay()
    );

  constructor(private breakpointObserver: BreakpointObserver,private newsfetch: NewsfetchserviceService) {}

  showAllSources():void {
    this.sourcesList = this.newsfetch.allNews;
    /* this.newsfetch.getNews().subscribe(news => this.news = news); */
  }

  updateNewsList(source : NewsData):void{
    console.log('option selected');
    console.log(source);
    this.newsfetch.updateNewsBlock(source);
  }
}

newsBlock.component.ts
import { Component, OnInit } from '@angular/core';
import { NewsData } from '../NewsData';
import { NewsfetchserviceService } from '../newsfetchservice.service';

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

  constructor(private newsfetch: NewsfetchserviceService) { }

  newsBlockData : NewsData[] = [];
  ngOnInit(): void {
    this.getNews();
  }

  getNews():void {
    this.newsBlockData = this.newsfetch.newsBlockData;
    /* this.newsfetch.getNews().subscribe(news => this.news = news); */
  }

}

Now, when user click a field in Navigation component it updates the newsBlockData array in Newsfetchservice. This newsBlockData is used by "newsBlock" component which is correctly updating data based on data changed. Issue i am facing is that updating data within newsBlockData array is also affecting allnews array Data. Any data added or removed from newsBlockData array is also reflected in allnews array even though they are two separate arrays.

I have tried changing approach like trying to use subscriber and promise but getting the same issue. Also tried deep copying and shallow copying but getting the same result

3
  • How are they two separate arrays if you assign the same value to them? this.allNews = res; this.newsBlockData = res; That makes both properties point to the same array. Commented Dec 16, 2022 at 8:55
  • I have replaced the this.allNews = res; this.newsBlockData = res; with this.allNews = JSON.parse(JSON.stringify(res)); this.newsBlockData = JSON.parse(JSON.stringify(res)); I have already tried this approach but then app loading takes too much time. Is it a symptom of this and no other way around it? or my approach to the problem is wrong ? Commented Dec 16, 2022 at 9:07
  • If you have a lot of content, that parse/stringify deep copy could be heavy. As far as I can tell, you only need a shallow copy though. If you do need a deep copy, you only need to do it for one of the arrays. Commented Dec 16, 2022 at 9:59

1 Answer 1

2

The problem is in the getNews() method. Even though you initialize both properties to point to a separate array:

newsBlockData : NewsData[] = [];
allNews : NewsData[] = [];

In your getNews() method, you point them to the same array:

getNews() {
  return new Promise((resolve, reject) => {
    this.http.get<NewsData[]>(this.newsFetchURL).subscribe(res => {
      this.allNews = res;
      this.newsBlockData = res;
      resolve(true);
    })
  })
}

A shallow copy in this case should be sufficient:

getNews() {
  return new Promise((resolve, reject) => {
    this.http.get<NewsData[]>(this.newsFetchURL).subscribe(res => {
      this.allNews = [...res];
      this.newsBlockData = [...res];
      resolve(true);
    })
  })
}
Sign up to request clarification or add additional context in comments.

1 Comment

Using shallow copy is giving a better performance as compared to deep copy. Thank you for solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.