yabab-dev / ng2-codemirror

Angular2 CodeMirror component
MIT License
70 stars 30 forks source link

Added working output for initialization so that users can get the instance #18

Open rlodge opened 7 years ago

rlodge commented 7 years ago

Fixes #17

cmpilato commented 7 years ago

+1 for a change of this sort.

I'm upgrading an AngularJS app (which used ui-codemirror) to Angular2. ui-codemirror added a magic onLoad callback function option which carried the CodeMirror editor instance, allowing folks to hook directly into the event system, manually refresh the editor, etc. In my situation, this is important for a number of reasons (one of which is that I need to distinguish between change events that occur as the result of setValue being called and those which don't -- something I can't do by merely hooking into ng2-codemirror's (change) EventEmitter).

I would argue that if you provided a hook that gave access to the CodeMirror instance, you could drop the (focus), (blur), and (change) hooks because those are easy enough to tap into via the editor instance itself.

rlodge commented 7 years ago

I haven't seen any action on the PR or the underlying issue, but I've discovered it's also possible to subclass the component to get access. The below example uses a "settings service" that I'm using to allow a user to select a theme; all I need is to subscribe to the service's emitter and react by calling setOption, but you could do anything, including publishing the instance to your own emitter in the overridden method.

import {CodemirrorComponent} from "ng2-codemirror";
import {Component, forwardRef, OnDestroy} from "@angular/core";
import {NG_VALUE_ACCESSOR} from "@angular/forms";
import {SettingsService} from "../settings/settings.service";
import {Subscription} from "rxjs/Subscription";

//Make sure that the selector is DIFFERENT than the original component's.
@Component({
  selector: 'themable-codemirror',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ThemableCodemirrorComponent),
      multi: true
    }
  ],
  template: `<textarea #host></textarea>`,
})
export class ThemableCodemirrorComponent extends CodemirrorComponent implements OnDestroy {

  subscription: Subscription = null;

  constructor(private settingsService: SettingsService) {
    super()
  }

  codemirrorInit(config: any): void {
    super.codemirrorInit(config);
    this.subscription = this.settingsService.emitter.subscribe((theme) => {
      this.instance.setOption("theme", theme.classes.join(' '));
    });
  }

  ngOnDestroy(): void {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
    super.ngOnDestroy();
  }

}
cmpilato commented 7 years ago

I hadn't considered the subclassing idea (still pretty new to TypeScript). I'm taking a crack right now at a simple subclass that adds an @Output onInit: EventEmitter interface (like the PR carries).

cmpilato commented 7 years ago

...and it works! Thanks, @rlodge, for the inspiration!