0

I need help :) I tried to find the solution in other topics, but was not able to, so I am sorry beforehand if there is any. I am a newbie.
So, the problem. I have a bunch of div's. I need to add "active" class for each div, then remove it in 2 sec, one by one.
I have the solution, but my master says that "from" and then "of" are not good at all. Any ideas how it can be done in other way? Thank you in advance!

const boxes = document.querySelectorAll('.box')
const innerBoxes = Array.from(boxes);
const clickOnDiv = fromEvent(innerBoxes, 'click')
   .pipe(
     map(event => {
       let notActiveElements = [];
       for ( let i=0; i < innerBoxes.length; i++) {
         if(innerBoxes[i] != event.target) {
           notActiveElements.push(innerBoxes[i])
         }
       }
       return notActiveElements
     }),
     concatMap(element => from(element)
      .pipe(
        concatMap(element => of(element)
        .pipe(
          tap(el => console.log(el)),
          delay(2000)
        )),
        tap(item => {
          item.classList.add('active')
        }),
        delay(2000),
        tap(item => {
          item.classList.remove('active')
        })        
      ))
   )

clickOnDiv.subscribe()
Ivan Vilch
  • 86
  • 1
  • 4
  • innerBoxes are EVENTS or HTML elements? – m.akbari Dec 18 '18 at 17:10
  • instead of fromEvent use from. – m.akbari Dec 18 '18 at 17:12
  • innerBoxes - array from boxes, classes assigned to divs. Just for easier looping. So basical event is click, sorry for not saying right away. So, clicking on one div - it should be inactive, other should get active class. after getting not active elements - I am working with array of notActiveElements – Ivan Vilch Dec 18 '18 at 22:58

1 Answers1

0

Not sure if condition "then remove it in 2 sec, one by one." doesn't stop you iterating over array

   click$.pipe(
      filter(notActive),
      tap((elements) => elements.forEach(addActiveClass)),
      delay(2000),
      tap((elements) => elements.forEach(removeActiveClass))
    ).subscribe();

If you cannot then

click$.pipe(
    filter(...)
    mergeMap(elements => from(elements)),
    tap(addActiveClass)
    delay(2000)
    tap(removeActiveClass)
).subscribe()

Extra:

User filter for this:

 let notActiveElements = [];
   for ( let i=0; i < innerBoxes.length; i++) {
     if(innerBoxes[i] != event.target) {
       notActiveElements.push(innerBoxes[i])
     }
   }
   return notActiveElements;

like: notActiveElements = innerBoxes.filter(box => box !== event.target);

UPDATE, based in comments

 click$.pipe(
    filter(...)
    concatMap(elements => from(elements).pipe(
        tap(addActiveClass),
        delay(2000),
        tap(removeActiveClass)
    ))
).subscribe()

Where do you study rxjs?

  • Thank you for your answer. This solution adds/removes the class for all elements (divs) at a time, so it adds active class for all divs, and then the class is removed for all elements at the same time. This solution is nothelping me. The problem was with adding/removing class for each div one by one. Basically, the class should be added for 1 div - then removed in 2 sec, only after that it should be added to next div and going forward. And thank you for filter :) – Ivan Vilch Dec 24 '18 at 09:36
  • I finished the courses and now I am a trainee in one small company getting ready to work with angular. Does it work on your end? I test it in StackBlitz, and it still does the same - just adds the class for all divs and then removes it for all as well. Not one by one. After filtering I put this `concatMap(elements => from(elements) .pipe( tap(item => { item.classList.add('active') }), delay(2000), tap(item => { item.classList.remove('active') }) ))` – Ivan Vilch Dec 24 '18 at 10:33