Utilize toggle functionality for page rotation with rxjs in Angular framework

Managing a project that involves a container holding multiple cards across different pages can be overwhelming. To address this, the screen automatically rotates to the next page after a set time interval or when the user presses the space bar.

To enhance the functionality, we have introduced a toggle button to disable the automatic rotation. I have integrated an 'EventEmitter' for the toggle button in the 'toggleEmitter' function below, but as I am fairly new to rxjs, I am unsure how to utilize it effectively to halt the rotation process. Can anyone offer guidance on this matter?

@Component({
  selector: 'rotator-container',
  templateUrl: './rotator-container.component.html',
})
export class RotatorContainerComponent implements AfterViewInit, OnDestroy {
  @ContentChildren(RotatorItemComponent, { read: ElementRef })
  rotatorItems: QueryList<ElementRef>;

  @Input() rotationInterval = 30 * 1000;

  @Output() toggleEmitter: EventEmitter<MatSlideToggleChange> =
    new EventEmitter();
  toggle(event: MatSlideToggleChange) {
    this.toggleEmitter.emit(event);
  }

  timer$ = this.activatedRoute.queryParams.pipe(
    map(params => params['rotate']),
    switchMap(rotate =>
      rotate === 'false' ? of(0) : timer(0, this.rotationInterval)
    )
  );

  spaceCounter$ = fromEvent<KeyboardEvent>(document, 'keydown').pipe(
    filter(({ code }) => code === 'Space'),
    tap(e => e.preventDefault()),
    map(() => 1),
    scan((acc, curr) => acc + curr, 0),
    startWith(0)
  );

  rotationCounter$ = combineLatest([this.timer$, this.spaceCounter$]).pipe(
    map(([index, offset]) => index + offset)
  );

  rotatorSubscription: Subscription;

  constructor(private activatedRoute: ActivatedRoute) {}

  ngAfterViewInit() {
    const rotatorItemsLength$ = this.rotatorItems.changes.pipe(
      map(() => this.rotatorItems.length),
      startWith(this.rotatorItems.length)
    );

    const visibleIndex$ = combineLatest([
      this.rotationCounter$,
      rotatorItemsLength$,
    ]).pipe(
      map(([index, length]) => index % length),
      startWith(0)
    );

    this.rotatorSubscription = visibleIndex$.subscribe(visibleIndex =>
      this.rotatorItems.forEach((item, index) => {
        (<HTMLElement>item.nativeElement).style.visibility =
          visibleIndex === index ? 'visible' : 'hidden';
        (<HTMLElement>item.nativeElement).style.position =
          visibleIndex === index ? 'relative' : 'absolute';
      })
    );
  }

  ngOnDestroy() {
    this.rotatorSubscription && this.rotatorSubscription.unsubscribe();
  }
}

Answer №1

It seems like using an EventEmitter is not necessary in this case. Instead, consider adjusting the functionality of the timer$ Observable.

One possible approach to try is as follows:

To start, create a Subject that will emit either true or

false> whenever the state of the toggle button changes. Specifically, it emits <code>true
if the button is toggled on and false otherwise.

This code snippet demonstrates how to achieve this:

// Use a BehaviorSubject to initiate with a specific value, such as false
toggleSubject = new BehaviourSubject<bool>(false)
....
toggle(event: MatSlideToggleChange) {
    this.toggleSubject.next(event.checked);
}

Next, modify the timer$ Observable. Here's one potential way to go about it:

// Initially, rename the current timer$ to _timer$
_timer$ = this.activatedRoute.queryParams.pipe(
  map(params => params['rotate']),
  switchMap(rotate =>
    rotate === 'false' ? of(0) : timer(0, this.rotationInterval)
  )
);

// Then redefine the timer$ stream based on toggleSubject
timer$ = toggleSubject.pipe(
  // Switch to a new stream whenever toggleSubject emits
  switchMap(toggleVal => {
    // If the toggleButton is on, automatic rotation is off; otherwise, it's on
    // This is achieved by returning an Observable that emits 0 if the button is on,
    // or the original definition of timer$ if it's off
    return toggleVal ? of(0) : this._timer$
    
  })
)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is Javascript necessary for submitting a form to a PHP script?

In my current project, I am working on a page to edit information in a database. While I know how to create the form in HTML and the PHP script that runs on the server, I am facing a challenge with JavaScript. My understanding of JavaScript is limited, and ...

The functionality of the WordPress Contact Form 7 Plugin becomes erratic when integrated into dynamically loaded AJAX content

I am currently facing a challenge with integrating the WordPress Contact Form 7 Plugin into a website I have built on WordPress. The theme of the site utilizes jQuery to override default link behavior and AJAX to load pages without refreshing the entire pa ...

