I need to change the content and UI language of the CKEditor5 when I click a button. Here's a screenshot of the app. On each button click, the config is updated with the new language selected. But the CKEditor remains with the same configuration when it has been initialized. How can we modify the content and UI of the editor dynamically using Angular or TypeScript?
Note: I'm using Angular 5, Angular CLI 1.7.4. And also I'm using CKEditor5 version 1.2.3
Here's the .ts component code:
import { Component, OnInit } from '#angular/core'
import { ChangeEvent } from '#ckeditor/ckeditor5-angular'
import * as ClassicEditor from '#ckeditor/ckeditor5-build-classic'
#Component({
selector: 'another-text-editor',
templateUrl: './another-text-editor.component.html',
styleUrls: ['./another-text-editor.component.css']
})
export class TextEditorComponent implements OnInit{
languages = [
{ id: 'fr', label: 'French' },
{ id: 'de', label: 'German' },
{ id: 'ar', label: 'Arabic' }
]
public Editor = ClassicEditor
config = {
toolbar: ['bold', 'italic'],
language: { ui: 'fr', content: 'fr' }
}
constructor () {}
ngOnInit () {}
changeConfig (lang) {
this.config = {
...this.config,
language: {
ui: lang,
content: lang
}
}
}
public onChange ({editor}: ChangeEvent) {
console.log(editor.getData())
}
}
And here's the HTML code for the component:
<div class="container pt-4">
<ckeditor [editor]="Editor" id="editor" tagName="textarea" [config]="config" [(ngModel)]="text" (change)="onChange($event)"></ckeditor>
<div class="row justify-content-start align-items-center mt-4">
<div class="col-auto" *ngFor="let lang of languages">
<button class="btn btn-primary" (click)="changeConfig(lang)">
Click for {{lang.label}}
</button>
</div>
</div>
</div>
I've added the translation files in .angular-cli.json:
"scripts": [
"../node_modules/#ckeditor/ckeditor5-build-classic/build/translations/de.js",
"../node_modules/#ckeditor/ckeditor5-build-classic/build/translations/fr.js",
"../node_modules/#ckeditor/ckeditor5-build-classic/build/translations/ar.js"
],
Related
I am using Ng-zorro to display a custom modal component inside a lazy loaded component:
component used to display custom modal:
showArtistModal(artist: any): void {
this.modalService.create({
nzContent: ArtistModalComponent,
nzComponentParams: {
artist,
},
nzCentered: true,
// nzOnOk: () => new Promise((resolve) => setTimeout(resolve, 1000)),
// nzFooter: [
// {
// label: 'Close',
// shape: 'round',
// onClick: () => modal.destroy(),
// },
// {
// label: 'Confirm',
// type: 'primary',
// onClick: () => modal.destroy(),
// },
// ],
})}
custom modal component:
import { Component, Input } from '#angular/core';
import { NzModalRef } from 'ng-zorro-antd/modal';
#Component({
selector: 'app-artist-modal',
templateUrl: './artist-modal.component.html',
styleUrls: ['./artist-modal.component.scss'],
})
export class ArtistModalComponent {
#Input() artist;
constructor(private modal: NzModalRef) {}
destroyModal(): void {
this.modal.destroy();
}
}
Template:
<div>
<div *nzModalTitle>
{{artist.name}}
</div>
<div>
truc
</div>
<div *nzModalFooter>
<button nz-button nzType="primary" (click)="destroyModal()">Close</button>
</div>
</div>
Shared module:
import { NgModule } from '#angular/core';
// Components
import { ArtistModalComponent } from './artist-modal/artist-modal.component';
// NgZorro Components
import { NzGridModule } from 'ng-zorro-antd/grid';
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzModalModule } from 'ng-zorro-antd/modal';
import { NzButtonModule } from 'ng-zorro-antd/button';
#NgModule({
imports: [NzCardModule, NzGridModule, NzModalModule, NzButtonModule],
exports: [
ArtistModalComponent,
NzCardModule,
NzGridModule,
NzModalModule,
NzButtonModule,
],
declarations: [ArtistModalComponent],
})
export class SharedModule {
constructor() {}
}
But I cannot close the modal when it is displayed, the destroy() event is not triggered and the closing button is not working. Am I missing something ? Already tried to move everything in the same module as the component used to display the modal but it is still not working.
I am using Angular 12.
I have an application which looks like on the image below.I used mattabs inside nav links.
this.navLinks = [
{
label: 'Preview',
link: './1',
index: 0
}, {
label: 'Tuning',
link: './tabtest2',
index: 1
}, {
label: 'Payment',
link: './tabtest3',
index: 2
},
];
in this code part when I press preview it shows me the 2nd element on the list(array).Thats exactly how I want it to work but it should be controlled dynamically.I made string concatanation and changed with that link on the preview tab but URL isnt recognizable.My concatanation is exactly same like '.1' on the link property
Here's what I tried below
TS File
import { Component, OnInit } from '#angular/core';
import { Car } from './car.model';
import { CarService } from './car.sevice';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Subject } from 'rxjs';
#Component({
selector: 'app-cars',
templateUrl: './cars.component.html',
styleUrls: ['./cars.component.css']
})
export class CarsComponent implements OnInit {
navLinks: any[];
public href: string = "";
activeLinkIndex = -1;
mySubject;
ngOnInit(): void {
this.href = this.router.url;
console.log(this.router.url);
this.router.events.subscribe((res) => {
this.activeLinkIndex = this.navLinks.indexOf(this.navLinks.find(tab => tab.link === '.' + this.router.url));
});
this.mySubject=this.carService.carrierSubject.subscribe(value=>
{
this.id=value;
let numid=this.id.toString();
this.newString="./".concat(numid);
console.log(this.newString);
})
}
newString:string='';
id:number;
car:Car;
constructor(private carService:CarService,private route: ActivatedRoute,private router: Router) {
this.navLinks = [
{
label: 'Preview',
link: '.1',
index: 0
}, {
label: 'Tuning',
link: './tabtest2',
index: 1
}, {
label: 'Payment',
link: './tabtest3',
index: 2
},
];
}
onTuning()
{
this.router.navigate(['tuning'], {relativeTo: this.route});
}
}
HTML
<div class="row">
<div class="col-md-5">
<app-car-list></app-car-list>
</div>
<div class="col-md-7">
<nav mat-tab-nav-bar>
<a mat-tab-link
*ngFor="let link of navLinks"
[routerLink]="link.link"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{link.label}}
</a>
</nav>
<router-outlet></router-outlet>
</div>
</div>
I have to click on the following menu "Text View" tab (mat-tab-link) twice to get the router-outlet to become active and underline the tab. I know this because of the documents.component.html content for the radio buttons, in it does not become active, unless I click twice on the Text View tab. Then the "Option 4" button shows active, and the tab underlines.
documents-pane.component.html
<nav mat-tab-nav-bar aria-label="documentsTabs">
<a class="navbar-brand" [routerLink]="['/customApp']">CustomApp</a>
<a mat-tab-link
*ngFor="let link of navLinks"
[routerLink]="link.path"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive"
skipLocationChange>
{{link.label}}
</a>
</nav>
<router-outlet></router-outlet>
documents-pane.component.ts
import { Component, OnInit } from '#angular/core';
import { CustomAppDocumentsComponent } from './documents/documents.component';
import { CustomAppGridComponent } from './grid/grid.component';
import { CustomAppSearchComponent } from './customApp-search/customApp-search.component';
#Component({
selector: 'app-documents-pane',
templateUrl: './documents-pane.component.html',
styleUrls: ['./documents-pane.component.scss'],
})
export class CustomAppDocumentsPaneComponent implements OnInit {
constructor() { }
ngOnInit() {
}
navLinks = [
{path: 'documents', label: 'Text View'},
{path: 'grid', label: 'Grid View'},
{path: 'customApp-search', label: 'Search Terms'},
]
}
app-routing.module.ts
...
import { CustomAppDetailComponent } from './customApp/customApp-detail.component';
import { CustomAppBaseComponent } from './customApp/documents-pane/customApp-base/customApp-base.component';
import { CustomAppDocumentsComponent } from './customApp/documents-pane/documents/documents.component';
import { CustomAppGridComponent } from './customApp/documents-pane/grid/grid.component'
import { CustomAppSearchComponent } from './customApp/documents-pane/customApp-search/customApp-search.component'
...
...
const routes: Routes = [
{
path: 'customApp',
component: CustomAppDetailComponent,
children: [
{
path: '',
component: CustomAppBaseComponent,
},
{
path: 'customApp-base',
component: CustomAppBaseComponent,
},
{
path: 'documents',
component: CustomAppDocumentsComponent,
},
{
path: 'grid',
component: CustomAppGridComponent,
},
{
path: 'customApp-search',
component: CustomAppSearchComponent,
},
]
}
...
documents.component.html
<div style='float: left; width: 75%;'>
<mat-radio-group formControlName="testEntryOption">
<mat-radio-button class="material-radio" value="opt1">Option 1</mat-radio-button>
<mat-radio-button class="material-radio" value="opt2">Option 2</mat-radio-button>
<mat-radio-button class="material-radio" value="opt3">Option 3</mat-radio-button>
<mat-radio-button class="material-radio" value="opt4" [checked]="true">Option 4</mat-radio-button>
</mat-radio-group>
</div>
<div style='float: left; width: 25%;'>
<mat-button-toggle-group name="buttonSelection">
<mat-button-toggle value="button1">Button 1</mat-button-toggle>
<mat-button-toggle value="button2">Button 2</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div>
documents works!
</div>
I have tried several other code implementations, even a bootstrap menu bar, with no luck. Any input is greatly appreciated. What are my options?
I was relatively new to Angular and had serious issues before i figured out a way to do this.
use this link to preview the solution
<https://plnkr.co/edit/OtJI13uA89caf8TG5lbI?p=preview>?
To dymanically populate your ng2-smart-table, you may follow the steps below.
1. Import smart table component in your module.
import { LocalDataSource } from "ng2-smart-table";
2.add the following code to your class.
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="addColumn()">Add Column</button>
<ng2-smart-table [settings]="settings" [source]="source"></ng2-smart-table>
</div>
`,
})
export class ResultComponent implements OnInit
{
source: LocalDataSource;
i = 0;
settings;
mySettings = {
mode: 'inline',
actions: {
delete:false,
},
add: {
confirmCreate: true,
},
delete: {
confirmDelete: true,
},
edit: {
confirmSave: true,
},
columns: {
}
};
//method that adds the column. You can use trigger events to do this
public addColumn() {
this.mySettings.columns["new column " + this.i] = { title: 'new column
' + this.i.toString()};
this.settings = Object.assign({}, this.mySettings);
this.i++;
}
}
I am using material design and have a dialogService set up for dynamically loading MdDialog. I'm trying to make a search dialog with search filters that when submitted it brings you to a search-results component route. And I can't figure out how to output the search data to the search-results component.
./dialog-service.ts
#Injectable()
export class DialogService {
private dynamicModalComponent: DialogComponent;
public init(dynModal: DialogComponent) {
this.dynamicModalComponent = dynModal;
}
public show(component: Type<any>, configuration?: MdDialogConfig) {
this.dynamicModalComponent.showModal(component, configuration);
}
public hide() {
this.dynamicModalComponent.hideModal();
}
}
./modules/search.component.html
<div class="search-component">
<h2>Search</h2>
<md-input-container class="full-width search">
<input mdInput placeholder="search" color="primary" />
</md-input-container>
<div class="radio-groups">
<md-radio-group class="radio-buttons" [(ngModel)]="searchFilterValue">
<md-radio-button class="r-button" [value]="sf.value" *ngFor="let sf
of searchFilter">
{{sf.name}}
</md-radio-button>
</md-radio-group>
</div>
<md-dialog-actions class="actions">
<button md-button (click)="hide()">Cancel</button>
<button md-raised-button (click)="search()"
color="primary">Search</button>
</md-dialog-actions>
</div>
./modules/search.component.ts
import {Component, OnInit} from "#angular/core";
import {DialogService} from "../dialog/dialog.service";
import {Router} from "#angular/router";
#Component({
selector: 'search',
templateUrl: './search.component.html',
styleUrls:['./search.component.scss']
})
export class SearchComponent implements OnInit {
searchFilterValue;
searchFilter = [
{
name: 'Groups',
value: 'groups',
},
{
name: 'People',
value: 'users',
},
{
name: 'Events',
value: 'events',
},
{
name: 'Posts',
value: 'posts',
}
];
constructor(private _dialogService: DialogService,
private router: Router){
this.searchFilterValue = 'groups';
}
ngOnInit(){}
hide() {
this._dialogService.hide();
}
search() {
this.hide();
this.router.navigate(['/search']);
}
}
You have several options:
1) You could use optional or query routing parameters. Then as part of the router.navigate, you'd also pass along the parameters. This is a great option if you need to pass data from this component directly to another component.
2) Another option is to build a service. The service holds onto the search filter values. The search component sets the values into the service and the component then reads the values from the service.
Do one of these options sound like they could work for you?
You can define an output event for hide/close event and pass result as event argument.Other components can subscribe such event to handle result.