Defining Custom Elements
In the previous example, we all use the default built-in block
node element, such as paragraph
using <div>
, in fact, we can define any type of custom block
node,
Such as block references, code blocks, list items, etc.
Next we show how to customize code block nodes in slate-ng
:
First Create Code Component
import {Component, ElementRef, Inject} from '@angular/core'; import {BaseElementComponent, Key, KEY_TOKEN, NsDepsService, NsEditorService} from 'slate-ng'; @Component({ selector: 'pre[custom-code]', template: ` <code> <ng-container *ngFor="let portal of portals; trackBy: trackBy"> <ng-template [cdkPortalOutlet]="portal"></ng-template> </ng-container> </code> ` }) export class CodeComponent extends BaseElementComponent { static type = 'code'; // 注意,这非常重要,必须存在,不然会造成这个Component无法被应用 constructor( @Inject(KEY_TOKEN) readonly key: Key, public deps: NsDepsService, public editorService: NsEditorService, public elementRef: ElementRef, ) { super(key, deps, editorService, elementRef); } }
Analyze::Here is an explanation of the above code:- Code Block 1:
This is to render<ng-container *ngFor="let portal of portals; trackBy: trackBy"> <ng-template [cdkPortalOutlet]="portal"></ng-template> </ng-container>
childPortals
, that is, child elements. Of course, you can directly use thens-portal-child
component provided inslate-ng
instead:
However, the use of<code> <ns-portal-entry [portals]="portals"></ns-portal-entry> </code>
ns-portal-entry
is not recommended. The main reason is that using this component to render sub-elements will add a layer of dom element wrapping inside. Although this does not affect the operation of the editor, it will deepen a layer of internal element nodes, so it is not recommended to use it in complex node components. - Code Block 2:
This inheritsexport class CodeComponent extends BaseElementComponent
BaseElementComponent
, which helps us to do a certain amount ofattr
increase and related content initialization, such as the previous use ofportals
, this is also handled byBaseElement
to export, and for this reason, we should also pay attention We need the corresponding dependencies ofsuper
, you can check xxx for detailsBaseElementComponent - Code Block 3:
Here is the node information that we can obtain. First, each node element will have its ownconstructor( @Inject(KEY_TOKEN) readonly key: Key, public deps: NsDepsService, public editorService: NsEditorService, public elementRef: ElementRef, ){//...}
key
as an identifier, which we obtain through@Inject(KEY_TOKEN)
. It can be combined withNsDepsService
to get all the dependencies required by the current component. For specific dependencies, please refer totoken(注意:token还没合理的划分,所以并非全部的token在element中都可被获取,API文档将会给出具体,待完成) - Code Block 4
static type = 'code';
Note! This is very important and is mainly used to mark which node type the Component belongs to. %/accordion%
- Code Block 1:
Import related dependencies into Module
@NgModule({ declarations: [ AppComponent, CodeComponent // <-- add ], imports: [ BrowserModule, AppRoutingModule, SlateNgModule, PortalModule // <-- add ], bootstrap: [AppComponent] }) export class AppModule { }
Note that because we will use
Angular CDK Portal
, we must injectPortalModule
, and secondly, because we will use<ng-template>
template syntax,CodeComponent
also needs to be registered inmodule
The last step is to use
RegistryNsElement
inapp.component.ts
to register toslate-ng
and add trigger conditions@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.less'], providers: [NsEditorService, NsDepsService, RegistryNsElement] }) export class AppComponent implements OnInit { title = 'angular-slate-demo'; editor = withHistory(withAngular(createEditor())); value = [ { type: 'paragraph', children: [{text: ''}] } ]; constructor( private registryNsElement: RegistryNsElement <-- add ) { } ngOnInit() { this.registryNsElement.add([CodeComponent]); <-- add } onKeyDown = (event: KeyboardEvent) => { <-- update if (event.key === '`' && event.ctrlKey) { event.preventDefault(); // Otherwise, set the type of the currently selected blocks to "code" Transforms.setNodes( this.editor, { type: 'code' } as any, { match: n => Editor.isBlock(this.editor, n) } ); } } }
Ok, let's open the page again, select part of the content, press Ctrl + ` to see the related styles~