Sorting through an array of objects using a filter method

While following a tutorial, I decided to make some changes to the TypeScript for learning purposes. However, I encountered a problem when trying to create a filter function from a React context script. I have successfully implemented a function called get ...

Using the Rails cocoon gem to populate numerous input fields

I'm currently implementing the cocoon gem in my rails application, where I have a form with two nested fields (categories and subcategories). Initially, only the first field is visible while the second one remains hidden. When the first select field h ...

Is React Context malfunctioning due to a syntax error?

Using the function "login" from React context is causing an error for me: const handleLogin = async (data: LoginType) => { try { await login(auth, data.email, data.password); router.push("/Dashboard"); } catch (error: an ...

How to retrieve a string from a regular expression in Javascript without [Object object] output

Within my code, there exists a parent form component and a child component used for auto-completing text input. The Parent component passes an array of objects named autoCompTxt, consisting of name and id fields, to the Child component. //Parent: const [ob ...

What is the best way to specify the type of a property that has already been assigned

I am currently utilizing a third-party library that includes a type defined as the following: export interface ThirdPartyNodeType { id: string; name: string; data: any; } Upon further exploration, I have identified the content that I intend to include ...

Chrome Automatically Playing WebRTC Audio

My webapp has webrtc functionality, but I've noticed a strange issue. When connections are established between Chrome browsers, the audio is not played, while video is. However, this problem doesn't occur with Mozilla users. So... Chrome user 1 ...

You are unable to move the image to the top of the screen after zooming it with CSS

I implemented an image viewer component with interactive buttons for rotating, zooming in, and zooming out. Upon clicking a button, CSS transform is applied to the image. However, I encountered an issue where, when zooming the image, it cannot be scrolled ...

Angular CLI integrated with Isotope version 2

I am facing difficulties when using the isotope-layout module with Angular CLI. To install the module, I used the command: npm install isotope-layout --save After installation, I added the script in my .angular-cli.json file: "scripts": [ ... " ...

Ionic: Error - Unable to access the 'ready' property of an undefined object

I keep encountering this error message: TypeError: Cannot read property 'ready' of undefined Here is the snippet of my code: angular.module('app', ['ionic', 'app.controllers', 'app.routes', 'app.dir ...

Ways to store information in variables and use it across different blocks in Cypress

Is it feasible to store data in variables and reuse them in other blocks within Cypress.io? For instance, imagine I have a unique name for a device. I aim to retrieve this information and then verify if the title in a new window includes that particular de ...

Steps to forward a restricted user to a specific webpage

I am currently utilizing NextJs and am in the process of creating a redirecting function for users who have been banned or blocked from accessing the DB/session. My attempt at this involved: redirect.js, where I created a custom redirect function. impo ...

I have implemented an email validation form in Angular, however, if the validation is not properly handled, the data will still be stored. How

When I enter an email address, for example: if I enter "abc" it shows an alert saying "please enter a valid email". If I leave it blank and try to submit, it shows an alert saying "email required". But when I click register, the data is saved regardless of ...

Attempting to transform HTML code received from the server into an image, but encountering an error while using ReactJS

This app is designed to automate the process of creating social media posts. I have a template for the vertical "Cablgram" stored in the backend, and when I make a request, it returns the HTML code for that template. However, I encounter an error when tryi ...

Is There a Quicker Alternative to Eval for Generating Deep Clones?

I am looking to create deep clones of a very large object called veryBigObject. To initialize veryBigObject, it first needs to be initialized using the initVeryBigObject function. Here is how this process looks: initVeryBigObject = function(){ veryBig ...

When working with Angular, the onSubmit method may sometimes encounter an error stating "get(...).value.split is not a function" specifically when dealing with Form

When the onSubmit method is called in edit, there is an error that says "get(...).value.split is not a function" in Form. // Code for Form's onSubmit() method onSubmitRecipe(f: FormGroup) { // Convert string of ingredients to string[] by ', ...

Display data from two arrays in real-time

The following data is available: "PensionPlanSummary": [ { "Type": "DefinedContributionPension", "Participants": [ { "Year": 2018, "Value": 425.0 } ...

The Angular mat-paginator is malfunctioning and not displaying the correct page sizes

I am facing an issue with the pagination display in my mat-table. Despite setting the page size to 5, all the results are being displayed on a single page. I fetch a list of transactions from an API and populate them in the table. I have tried various solu ...

Ways to transfer specific properties from one object to another in TypeScript

I'm currently working on a function that selectively copies key-value pairs from one object to another in order to remove certain properties. The code snippet for this function is shown below: sanitizeData: function (sourceObject: object, ...allowedKe ...