Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Docs] Example integration with React, Angular 1/2+, Vue, Ember #599

Closed
Reinmar opened this issue Oct 11, 2017 · 24 comments
Closed

[Docs] Example integration with React, Angular 1/2+, Vue, Ember #599

Reinmar opened this issue Oct 11, 2017 · 24 comments
Labels
type:docs This issue reports a task related to documentation (e.g. an idea for a guide).
Milestone

Comments

@Reinmar
Copy link
Member

Reinmar commented Oct 11, 2017

There's been a lot of discussion around Angular in #347 but we need some summary in form of a documentation.

Similarly, we need some documentation about integration with React, Vue and Ember.

If anyone is willing to give it a try we'd be grateful for step-by-step introductions to how to initialize and integrate CKEditor 5 with those platforms. The simplest way you can share such tutorials with us is by writing them in comments in this thread and we'll convert them to guides that can be published on https://docs.ckeditor.com/ckeditor5/latest/. Thanks in advance!


UPDATE (27.07.2018)

💥 We released official integrations for React and Angular 💥

@Reinmar Reinmar added status:confirmed type:docs This issue reports a task related to documentation (e.g. an idea for a guide). labels Oct 11, 2017
@figuerres
Copy link

Sounds good!

@stnor
Copy link

stnor commented Oct 17, 2017

Angular1 example using two-way binding with ngModel:

import CkEditor from "@ckeditor/ckeditor5-build-classic";
export default class CkEditorDirective {

   constructor() {
     this.restrict = 'A';
     this.require = 'ngModel';
   }

  static create() {
    return new CkEditorDirective();
  }

  link(scope, elem, attr, ngModel) {
    CkEditor.create(elem[0]).then((editor) => {
      editor.document.on('changesDone', () => {
        scope.$apply(() => {
          ngModel.$setViewValue(editor.getData());
        });
      });

      ngModel.$render = () => {
        editor.setData(ngModel.$modelValue);
      };

      scope.$on('$destroy', () => {
        editor.destroy();
      });
    })
  }
}

Registration:

export default angular.module('admin.newsletter', [])
    .directive('ckEditor', CkEditorDirective.create)

Usage:

<textarea ck-editor ng-model="$ctrl.body"></textarea>

@Reinmar
Copy link
Member Author

Reinmar commented Oct 17, 2017

Thanks!

One thing I spotted here is that this code doesn't handle rejecting the promise returned by CKEditor.create().

And actually a second thing – the change event is fired on every atomic change and retrieving data after each of those atomic operations are applied may be unsafe. I think that it would be safer to listen to changesDone (fired when a whole set of changes is being rendered).

We're aware that this bit with the change event may be confusing and we'll rethink it during the planned engine refactoring (in this ticket, to be precise).

@stnor
Copy link

stnor commented Oct 17, 2017

Ok, thanks.
I updated the example to use changesDone. When it comes to the rejection-handling, I'm not sure what to do should it fail. One could always add

.catch((error) => {
      console.error(error);
    });

@Reinmar Reinmar changed the title [Docs] Example integration with React and Angular [Docs] Example integration with React, Angular 1/2+, Vue Oct 18, 2017
@Reinmar Reinmar changed the title [Docs] Example integration with React, Angular 1/2+, Vue [Docs] Example integration with React, Angular 1/2+, Vue, Ember Oct 18, 2017
@gurnzbot
Copy link

I have ckeditor v4.7.3 running in my react app. I have file browser/uploads working as well.
Truly thanks to https://github.com/codeslayer1/react-ckeditor to get the ball rolling and all easy updates of new ckeditor builds/versions.

If I can be of any help please let me know how.

@pburrows
Copy link

pburrows commented Nov 7, 2017

Here's a VERY primitive Angular2+ example. Note that it only works about 25% of the time for me because of this error. Enough reloading usually gets it to work.

import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';

declare var ClassicEditor: any;

@Directive({
	selector: '[ckeditor]'
})
export class CkEditorDirective {

	@Output() change: EventEmitter<string> = new EventEmitter();

	constructor(el: ElementRef) {
		console.log(el.nativeElement);
		ClassicEditor.create(el.nativeElement)
			.then(editor => {
				editor.document.on('changesDone', () => {
					const data: string = editor.getData();
					this.change.emit(data);
				});
				console.log(editor);
			}, (err) => {
				if (err.message.indexOf('TypeError: e.on is not a function') >= 0) {
					console.log('grr!');
				}
				console.log(err.message);
				console.log(err);
			});
	}
}

and then the html would look like this:

<textarea class="form-control" ckeditor (change)="textChanged($event)" [(ngModel)]="requestText"></textarea>

