29

I'm new to Angular 6 and i'm having trouble on how i can add objects into observable in a service.

i have this observable

 getContacts(){
  return this.contact = 
  this.http.get('https://jsonplaceholder.typicode.com/users');
 }

and i need to add an item into that observable via another function

addContact(item){
 //observable insertion goes here.
}

Here is my full service code

export class ContactService {

contact;
details;

constructor(private http: HttpClient) {}

getContacts(){
 return this.contact = 
 this.http.get('https://jsonplaceholder.typicode.com/users');
}

addContact(contactName: string, contactPhone: string){

}

}
Francis Rubia
  • 439
  • 2
  • 6
  • 14
  • seems like you need to use RxJS forkJoin – Suresh Kumar Ariya Nov 12 '18 at 10:34
  • 1
    I do not understand, what you exactly want to achieve. Observables only support you to get messages from your server, they do not directly contain the data themselves. You only get your contact/user data when you `subscribe()` on the observable. The docs explain it better than I do (https://angular.io/guide/observables). Anyway, you probably want to add an item to your contact? – gillesB Nov 12 '18 at 10:41
  • 1
    @gillesB Yes, Exactly that's what i wanted but add contact only on the current instance not in the server – Francis Rubia Nov 12 '18 at 10:43
  • It is hard to read this as a comment. Please edit your answer and put the code there. – gillesB Nov 12 '18 at 10:51
  • 1
    @gillesB i edit my question. last part is my full service code – Francis Rubia Nov 12 '18 at 10:57

3 Answers3

38

If this.contacts is an Observable of list of objects (contacts: Observable<Items[]>) and you want to make some changes to that list, you can simply use tap:

import { tap } from 'rxjs/operators';

this.contacts.pipe(tap(usersList => {
  usersList.push(newItem);
}));

But if you want to make another request to the server and merge these lists, you can use merge:

import { merge } from 'rxjs';

merge(
  this.contacts,
  this.http.get('https://jsonplaceholder.typicode.com/other_users');
).pipe(
  map(data => {
    const [currentResult, pastResult] = data;
    // ...
  }
));

Update

Based on your comment for more details, you don't need to do anything with observables. What you need is something like this:

In your contacts.service.ts:

getContacts(){
  return this.http.get('https://jsonplaceholder.typicode.com/users');
}

In your contacts.component.ts`:

contacts: any[] = [];
ngOnInit() {
  this.contactsService.getContacts().subscribe(data => {
    this.contacts = data;
  });
}

addContact(item) {
  this.contacts.push(item);
}

But if you want to have your contacts list as an Observable, you should use a Subject.

In your contacts.service.ts:

contactsChange$ = new Subject<any>();
private contactsList = [];

getContacts(){
  return this.http.get('https://jsonplaceholder.typicode.com/users').pipe(tap(data => {
    this.contactsList = data;
    this.contactsChange$.next(this.contactsList);
  }));
}

addContact(item) {
  this.contactsList.push(item);
  this.contactsChange$.next(this.contactsList);
}

In your contacts.component.ts`:

contacts: any[] = [];
ngOnInit() {
  this.contactsService.getContacts().subscribe(data => {this.contacts = data});
  this.contactsService.contactsChange$.subscribe(data => {this.contacts = data});
}
Vahid
  • 6,639
  • 5
  • 37
  • 61
  • I tried this one but it seems not working for me. There is no error but i cant see the new added item – Francis Rubia Nov 12 '18 at 11:11
  • @FrancisRubia When are you subscribing to `this.contacts`? If you do that before calling `addContact`, then you won't see any changes. – Vahid Nov 12 '18 at 11:18
  • i'm subscribing on init. After the page load i should see those default user from jsonplaceholder.com and after adding a contact i should be able to see the changes from the list. How am i supposed to do it right – Francis Rubia Nov 12 '18 at 11:22
  • @FrancisRubia I've updated my answer. Check it please. – Vahid Nov 12 '18 at 11:31
  • Yes, this is actually working but for some reason. I needed to use a service for adding a contact – Francis Rubia Nov 12 '18 at 11:33
  • @FrancisRubia So then you need to have a Subject in your service. A Subject is like an Observable but you also can use `next` method to add items to it. I'll add the code or using a Subject. – Vahid Nov 12 '18 at 11:49
  • 2
    This is an awesome answer! I'd like to add one small note: The dollar sign should be at the end of the variable name, to make clear that it is an observable/subject and not an event. source: https://angular.io/guide/rx-library#naming-conventions-for-observables – denns Oct 28 '19 at 07:55
  • The updated versions of this answer is well done, thanks! – MikhailRatner May 10 '22 at 15:31
3

Working With Observable


In Your Service

private contactInsertedSubject = new Subject<Contact>();
contactInsertedActions$ = this.contactInsertedSubject.asObservable();

 public contacts$ = this.http.get<Contact[]>(this.contactsUrl)
            .pipe(
              // tap(data => console.log('Contacts: ', JSON.stringify(data))),
              catchError(this.handleError)
            );
public contactsWithAdd$ = merge(this.contacts$, this.contactInsertedActions$)
                        .pipe(
                          scan((acc: Product[], value: Product) => [...acc, value])
                        );
addContact(newContact?: Contact) {
   this.contactInsertedSubject.next(newContact);
}

Your Contact Component Class

contacts$ = this.contactService.contactsWithAdd$;
onAdd(): void {
   this.contactService.addProduct();
}

when this add method will call the subject in service will emit the value and merge observable has two input observable if any one will emit value so this will call automatically and then in pipe map operator will do the insertion job and contactWithAdd observable will have updated list.

Hassan
  • 61
  • 3
0

The addContact () method is where you subscribe to the observable getContacts():

getContacts(): Observable<any> {   
    return this.contact = 
    this.http.get('https://jsonplaceholder.typicode.com/users');
}

At the time of subscription is when the call is triggered:

addContact(){
    let cont: Observable<contactModel>;
    cont = this.getContacts();
    prueba.finally(() => {
       console.log('Finally callback')
    })
    cont.subscribe(res => {
        console.log('at the time of subscription is when the call is triggered')
        let resp: contactModel[];
        resp = res.json() as contactModel[];  
    });


}
ararb78
  • 1,137
  • 5
  • 19
  • 44