Search code examples
javascriptangulartypescriptrxjscodemirror

debounceTime to CodeMirror Angular


I have already tried multiple variations also following This Possible Dup

Using the ng2-codemirror 1.1.3 lib + codemirror 5.33.0 anchor

All I'm trying to do is to attach a DebounceTime operator to the change event of the CodeMirror Editor

html:

<codemirror #cm [(ngModel)]="code" [config]="config" (focus)="onFocus()" (blur)="onBlur()"></codemirror>

ts:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/debounceTime';

@ViewChild('cm') editor;

ngAfterViewInit() {
  const watch = Observable.fromEvent(this.editor, 'change'); // <--- Error
  watch.subscribe(v => console.log(v));
}

The error I'm getting is:

ERROR TypeError: Invalid event target

I've also tried attaching the Observable.fromEvent to this.editor.value/ this.editor.input

EDIT Entire Component: component.HTML:

<codemirror #cm [(ngModel)]="code" [config]="config" (focus)="onFocus()" (blur)="onBlur()"></codemirror>

component.TS:

import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { global } from '../shared/global.constants';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/addon/scroll/simplescrollbars';
import 'codemirror/addon/hint/javascript-hint';
import 'codemirror/addon/hint/show-hint.js';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/debounceTime';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.scss']
})
export class MainComponent implements OnInit, AfterViewInit {
  @ViewChild('cm') editor;
  @ViewChild('output') output;
  code = global.code;
  config = {
    lineNumbers: true,
    mode: {name: 'javascript', json: true},
    tabSize: 2,
    scrollbarStyle: 'simple',
    extraKeys: {'Tab': 'autocomplete', 'Ctrl-Space': 'autocomplete'}
  };

  constructor() {

  }

  ngOnInit() {

  }

  ngAfterViewInit() {
    console.log(this.editor); // <--- CodemirrorComponent {change: EventEmitter, focus: EventEmitter, blur: EventEmitter, cursorActivity: EventEmitter, instance: CodeMirror$1, …}
    console.log(this.editor.nativeElement); // <--- undefined
    const watch = Observable.fromEvent(this.editor.host.nativeElement, 'input');
    console.log(watch);
    watch.subscribe(w => console.log(w)); // <-- invalid target
  }
}

Solution

  • Considering that <codemirror> is a component, @ViewChild('cm') editor queries an instance of component class, while @ViewChild('cm') editor: ElementRef just tricks typing system but doesn't affect editor value.

    As the reference explains, read property is used to specify which token should be queried. In order to force it to be ElementRef, it should be:

    @ViewChild('cm', { read: ElementRef }) editor: ElementRef;
    

    Then event listener can be added to DOM element (as another answer already explains):

    const watch = Observable.fromEvent(this.editor.nativeElement, 'change');