@chihab
Copy link

chihab commented Nov 16, 2017

Nice initiative, I think it would be better to have a separate issue for each framework.

As for Angular, the main issue I've found is loading svg items, since internally angular cli rule on svg assets is to use file-loader instead of raw-loader used in CKeditor webpack config.

The only solution I've came up with is to eject webapack config using 'ng eject' which gives you the whole webpack config under the hood (running webpack would then be exactly same as ng build) but now you do have hands on webpack config.

Modifications I've made to make it suitable for my use case:

      {
        // Or /ckeditor5-[^/]+\/theme\/icons\/[^/]+\.svg$/ if you want to limit this loader
        // to CKEditor 5's icons only.
        test: /ckeditor5-[^/]+\/theme\/icons\/[^/]+\.svg$/,
        use: ['raw-loader']
      },
      {
        "test": /(ionicons|font-awesome).*\/[^/]+\.svg$/,
        "loader": "file-loader",
        "options": {
          "name": "[name].[hash:20].[ext]",
          "limit": 10000
        }
      },
      {
        "test": /\.(eot|cur)$/,
        "loader": "file-loader",
        "options": {
          "name": "[name].[hash:20].[ext]",
          "limit": 10000
        }
      }

Note that I had to replace "test": /\.(eot|svg|cur)$/ with "test": /\.(eot|cur)$/ and make specific regexp for my svg resources folders.

