i am trying to send data from one component to another in angular like so
this.newsService.searchNews(form.value.query).subscribe((res:any) => {
this.newsService.searchedNews.next(res.articles);
});
}
im sending the searched news from my search component to my home component, if i subscribe to the subject in ngOninit in my home component the data would be null since the method wasn't called yet or the user hasn't searched for anything, so my question is, is there a way to listen to this method (SearchComponent) when it is called or executed in my HomeComponent, this is the service
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs';
import { Article } from '../models/article';
@Injectable({
providedIn: 'root'
})
export class NewsService {
searchedNews = new BehaviorSubject<any>('');
constructor(private http: HttpClient) { }
getHeadlines() {
return this.http.get(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${this.newsApiKey}`);
}
searchNews(query: string) {
return this.http.get(`https://newsapi.org/v2/everything?q=${query}&apiKey=${this.newsApiKey}`)
}
}
CodePudding user response:
In general, your subjects in services should not be publicly exposed. Use a set method that will call next, and create a new observable with the subject as the source.
There are different types of subjects that can be used in the case of late subscribers. That means that your observable will emit the latest value when it is subscribed to. You can for example use ReplaySubject, BehaviorSubject, or AsyncSubject(it should complete before it starts emitting). You can also utilize the ShareReplay operator.
And last but not least. Remember to unsubscribe from your observable to avoid memory leaks or other bad stuff. You can do it directly in the template by using the async pipe. e.g. obs$ | async
. You can also destroy it in the component by unsubscribing in ngOnDestroy.
Here is an example. In this case, null is the default value but you can change it. Components can subscribe to searchedNews$
and late subscribers will get the last emitted value. The observers will receive a null value if nothing has been emitted.
@Injectable()
export class NewsService {
private _searchedNews$ = new BehaviorSubject(null);
searchedNews$ = this._searchedNews$.asObservable();
sendArticle(article: Article){
this._searchedNews$.next(article);
}
}
and in the components it is:
@Component({
selector: 'homecomponent',
template: `<h1>{{newsobs$ | async}}</h1>`,
})
export class HomeComponent {
newsobs$ = this.newsService.searchedNews$;
constructor(private newsService: NewsService) {}
}
@Component({
selector: 'searchComponent',
})
export class Searchomponent implements OnInit {
constructor(private newsService: NewsService) {}
ngOnInit(): void {
this.newsService.sendArticle({} as Article);
}
}
UPDATE: Could see you have updated your question after my first answer. Maybe you can do this. You don't have to unsubscribe from HTTP calls since they will complete automatically.
import { BehaviorSubject } from "rxjs";
@Injectable({
providedIn: 'root'
})
export class NewsService {
private _searchedNews$ = new BehaviorSubject<any>('');
searchedNews$ = this._searchedNews$.asObservable();
constructor(private http: HttpClient) { }
getHeadlines() {
return this.http.get(`https://newsapi.org/v2/top-headlines?country=us&apiKey=${this.newsApiKey}`);
}
searchNews(query: string) {
return this.http
.get(`https://newsapi.org/v2/everything?q=${query}&apiKey=${this.newsApiKey}`)
.subscribe(x => this.searchedNews$.next(x))
}
}