ngx-codemirror
ngx-codemirror copied to clipboard
Can not use some addons
I try to use this addon: https://codemirror.net/demo/loadmode.html
The idea is to put all folder languages in my assets dir, and give formatted url etc ...
How can i access to this variable https://github.com/codemirror/CodeMirror/blob/29e338b8c1f27ade4502839877df7afd49584479/demo/loadmode.html#L65 with ngx-codemirror ?
accessing the editor property
use a viewchild ref to access the component and then its at the public codemirror property https://github.com/TypeCtrl/ngx-codemirror/blob/master/src/lib/codemirror.component.ts#L87
Thank you :)
Another problem: CodeMirror.autoLoadMode(instance, mode) must be called but this.codeMirror.codeMirror.autoLoadMode is not a function
After reading code of loadmode.js: https://github.com/codemirror/CodeMirror/blob/29e338b8c1f27ade4502839877df7afd49584479/addon/mode/loadmode.js#L58
The function seems to not be declared properly on codeMirror instance
I think is related to: https://github.com/codemirror/CodeMirror/issues/5484
Your import seems to be the same as described: https://github.com/TypeCtrl/ngx-codemirror/blob/d5cafceb528b8b95643bd0fa3a7ff858a5c63582/src/lib/codemirror.component.ts#L23 and nothing is correctly declared to the "fake" instance described.
its imported down further, those are just @types being imported at the top https://github.com/TypeCtrl/ngx-codemirror/blob/d5cafceb528b8b95643bd0fa3a7ff858a5c63582/src/lib/codemirror.component.ts#L98
You might make sure you've included your plugin correctly from the first step of use https://github.com/TypeCtrl/ngx-codemirror#use or make sure the codemirror instance has been created when your code runs

console.log(this.codeMirror.codeMirror), instance is ok. Viewer is ok, but when addons are loaded, no functions are inherited

Same problem with the meta mod:
Just for information, I use angular 6
This seems to be the case for all the addons
After a lot of debugging, it seems require creates a scoped instance of CodeMirror. Addons have to find a global instance of CodeMirror in plain mode to correctly work. fromTextArea doesn't return all CodeMirror object (this is why i did not find the addons functions).
My final solution is to mix global instance and this component. For this i need to declare in angular.json all the scripts to import:
"scripts": [
"node_modules/codemirror/lib/codemirror.js",
"node_modules/codemirror/mode/meta.js",
"node_modules/codemirror/addon/mode/loadmode.js"
]
If we use fromTextArea from scoped instance, the setOption function will not work. In ngx-codemirror component replace:
declare var require: any; // remove this
const { fromTextArea } = require('codemirror');
this.codeMirror = fromTextArea(this.ref.nativeElement, this._options);
by:
declare var CodeMirror: any; // replaced by "var require..."
this.codeMirror = CodeMirror.fromTextArea(this.ref.nativeElement, this._options);
In my internal component i use declare var CodeMirror: any to access all functions (ref is the childView of ngx-codemirror component)
ngAfterViewInit() {
CodeMirror.modeURL = this.modeUrl
const mode = CodeMirror.findModeByFileName(this.file.name).mode // this function is loaded by meta addon
CodeMirror.autoLoadMode(this.ref.codeMirror, mode) // this function is loaded by loadmode addon
this.ref.codeMirror.setOption('mode', mode)
}
Importing addons like modes as described in the README works perfectly. Here's my main.ts
file:
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
// Import your required language in main.ts or at the root of your application
// see https://codemirror.net/mode/index.html
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/css/css';
import 'codemirror/mode/htmlmixed/htmlmixed';
import 'codemirror/addon/edit/matchbrackets';
import 'codemirror/addon/edit/closetag';
import 'codemirror/addon/selection/active-line';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
and here's my options object to enable the above addons:
editorOptions = {
lineNumbers: true,
autoCloseTags: true,
styleActiveLine: true,
theme: 'monokai',
mode: 'text/html',
// define Emmet output profile
profile: 'xhtml'
};
Btw, thank you a lot @scttcper for this awesome ngx wrapper for codemirror! 🙌 Cheers!
This only works for addons that affect the editor (CodeMirror.fromTextArea)
@johaven I got it! Good to know. 👍
@johaven i'm not sure how to fix it for your case. You might try copying out the component and instantiating codemirror as you require, unless there's a way to make it work for everyone's general use.
@scttcper This is what i do for the time being. But if you replace the 2 lines of code, it should work for everyone:
declare var CodeMirror: any; // replaced by "var require..."
this.codeMirror = CodeMirror.fromTextArea(this.ref.nativeElement, this._options);
If people want to use other addons like me, they will only have to load the libraries via the Angular scripts tag above, for others it will work the same way.
I am attempting to do something similar except in my case is to dynamically define the mode and load it on the fly based on a matrix of user provided data... @johaven could you provide a StackBlitz showing what you did to get loadmode functional? because I am hitting a brick wall trying to deduce this thread.
I do not have much time but I will give you my configuration.
angular.json
"scripts": [
"node_modules/codemirror/lib/codemirror.js",
"node_modules/codemirror/mode/meta.js",
"node_modules/codemirror/addon/mode/loadmode.js",
"node_modules/codemirror/addon/mode/overlay.js"
]
codemirror.component.ts diff I declare this modified component in my module.
Usage example
import {AfterViewInit, Component, Input, OnInit, ViewChild, ViewEncapsulation} from '@angular/core'
import {HttpClient} from '@angular/common/http'
declare var CodeMirror: any
@Component({
selector: 'app-files-viewer-text',
encapsulation: ViewEncapsulation.None,
styles: [`
.CodeMirror {
height: 100%
}
`],
template: `
<div [style.height.px]="currentHeight">
<ngx-codemirror #CodeMirror [(ngModel)]="content" [options]=options></ngx-codemirror>
</div>`
})
export class FilesViewerTextComponent implements OnInit, AfterViewInit {
@ViewChild('CodeMirror') ref: any
@Input() currentHeight: number
@Input() file: any
@Input() fileUrl: string
private readonly modeUrl = '/static/assets/codemirror/mode/%N/%N.js'
public content: string
public options: any = {lineNumbers: true, readOnly: true, theme: 'material', mode: 'null'}
private mode: string = null
constructor(private http: HttpClient) {
CodeMirror.modeURL = this.modeUrl
}
ngOnInit() {
const detectedMode = CodeMirror.findModeByFileName(this.file.name)
if (detectedMode) {
this.mode = detectedMode.mode
this.http.get(this.fileUrl, {responseType: 'text'}).subscribe((data: string) => this.content = data)
} else {
this.content = 'This file contains binary data that can not be read'
}
}
ngAfterViewInit() {
if (this.mode) {
CodeMirror.autoLoadMode(this.ref.codeMirror, this.mode)
this.ref.codeMirror.setOption('mode', this.mode)
}
}
}
Hello, i also had problems to use the mergeView addon, but finally made it, so here is my sample codemirror-merge-view
@scttcper this can be closed