Home > OS >  Object unsubscribed when navigating from component to another component
Object unsubscribed when navigating from component to another component

Time:08-16

I am implementing a virtual keypad in my application but am getting the following error when navigating from my second component to my first component. I created a stackblitz example of the issue.

https://stackblitz.com/edit/onscreen-keyboard-ajten3?file=src/app/app.module.ts

As you will see I can navigate and use the keyboard when I go from the first component to the second component but when I return the the first component then I get an error ERROR Error: object unsubscribed

Here is the code in my directive that controls the subscriptions

import {
  Directive,
  OnInit,
  ElementRef,
  Renderer2,
  HostListener
} from "@angular/core";
import { KeyboardService } from "./keyboard.service";
import { Subscription } from "rxjs";

@Directive({
  selector: "[appOskInput]"
})
export class OskInputDirective implements OnInit {
  private keySubscription: Subscription;
  private backspaceSubscription: Subscription;
  private enterSubscription: Subscription;
  private measure: HTMLElement;

  constructor(private el: ElementRef, private keyboard: KeyboardService) {}

  ngOnInit() {
    // TODO I'm sure there's an "Angular way" of doing this
    let thisStyle = window.getComputedStyle(this.el.nativeElement);
    this.measure = document.createElement("span");
    this.measure.style.position = "absolute";
    this.measure.style.right = "100%";
    this.measure.style.font = thisStyle.font;
    document.body.appendChild(this.measure);
  }

  @HostListener("focus")
  private onFocus() {
    this.keyboard.fireKeyboardRequested(true);
    this.subscribeToKeyboardEvents();
  }

  @HostListener("blur")
  private onBlur() {
    this.keyboard.fireKeyboardRequested(false);
    this.unsubscribeFromKeyboardEvents();
  }

  private subscribeToKeyboardEvents() {
    this.keySubscription = this.keyboard.keyPressed.subscribe(key =>
      this.onKey(key)
    );
    this.backspaceSubscription = this.keyboard.backspacePressed.subscribe(_ =>
      this.onBackspace()
    );
    this.enterSubscription = this.keyboard.enterPressed.subscribe(_ =>
      this.onEnter()
    );
  }

  private unsubscribeFromKeyboardEvents() {
    this.keySubscription.unsubscribe();
    this.backspaceSubscription.unsubscribe();
    this.enterSubscription.unsubscribe();
  }

}

Any idea what I can do to fix this?

CodePudding user response:

Dont unsubscribe the source observable this.keyboard.shiftChanged this is causing the issue, instead add the subscribes of the component to a subscription this.subscription, and then finally unsubscribe the subscriptions added on ngOnDestroy.

import {
  Directive,
  Input,
  HostBinding,
  HostListener,
  OnInit,
  OnDestroy,
} from '@angular/core';
import { Subscription } from 'rxjs';
import { KeyboardService } from '../app/keyboard.service';

@Directive({
  selector: '[appKeyboardKey]',
})
export class KeyboardKeyDirective implements OnInit, OnDestroy {
  private _values: string[];
  private isShifted: boolean;
  private isAlt: boolean;
  subscription: Subscription = new Subscription();

  @Input('appKeyboardKey') values: string;

  @HostBinding('innerText') currentValue: string;

  constructor(private keyboard: KeyboardService) {}

  ngOnInit() {
    this._values = this.values.split(' ');
    this.currentValue = this._values[0];

    this.subscription.add(
      this.keyboard.shiftChanged.subscribe((shift) => {
        this.isShifted = shift;
        this.updateCurrentValue();
      })
    );
    this.subscription.add(
      this.keyboard.altChanged.subscribe((alt) => {
        this.isAlt = alt;
        this.updateCurrentValue();
      })
    );
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

  updateCurrentValue() {
    if (!this.isAlt) {
      if (!this.isShifted) {
        this.currentValue = this._values[0];
      } else {
        this.currentValue = this._values[0].toUpperCase();
      }
    } else {
      if (!this.isShifted) {
        this.currentValue = this._values[1];
      } else {
        this.currentValue = this._values[2];
      }
    }
  }

  @HostListener('click')
  onClick() {
    this.keyboard.fireKeyPressed(this.currentValue);
  }
}

stackblitz

  • Related