So recently i've learnt about Subjects, and i'm trying to use them in a personal project. I have a service that fetches data from a json file and casts it to an "Article" type. Article is a custom class that holds information on a blog article.
My end goal here is to fetch this array of articles, then when I press a + button it adds a new blank Article to the current list, and the view should represent it by showing the blank article with some default values. This does not persist (save to json) the new blank article, but simply add it to the current list so the view updates and displays it. Saving will come later.
I cannot for the life of me get this to work. All the articles are correctly displaying on my "article list" page but manually pushing a blank one to it doesn't seem to do anything at all.
Here is my service file
@Injectable()
export class ArticleService {
headers: Headers;
options: RequestOptions;
articles: ReplaySubject<Article[]>;
private url = 'data/articles.json';
constructor(private http: Http) {
this.headers = new Headers({ 'Content-Type': 'application/json' });
this.options = new RequestOptions({ headers: this.headers });
this.articles = new ReplaySubject<Article[]>();
}
/**
* fetch a list of articles
*/
getArticles(): Observable<Article[]> {
// no articles fetched yet, go get!
return this.http.get(this.url, this.options)
.map(response => <Article[]>response.json())
.do(data => this.articles.next(data))
.catch(this.handleError);
}
/**
* add a new article to the list
* @param article
*/
addArticle(article: any): void {
this.getArticles().take(1).subscribe(current => {
//
//
// THIS WORKS. this.articles is UPDATED successfully, but the view doesn't update
// IT ALSO LOOKS LIKE this.articles may be being reset back to the result of the get()
// and losing the new blank article.
//
//
current.push(article);
this.articles.next(current);
});
}
...
}
and I have a list component updating the list like this:
export class ArticleListComponent implements OnInit {
articles: Article[];
public constructor(private articleService: ArticleService) { }
ngOnInit(): void {
this.getArticles();
}
getArticles(): void {
this.articleService.getArticles().subscribe(articles => this.articles = articles);
}
}
and another component that creates the new blank article:
export class CreatorComponent {
articles: Article[];
public constructor(private articleService: ArticleService) { }
/**
* add a new empty article
*/
add(): void {
let article = {};
article['id'] = 3;
article['author'] = "Joe Bloggs";
article['category'] = "Everyday";
article['date'] = "November 22, 2017"
article['image'] = "/assets/images/post-thumb-m-1.jpg";
article['slug'] = "added-test";
article['title'] = "New Via Add";
article['content'] = "Minimal content right now, not a lot to do."
this.articleService.addArticle(article);
}
}
I can debug, and the this.articles property on the service seems to get updated with the new blank article, but the view doesn't change, and i can't tell for sure but it seems like that article is just lost as soon as soon as its added anyway. Is the observable repeating the http get and scrubbing the articles list clean again?
You haven't actually subscribed to the subject you're interested in in your display component. You only subscribe to the http call that populates the subject you're interested in and then terminates. Try it more like this:
private articleSub: Subscription;
ngOnInit(): void {
this.articleSub = this.articleService.articles.subscribe(articles => this.articles = articles);
this.articleService.getArticles().subscribe();
}
ngOnDestroy() { //make sure component implements OnDestroy
this.articleSub.unsubscribe(); // always unsubscribe from persistent observables to avoid memory leaks
}