1

I have a component that gets data from server. My service has a BehaviorSubject<any[]>([]) to get data.

export class AppComponent {
  items: Observable<any[]>;

  constructor(private service: MyService) {
    this.items = service.getItems();
    // this items format is like: `[{id:1,name:'cat'},{id:2,name:'dog'}]`
  }

  addItem(item:any){
   // add item to `this.items` observable array ???
  }

  removeItem(item:any){
   // remove item from `this.items` observable array ???
  }
}

And my service is like following:

@Injectable()
export class MyService{
    private items = new BehaviorSubject<any[]>([]);

    constructor(private http: HttpClient) {
      this.loadItems();
    }

    private loadItems() {
      this.http.get<any[]>('/api/items')
        .subscribe((i) => this.items.next(i));
    }

    getItems() {
      return this.items.asObservable();
    }

    addItem(item: any) {
      return this.http
        .post<any>('/api/items', item)
        .subscribe(() => this.loadItems());
    }
}

I need to add add and remove an item to this observable array but could not do it. The service can add data to server, but I need to add array without send to server. Is this possible?

barteloma
  • 6,403
  • 14
  • 79
  • 173
  • 2
    Possible duplicate of [Angular 6 add items into Observable](https://stackoverflow.com/questions/53260269/angular-6-add-items-into-observable) – jitender Oct 13 '19 at 14:17
  • It's possibly a duplicate as posted by @jitender. On another note: Please also share the code within `MyService`. – Philipp Meissner Oct 13 '19 at 14:19
  • Are you assign array into `BehaviourSubject` (`BehaviorSubject([])`) that you need the array to be added into another array (`items: Observable;`)? – varman Oct 13 '19 at 14:25
  • @varman no I did not. Should I add? Can you type solution as answer? – barteloma Oct 13 '19 at 14:28
  • So you need to pass only one value to behaviour subject and put into the array, isn't it? – varman Oct 13 '19 at 14:54
  • Please brief actually what you need to add and remove that we can help you – varman Oct 13 '19 at 15:10
  • @varman I need to add and remove item from `this.items` observable array in component, I do not want to add to service. I updated the post. – barteloma Oct 13 '19 at 15:13
  • `service.getItems()` returns array or array object? – varman Oct 13 '19 at 15:15
  • Not it returns an observable array. – barteloma Oct 13 '19 at 15:18
  • What I asked you is, is that returning like `['cat','dog','rabbit']` or `[{id:1,name:'cat'},{id:2,name:'dog'},{id:3,name:'rabbit'}]`. Please clearly mention what is your question – varman Oct 13 '19 at 15:21
  • It returns object array `[{id:1,name:'cat'},{id:2,name:'dog'},{id:3,name:'rabbit'}]` as you said. – barteloma Oct 13 '19 at 15:23

2 Answers2

4

In your case you don't need to define BehaviourSubject, because you are not maintaining state over the application. So simply you can use like following.

In your service component, write only the service. Because service is a singleton which is only one time initialized.

@Injectable()
export class SomeDataService {    

    //Made this as observable, But when you use httpClient, No need to use Observable.of(), you can directly return like this.http.get<any[]>('/api/items')

    myData=Observable.of([{id:1,name:'cat'},{id:2,name:'dog'},{id:3,name:'rabbit'}])
    constructor() {     
    }

    loadItems() {
      // in your case, return this.http.get<any[]>('/api/items')
      return this.myData;
    }
}

In the AppComponent

export class AppComponent implements OnInit {
    counter=4;
    mydata=[]; //No point to make this as Observable array

    constructor(private _service: SomeDataService) { }

    public ngOnInit(): void {
        this._service.loadItems().subscribe(res=>{     
            this.mydata=res;       
        })  
    }

    addData(){
        let increment=this.counter++
        let data={id:increment,name:increment+"data"}
        this.mydata.push(data)
    }

    removeData(item){
        let index=this.mydata.indexOf(item)
        this.mydata = this.mydata.filter((val,i) => i!=index); 
    }
}

In html,

<button (click)="addData()">Add data</button>

<table>
    <tr>
        <th>Id</th>
        <th>Name</th>
        <th>Action</th>
    </tr>
    <tr *ngFor="let data of mydata;let i=index;">
        <td>{{data.id}}</td>
        <td>{{data.name}}</td>
        <td><button (click)="removeData(data)">Remove data</button></td>
    </tr>
</table>

Click here for the demo Stackblitz.

halfer
  • 19,824
  • 17
  • 99
  • 186
varman
  • 8,704
  • 5
  • 19
  • 53
  • Hi Varman. Please do not roll back good edits here, or add chatty/conversational material to posts. Technical writing is preferred. If you are not familiar with the guidelines for succinct writing, please let me know, so I can point you to some relevant posts on _Meta_. – halfer Jan 28 '20 at 22:49
2

You will need to subscribe to the observables and return the values, before you can do any further manipulation.

For instance,

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})

export class AppComponent implements OnInit {
  items: any[];

  constructor(private service: MyService) {

  }

  ngOnInit() {
    this.service.getItems().subscribe(res => {
      console.log(res);
      this.items = res;
    });
  }

addItem(){
  // this.items.push(someObject)
}


}
wentjun
  • 40,384
  • 10
  • 95
  • 107