1

I am fairly new to rxjs and I have something like following.

I subscribe to some rxjs Subject and don't know how to remove only particular item from its Observable.So that, I use a second variable removeItem and subscribe it as well and remove element from local carItems var. (It works but...Yes,it smells bad. There must be a better practice)

After deleting an object I can re-have whole set in my subscription but I do not want that because there is an animation for each item. There is also another animation for removal of each item.

Is there a usage something like C# ObservableCollection which notifies both add/remove ops and let me know which particular object is removed?

  import { TS } from 'typescript-linq'    
  @Injectable() 
  export class CartService {

  private items = new ReplaySubject<Array<ProductModel>>(1);
  private removeItem= new ReplaySubject<ProductModel>(1);
  var cartItems=new Array<ProductModel>();

  removeFromCart(remItem)
    {
      this.removeItem.next(remItem);
    }
 ...

Moreover, TS.Linq.Extensions works quite well. But, requires something support [Symbol.iterator] and I needed to go for an Array instead of my local Ovservable.

(I don't know if there is a way to use it as method chain like we use in C# )

var groupedItems=TS.Linq.Extensions.groupBy(cartItems,(i:ProductModel)=>i.Name)
    .select((t)=>{return {item:t.key,count:t.count()}});

    groupedItems.forEach(item=>{console.log(item.item+" count " + item.count)});

There is a semi-similar question. I still couldn't make following QA's accepted answer run in plnkr.

How to remove specific element from Observable<Array<any>>

Davut Gürbüz
  • 5,526
  • 4
  • 47
  • 83
  • 1
    Observables are a great tool, but are not the best fit for everything. Think of them as great for managing streams of events, such as UI clicks, buttons, sliders, responses to http requests, server confirmations, timeouts etc, and your UI can deal with this flow of information. It's not really meant for managing data, although you can have observables call action routines that do the data management if you like. – Mikkel Feb 03 '18 at 22:54
  • 1
    If you want to manage state in your application, perhaps [ngrx](https://github.com/ngrx/platform) would be a better fit. – R. Richards Feb 03 '18 at 22:59
  • Could you please clarify why you are using Replay subject and not Behavioral subject. i think the problem with understanding what replay and behavioral subject do. – Nour Feb 04 '18 at 09:38
  • @Nour not something particular. The only difference I know BehaviourSubject requires some initial values but ReplaySubject not. In my case, ReplaySubject was a better option. – Davut Gürbüz Feb 04 '18 at 13:30
  • Thanks all. I'll try following project which also use rxjs innerly [https://github.com/Narazaka/observable-collection.js](https://www.npmjs.com/package/observable-collection) – Davut Gürbüz Feb 04 '18 at 14:56

2 Answers2

1

There's a way to do what you want but not the best approach to be honest. If you want a global state, use a global subject instead. If local state you can just use plain array, or by combining user action with data like

assume userclick$ and buttonClick$ will modify the data

Observable.merge(userClick$,butonClick$).startWith([1,2,3])...

let items$=new Rx.BehaviorSubject([1,2,3])
let itemRemove=(index)=>{
 let arr=null 
  items$.subscribe(value=>{
   ar=value.filter((value,i)=>i!=index) 
  })
 items$.next(ar) 
}
itemRemove(1)
items$.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
Fan Cheung
  • 10,745
  • 3
  • 17
  • 39
0

Could you please try the below code:

@Injectable()
export class CartService{

  private items = new BehaviorSubject<Array<ProductModel>>(null);
  private cartItems=new Array<ProductModel>();

  removeFromCart(remItem)
  {
    this.carItems = this.carItems.filter((item:ProductModel) => item !== remItem);
    this.items.next(this.carItems);
  }

  getItems():BehaviorSubject<Array<ProductModel>>{
    return this.items;
  }


}


import {CartService} from 'yourServiceLocation';

@Component({
  selector: 'test-com',
  template: `<div>Test component</div>`
})

 export class TestComponent{

  private cartItems=new Array<ProductModel>();

  constructor(private cartService:CartService){
    this.cartService.getItems()
      .subscribe(items => this.carItems = items);
  }


  //On button clicked or so

  private removeItem(item:ProductModel){
    this.cartService.removeFromCart(item);
  }


}
Nour
  • 5,609
  • 3
  • 21
  • 24
  • Thanks for your interest, but I'm not looking for this. I can subscribe and be notified of the new product set once `next` run. But, there is no subscription to removal item. BTW, check your filtering again :) . This question asks for something like `C# ObservableCollection` which gives `NotifyCollectionChangedEventArgs.OldItems Property` to its `CollectionChanges` event subscribers. – Davut Gürbüz Feb 04 '18 at 14:05
  • Thank you, i have updated my filtering :). Yeah you are right i think there is no equivalent data structure like C# ObservableCollection, but there are a lot of workarounds. :). – Nour Feb 04 '18 at 14:10
  • I already make use of these turnarounds but there are several reasons to avoid. 1) Not elegant 2) Reduce readability 3) Can cause other problems if you can't keep several variables synced – Davut Gürbüz Feb 04 '18 at 14:15