I was trying not to override/modify webpack config and keep with angular cli simple usage but as far as I understood, the only way to have that would be that CKeditor uses file loader for svg resources rather than raw-loader (don't really know what I am talking about thought).

@pat123456
Copy link

pat123456 commented Nov 17, 2017

Hi,

This is how I integrated v.5 in vue.js component (with two-way biding):
(more setup could be added, for ex like in this v.4 integration : https://github.com/dangvanthanh/vue-ckeditor2/blob/master/src/VCkeditor.vue

But I feel it's still a little bit "tinker". Ckeditor 5 is mvc based, could not there be the possibility to directly connect/bind the "model" of the editor with vuejs data/model (or other js framework) ?

<template>
	<textarea id="editor" :value="value"
        v-on:input="updateValue($event.target.value)" >
	</textarea>
</template>

<script>
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';

export default {
    name: "ckeditor",
    data: function () {
        return {
            instance: null
        }
    },
    props: ['value'],
    watch: {
        value(){
            let html = this.instance.getData();

            if(html != this.value){
                this.instance.setData(this.value)
            }
        }
    },
    mounted(){

        ClassicEditor
            .create( this.$el, {
                toolbar: [ 'bold', 'italic', 'link', 'bulletedList']
            } )
            .then( editor => {
                this.instance = editor;
			
                editor.document.on( 'changesDone', ( evt, data ) => {
                    this.updateValue(editor.getData())
                } );
            } )
            .catch( error => {
                console.error( error );
            } );
        },
        methods: {
            updateValue: function (value) {
                this.$emit('input', value)
            }
        }
}
</script>

and use it like that :
<ckeditor v-model="editorcontent"></ckeditor>

@pat123456
Copy link

@chihab why do you need to take care about webpack.config and svg integration when using ckeditor with angular ? normaly we only use builds versions of ckeditor in framework projects, not sources ?
I'm pretty new with ckeditor and don't know angular, so may my question make no sense...

@chihab
Copy link

chihab commented Nov 18, 2017

@pat123456 I am also pretty new to ckeditor and your observation totally makes sense. My project has to use a custom build and at the begging I was making a poc to test its integration into an existing angular project
A better approach would certainly be to maintain a separate project for ckeditor custom build specific to our needs and that would be agnostic to the application framework and then only have to use it inside the project as a directive or a component. I was also thinking about making it a separate web component using ionic's stencil project.

@pat123456
Copy link

Ok understand. Yes seems more logic to have a separate framework/build project. Anyway, for the documentation it's certainly the method to describe in priority.

@figuerres
Copy link

@pburrows hey i am trying to get ckeditor5 working in my angular 5 app.
used your sample code but something is missing.
it compiles with ng build but it looks like the editor code is not getting added to my bundles so at runtime i get an error that the editor is not defined.

any ideas ?
does anyone have a working sample to check with ?

do i need to add something to modules ?
do i need to force a script to be added outside of angular/build ?

@pburrows
Copy link

pburrows commented Dec 7, 2017

The code I posted is a directive. So, make sure that whatever module it is in CkEditorDirective is in both the "exports" and "declarations" section. And then make sure you are importing that module into whatever other module you want to use.

You do not need to add scripts anywhere else (such as to the .angular-cli.json file).

Also, I have the directive in a separate "shared" module. If you choose to put it all in the same module, you still need to add it to declarations for that module.

@figuerres
Copy link

one module -- the app.
my @NgModule has it in the declare like my other directive code, the other one works btw.
so the basic setup is right.

in trying to make it work i did find that adding it to my angular-cli file DOES make it work.
as far as i can see before i did that i got the runtime undfined error.
i will go back and re-try some things and see if any other things changed.

one other item: i am building with angular 5 not 4 -- angular 5 compile / build is a bit different than 4 and may not pull in code if it can not see it used.
have you tried your code with V5 of angular ??

@pburrows
Copy link

pburrows commented Dec 7, 2017

Good point. It is probably a v4 vs v5 difference. I haven't updated to v5 yet.

@figuerres
Copy link

@pburrows
also one other thing to check, which package did you npm install ?? that may also be a factor in what happens. i used the classic editor build, but there are other packages that can be used ...

@figuerres
Copy link

so far i have not found a way to pull in the script unless i use a pre built editor package and use the angular-cli json file.
that does pull in the script but does not allow angular compiler to do anything with it other than add it to the project.

@lbjones
Copy link

lbjones commented Apr 16, 2018

With the lastest release, this code no longer works:

editor.document.on('changesDone', () => {
   this.$emit('input', this.instance.getData());
});

After searching through the documentation, I haven't been able to find the proper way to detect changes to the editor. Any ideas?

@Reinmar
Copy link
Member Author

Reinmar commented Apr 17, 2018

Since beta.1 there's no changesDone event anymore. You can now use the Document#change event now. Refer to its documentation for a description how it works and what it means.

@Reinmar
Copy link
Member Author

Reinmar commented May 14, 2018

We began the work on Angular (#1020) and React (#1015) components for CKEditor 5.

We've got some doubts in #1020 on how to propose this component in the most flexible way. We'll be grateful for all the feedback.

@ma2ciek
Copy link
Contributor

ma2ciek commented Jul 26, 2018

We've just released ckeditor5-angular and ckeditor5-react on the NPM 🎉

Both of them provide comprehensive readme files, so you can integrate them easily into your applications.

@wwalc
Copy link
Member

wwalc commented Jul 31, 2018

Just a note that this ticket should not be closed until we add proper content in the official documentation (a dedicated section/article(s) for integrations). A significant group of users when looking for Angular/React instruction will simply use the search input in the official documentation.

The first result that currently is returned when looking for React contains pretty outdated information:
https://docs.ckeditor.com/ckeditor5/latest/builds/guides/faq.html#how-to-use-ckeditor-5-with-frameworks-angular-react-etc

@Reinmar
Copy link
Member Author

Reinmar commented Sep 20, 2018

I updated existing docs (including the FAQ). All of them link to #1002 where I'd like to gather all feedback regarding next frameworks we can work on.

@Reinmar Reinmar modified the milestones: backlog, iteration 20 Sep 20, 2018
@abhinavdypp
Copy link

abhinavdypp commented Dec 15, 2020

Hi , I have some problem with svg tag on ckeditor5 . In my case ckeditor filter out svg tag .So i have written schema for this but now SVG tag is now working fine but its child element filter out . please help me on this .

            editor5._instance.model.schema.register( 'circle', {
                    allowIn: [ '$text', 'paragraph', '$block' ],
                    allowAttributes: [ '*' ]//'width', 'height', 'cx', 'cy', 'r', 'stroke', 'fill'
                } );
                editor5._instance.model.schema.register( 'svg', {
                    allowIn: [ '$text', 'paragraph', '$block','image' ],
                    allowAttributes: [ '*' ]//'width', 'height', 'cx', 'cy', 'r', 'stroke', 'fill'
                } );

                editor5._instance.conversion.for( 'upcast' ).elementToElement( {
                    view: 'svg',
                    model: ( viewElement, modelWriter ) => {
                        return modelWriter.createElement( 'svg', viewElement.getAttributes() );
                    }
                } );

                editor5._instance.conversion.for( 'downcast' ).elementToElement( {
                    model: 'svg',
                    view: ( modelElement, viewWriter ) => {
                        return viewWriter.createContainerElement( 'svg', modelElement.getAttributes() );
                    }
                } );
                editor5._instance.model.schema.extend( 'circle', {
                    allowIn: ['$text', 'paragraph', '$block' ,'blockQuote'],
                    isBlock: false
                } );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:docs This issue reports a task related to documentation (e.g. an idea for a guide).
Projects
None yet
Development

No branches or pull requests