2
class item {
  name: string;
  order: number;
}
let onUp = new Rx.Subject<item>();
let list = new Rx.BehaviorSubject<item>([
  { name: "7", order: 70 },
  { name: "2", order: 20 },
  { name: "5", order: 50 },
  { name: "3", order: 30 },
  { name: "4", order: 40 },
  { name: "6", order: 60 },
  { name: "1", order: 10 }
]);
list.subscribe(console.log);
onUp.subscribe(anItem => {
  let numberList: item[];
  list
    .take(1)
    .map(x => x.sort((a, b) => a.order - b.order))
    .subscribe(ddList => (numberList = ddList));
  let index = numberList.indexOf(numberList.find(num => num.order == anItem));
  let ddvalue = numberList[index];
  let preddvalue = numberList[index - 1];

  let preddvalueOrder = preddvalue.order;
  preddvalue.order = ddvalue.order;
  ddvalue.order = preddvalue.order;

  list.next(numberList);
});

onUp.next(30);

whats the reactive way to exchange values of "order" with another object from the list?

I have a bunch of items that I should be able to reorder.

The order of an item is based on the order property of the item object in the item list. I reorder the items by switching the order property of two items. In the sample code, the onUp Subject, emits an orderNumber which should be switched with the upper item(ordered by order property)

The sample code works, its just that its probably bad practice since the second subscribe is asynchronous. An alternative is to do the reordering inside the subscription inside the outer subscription but that's also bad practice(not sure why aside from the fact that its a messy nest).

I always see flatMap but if I understand correctly the 2nd subscription just uses a data from the first subscription to get a data. In this case I need both data from the first and second subject to get the two items to switch and the new list to push to list subject.

justelouise
  • 714
  • 1
  • 5
  • 20

2 Answers2

0

Ah.... Is maintaining 2 lists ok to you? One is the unsorted, the other one always listen to unsorted changes and sort it.

const list = new Rx.BehaviorSubject([
  { name: "7", order: 70 },
  { name: "2", order: 20 },
  { name: "5", order: 50 },
  { name: "3", order: 30 },
  { name: "4", order: 40 },
  { name: "6", order: 60 },
  { name: "1", order: 10 }
]);
const sortedList = new Rx.BehaviorSubject([]);
const onUp = new Rx.BehaviorSubject(0);

list
  .map(x => x.sort((a, b) => a.order - b.order))
  .subscribe(x => sortedList.next(x));

sortedList.subscribe(console.log);

onUp.subscribe(x => {
  const idx  = sortedList.getValue()
    .findIndex(itm => itm.order === x);
  
  if (idx < 1) return;
  
  const list = sortedList.getValue();
  
  const prev = list[idx - 1].order;
  const curr = list[idx].order;
  
  list[idx].order = prev;
  list[idx - 1].order = curr;
  
  sortedList.next(list);
});

onUp.next(30);
onUp.next(70);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
Jecfish
  • 4,026
  • 1
  • 18
  • 16
  • thank you for this, @Chybie . but what i'm actually after is switching the order property of 2 adjacent objects in the array. – justelouise Jan 24 '18 at 13:09
0

getValue() of BehaviorSubject is bad practice as well(says so in my source by Ben Lesh). readup on withLatestFrom or combineLatest for combining two observables.

class item {
  name: string;
  order: number;
}
let onUp = new Rx.Subject<item>();
let list = new Rx.BehaviorSubject<item[]>([
  { name: "7", order: 70 },
  { name: "2", order: 20 },
  { name: "5", order: 50 },
  { name: "3", order: 30 },
  { name: "4", order: 40 },
  { name: "6", order: 60 },
  { name: "1", order: 10 }
]);
list.subscribe(console.log);
// onUp.subscribe(anItem => {
onUp
  .withLatestFrom(list, (item, itemList) => {
    return { item: item, itemList: itemList };
  })
  .subscribe(itemWithList => {
    let numberList: item[] = itemWithList.itemList.sort(
      (a, b) => a.order - b.order
    );
    let orderToUp: number = itemWithList.item;

    let index = numberList.findIndex(x => x.order === orderToUp);
    let ddvalue = numberList[index];
    let preddvalue = numberList[index - 1];
    console.log(ddvalue);

    let preddvalueOrder = preddvalue.order;
    preddvalue.order = ddvalue.order;
    ddvalue.order = preddvalueOrder;

    list.next(numberList);
  });

onUp.next(30);

Paste it here: https://emeraldwalk.github.io/rxjs-playground/#

Source: https://stackoverflow.com/a/45227115