Adnan Sheikh
Adnan Sheikh

Reputation: 806

Upload adapter is not defined Issue with Image uploading in ckeditor5-angular

This question may have already answers but none of them is Angular specific. Here are some of them

I am using Angular 5 and following this documentation to implement ckeditor5-angular.

But I am having issue with image uploading, when I try uploading image it says in the browser console.

filerepository-no-upload-adapter: Upload adapter is not defined. Read more: https://docs.ckeditor.com/ckeditor5/latest/framework/guides/support/error-codes.html#error-filerepository-no-upload-adapter

I have tried searching for this issue and was able to find a lot of solutions, but literally I couldn't understand a single of them because they were not Angular specific.

Please help how can I upload image.

Upvotes: 11

Views: 19486

Answers (6)

Timileyin Oluwayomi
Timileyin Oluwayomi

Reputation: 367

Try this out for Angular

You can either choose to use base64 or upload the file to your server and return the file url

///component.ts
 onReady(editor: any): void {
   editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader: any ) => {
      return new ckeditor5UploadAdapter( loader, this.apiService);
   };
 }

Full code to upload to server and get the file url

this option will make your content more clean and prevent storage all content images in your db

//adapterClass.ts
import { ApiService } from "src/app/app-services/api.service";
import { environment } from "src/environment/environment"

export class ckeditor5UploadAdapter {

    constructor(private loader: any, private apiService: ApiService) { }

    public upload() {
        return new Promise((resolve, reject) => {
            this.loader.file.then((file: File) => {
                const reader = new FileReader();
                reader.onload = async (e: any) => {
                    const imageurl = await this.getImageLink(e.target.result);
                    resolve({ default:  environment.appUrl +  '/storage/'  + imageurl });
                };
                reader.readAsDataURL(file);
            });
        })
    }

    getImageLink(base64Img: string) {
        return new Promise((resolve, reject) => {
            this.apiService.post('admin/image/upload', { base64Img })
                .subscribe(response => {
                    if (response.status === "success") {
                        resolve(response.imageLink);
                    } else {
                        resolve("");
                    }
                });
        })
    }

    abort() {
        console.error('aborted');
    }

}

to return base64 image(no need in storing file in server), replace this code

 reader.onload = async (e: any) => {
      const imageurl = await this.getImageLink(e.target.result);
      resolve({ default:  environment.appUrl +  '/storage/'  + imageurl });
 };

with this

reader.onload = async (e: any) => {
     resolve({ default:  e.target.result});
};

Upvotes: 0

DKKs
DKKs

Reputation: 385

Thank you for everyone answer. I create code snippet for anyone who want looking the example. But I used ckeditor inline build. Hope it help.

stackblitz

Upvotes: 3

Kapil Thakkar
Kapil Thakkar

Reputation: 870

In component.html file add following code

<ckeditor [editor]="Editor" (ready)="onReady($event)"></ckeditor>

in component.ts file create function onReady(data)

onReady(eventData) {
    eventData.plugins.get('FileRepository').createUploadAdapter = function (loader) {
      console.log(btoa(loader.file));
      return new UploadAdapter(loader);
    };
  }

Add new class called UploadAdapter and add following code:-

export class UploadAdapter {
  private loader;
  constructor(loader: any) {
    this.loader = loader;
    console.log(this.readThis(loader.file));
  }

  public upload(): Promise<any> {
    //"data:image/png;base64,"+ btoa(binaryString) 
    return this.readThis(this.loader.file);
  }

  readThis(file: File): Promise<any> {
    console.log(file)
    let imagePromise: Promise<any> = new Promise((resolve, reject) => {
      var myReader: FileReader = new FileReader();
      myReader.onloadend = (e) => {
        let image = myReader.result;
        console.log(image);
        return { default: "data:image/png;base64," + image };
        resolve();
      }
      myReader.readAsDataURL(file);
    });
    return imagePromise;
  }

}

here default indicate uploaded image url. I have converted file in base64 but you can call server url and upload your file then return server url with same key.

EnjOy CodInG :)

Upvotes: 13

anysunflower
anysunflower

Reputation: 140

I solved this by implementing my own UploadAdapter
if you use Editor.create(),that would create a new editor element, not associate with the angular component

<ckeditor 
[editor]="Editor" 
[(ngModel)]="content"
(ready)="onReady($event)"
>
</ckeditor>

at component.ts

  onReady($event){
    $event.plugins.get('FileRepository').createUploadAdapter = (loader)=> {
      return new UploadAdapter(loader,'',this.http);
    };
  }

UploadAdapter.ts

import { HttpParams, HttpClient } from "@angular/common/http";

export class UploadAdapter {
    constructor(
      private loader,
      public url:string,
      private http:HttpClient
      ) {
    }
//the uploadFile method use to upload image to your server
  uploadFile(file,url?:string,user?:string){
    let name = '';
    url='your api';
    let formData:FormData = new FormData();
    let headers = new Headers();
    name = file.name;
    formData.append('attachment', file, name);
    const dotIndex = name.lastIndexOf('.');
    const fileName  = dotIndex>0?name.substring(0,dotIndex):name;
    formData.append('name', fileName);
    formData.append('source', user);

    headers.append('Content-Type', 'multipart/form-data');
    headers.append('Accept', 'application/json');
    console.log('formData',formData);
    let params = new HttpParams();
    const options = {
        params: params,
        reportProgress: true,
    };
//http post return an observer
//so I need to convert to Promise
    return this.http.post(url,formData,options);
  }
//implement the upload 
  upload() {
      let upload = new Promise((resolve, reject)=>{
        this.loader['file'].then(
            (data)=>{
                this.uploadFile(data,this.url,'test')
                .subscribe(
                    (result)=>{
//resolve data formate must like this
//if **default** is missing, you will get an error
                        **resolve({ default: result['attachment'] })**
                    },
                    (error)=>{
                        reject(data.msg);
                    }
                );
            }
        );
      });
      return upload;
  }
  abort() {
      console.log("abort")
  }
}

Upvotes: 4

woj1965
woj1965

Reputation: 11

I was trying to use zackhalil's solution. The image was displayed in the editor, but when I get the value to update the database, I just have:

<figure class="image"><img></figure>

To fix this, I changed the following code:

return { default: "data:image/png;base64," + image };
resolve();

to:

resolve({ default: image });

Upvotes: 0

zackhalil
zackhalil

Reputation: 533

I used the below seems to work

class UploadAdapter {
   constructor( loader ) {
      this.loader = loader;
   }

   upload() {
      return this.loader.file
            .then( file => new Promise( ( resolve, reject ) => {
                  var myReader= new FileReader();
                  myReader.onloadend = (e) => {
                     resolve({ default: myReader.result });
                  }

                  myReader.readAsDataURL(file);
            } ) );
   };
}

Upvotes: 7

Related Questions