I am a beginner working with React.js and Quill.
I am trying to upload a file from my local machine by rewriting existing imageHandler. It does take the file, but do not upload it. The error is following: TypeError: Cannot read property 'quill' of undefined. Here is my code so far:
function imageHandler() {
console.log('Image Handler called');
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async function () {
const file = input.files[0];
console.log('User trying to upload this:', file);
const formData = new FormData()
if (file !== null) {
formData.append('file', file)
}
fetch('https://smartquestionapi.advancity.net/Image', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData
}).then(function (response) {
if (response.ok) {
return response.json()
} else {
return { "error": true }
}
}).then(function (json) {
console.log(file.name);
var cursorPosition = this.quill.getSelection();
var imagePath = "https://smartquestionapi.advancity.net/Images/" + file.name;
this.quill.insertEmbed(cursorPosition.index, 'image', imagePath, Quill.sources.USER);
return json;
}).catch(err => {
console.log("eror: ", err);
})
}.bind(this);
}
The code crushes exactly in then(function (json){ function.
I think is because you are not binding this in this part:
.then(function (json) {
console.log(file.name);
var cursorPosition = this.quill.getSelection();
You can solve it with an arrow function:
.then((json) => {
console.log(file.name);
var cursorPosition = this.quill.getSelection();
Take also a look here, to see the differences between function(){} and (args..) => {}
Related
TDLR: Using s3 presigned post url to upload file to s3. Works fine on the browser but fails on the server.
I have a simple lambda function that generates presigned post url that can be consumed either in the browser or in the server.
During testing I noticed that the upload works fine one the browser but fails if I try to upload a file from a server even tho the code is identical.
The error i get is:
You must provide the Content-Length HTTP header
Detailed error:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>MissingContentLength</Code>
<Message>You must provide the Content-Length HTTP header.</Message>
<RequestId>JP75YMFARK0G3X5Z</RequestId>
<HostId>toHsKmxmVYYAtac94cQoy8wXoregKG3PNBm97c3gQewEmKxLggcumTAP882T/pJNWx/lxRgH98A=</HostId>
</Error>
Request failed with status code 411
I checked online and found many threads about this issue but unfortunately not a single suggestion helped me.
Code I am running in the server
const axios = require('axios');
const { createReadStream, readFileSync } = require('fs');
const FormData = require('form-data');
const getPostPresignedUrl = async () => {
var config = {
method: 'post',
url: LAMBDA_GET_URL,
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
key: 'test-2.jpg',
fileType: 'image/jpeg',
}),
};
const {
data: { data },
} = await axios(config);
return data;
};
const uploadFileToS3 = async (fields, url) => {
const formData = new FormData();
Object.entries(fields).map(([key, value]) => {
formData.append(key, value);
});
const file = createReadStream('./test-1.jpg');
formData.append('file', file);
try {
const { data } = await axios({
url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
});
} catch (error) {
if (error instanceof axios.AxiosError) {
console.log(error.response.data);
}
console.log(error.message);
}
};
const init = async () => {
const { fields, url } = await getPostPresignedUrl();
await uploadFileToS3(fields, url);
};
init();
Code I am running in the browser:
const form = document.getElementById('form');
const input = document.getElementById('file');
const getPostPresignedUrl = async (name) => {
var config = {
method: 'post',
url: LAMBDA_GET_URL,
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
key: name,
fileType: 'image/jpeg',
}),
};
const {
data: { data },
} = await axios(config);
return data;
};
const uploadFileToS3 = async (fields, url, file) => {
const formData = new FormData();
Object.entries(fields).map(([key, value]) => {
formData.append(key, value);
});
formData.append('file', file);
try {
const { data } = await axios({
url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
});
} catch (error) {
if (error instanceof axios.AxiosError) {
console.log(error.response.data);
}
console.log(error.message);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
const file = input.files[0];
const data = await getPostPresignedUrl(file.name);
await uploadFileToS3(data.fields, data.url, file);
};
form.onsubmit = handleSubmit;
I can't understand what the problem is, the essence of this request is to pass some data, call a function and send back the generated Json file, but this does not happen, instead the server does not return anything. What could be the problem? Please help me
Web part
clickOnRow: function(elem, whichScreen){
this.clicks++
if(this.clicks === 1) {
var self = this
this.timer = setTimeout(function() {
console.log("одинарный");
self.clicks = 0
}, this.delay);
} else{
clearTimeout(this.timer);
console.log("двойной");
elem['whichScreen'] = whichScreen;
console.log(this.helper);
// this.nameOfMethod(elem);
this.clicks = 0;
fetch('/currentDir1',{
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(elem)
})
.then(response => response.json())
.then(json => this.helper = json)
.then(json => this.$emit("newvalue", json))
console.log("helper");
console.log(this.helper);
Server part
router.post('/currentDir1',(req, req) =>{
console.log("POST");
let body = "";
let pathToFile = "";
req.on("data", function (data) {
body += data;
});
req.on("end", function(currentData) {
console.log(JSON.parse(body));
currentData = JSON.parse(body);
if(currentData.sizeOrType === "<папка>"){
let dir = currentData.dir + currentData.fileName;
// dir = "C:\\totalcmd";
console.log(dir);
if(currentData.whichScreen){
foo(dir, './data/firstScreen.json');
pathToFile = './data/firstScreen.json';
res.sendFile(path.resolve('./data/firstScreen.json'));
}else{
console.log('aaaa');
Foo(dir, './data/secondScreen.json');
pathToFile = './data/firstScreen.json';
res.sendFile(path.resolve('./data/secondScreen.json'));
}
}
// res.json({ message: 'goodbye'})
res.json(path.resolve(pathToFile));
});
res.sendFile(path.resolve(pathToFile));
})
I got problem how to display image send by API from backend it not display. And when I console.log, I got this error.
This is my code as your reference.
HTML
<img [src]="imageToShow" style="width:100%;margin-left: -14px;">
Component
ngOnInit() {
this.getBanner()
}
getBanner() {
this.bannerId = {
confId: 1,
type: "Banner",
};
this.httpService.getBanner(this.bannerId).subscribe(
(baseImage: any) => {
let objectURL = "data:image/jpeg;base64," + baseImage.image;
this.imageToShow = this.sanitizer.bypassSecurityTrustUrl(objectURL);
},
(error) => {
// this.isImageLoading = false;
console.log(error);
}
);
}
Service
public getBanner(data){
console.log(data)
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
responseType: 'blob',
Authorization: 'Bearer '+this.getToken()
})
};
return this.httpClient.post((this.serverUrl + this.basePath + '/landing/conferenceitem'),data,httpOptions);
}
edit
when I check up Network Response I got this image
Try this
Step #1
Remove Content-Type header and set responseType to blob in httpOptions, but not in the header part like you did. Now, you should get a blob as a response. Before, angular was trying to parse your response as JSON, hence the error
public getBanner(data){
console.log(data)
const httpOptions = {
headers: new HttpHeaders({
Authorization: 'Bearer '+this.getToken()
}),
responseType: 'blob'
};
return this.httpClient.post((this.serverUrl + this.basePath + '/landing/conferenceitem'),data,httpOptions);
}
Step #2 Use baseImage instead of baseImage.image (the response is a blob, it does not have an image property), and then use createObjectURL to get an image url from the blob. Sanitize that URL like your did
this.httpService.getBanner(this.bannerId).subscribe(
(baseImage: Blob) => {
let objectURL = URL.createObjectURL(baseImage);
this.imageToShow = this.sanitizer.bypassSecurityTrustUrl(objectURL);
},
(error) => {
// this.isImageLoading = false;
console.log(error);
}
);
One way to fix this is by Setting the response type to blob
const requestOptions: Object = {
/* other options here */
responseType: 'blob'
}
return this.httpClient.post((this.serverUrl + this.basePath + '/landing/conferenceitem'),data,requestOptions);
and you have to convert your image data to a dataURL:
this.httpService.getBanner(this.bannerId).subscribe(
(baseImage: any) => {
this.imageToShow = baseImage;
},
(error) => {
// this.isImageLoading = false;
console.log(error);
}
);
Change Your getBannerMethod as below :-
getBanner() {
this.bannerId = {
confId: 1,
type: "Banner",
};
this.httpService.getBanner(this.bannerId).subscribe(
(baseImage: any) => {
const reader = new FileReader();
const url = reader.readAsDataURL(baseImage.image);
reader.onloadend = () => this.imageToShow = reader.result;
},
(error) => {
// this.isImageLoading = false;
console.log(error);
}
);
}
Working Stackblitz :- https://stackblitz.com/edit/angular-yvicvq
I have implemented Jodit Editor (react)https://github.com/jodit/jodit-react, Insert Image option, in which can you upload the image, which saves to the default option by the Editor,
I would like to know how to use custom url and insert the image in editor
Jodit default behaviour
config:{
readonly: false,
enableDragAndDropFileToEditor: true,
uploader: { url: "https://xdsoft.net/jodit/connector/index.php?action=fileUpload"}
}
Expected
How to do adding custom url
config:{
readonly: false,
enableDragAndDropFileToEditor: true,
uploader: { url: "www.xyz.com/upload"}
}
In this repository, https://github.com/GilianMoa/jodit-editor-react
I'm uploading images with Cloudinary api.
Hope I can help you with this code.
I create a custom buttom:
uploadImageButton = () => {
Jodit.defaultOptions.controls.uploadImage = {
name: 'Upload image to Cloudinary',
iconURL: "https://www.kindpng.com/picc/m/261-2619141_cage-clipart-victorian-cloud-upload-icon-svg-hd.png",
exec: (async (editor) => {
await this.imageUpload(editor);
})
};
}
Then I create a method to open a dialog to pick the image and send to a service which send a post with the image file formData to cloudinary.
//dialog method
imageUpload = (editor) => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async function () {
const imageFile = input.files[0];
if (!imageFile) {
return;
}
if (!imageFile.name.match(/\.(jpg|jpeg|png)$/)) {
return;
}
const imageInfo = await FileUpload(imageFile);;
this.insertImage(editor, imageInfo.url);
}.bind(this);
}
//this method insert the image inside the editor after the upload is done.
insertImage = (editor, url) => {
const image = editor.selection.j.createInside.element('img');
image.setAttribute('src', url);
editor.selection.insertNode(image);
}
// this method send the image to cloudinary
export const FileUpload = async (file) => {
let result = null;
let formData = new FormData();
formData.append('file', file);
formData.append('upload_preset', `${process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET}`);
await fetch(`https://api.cloudinary.com/v1_1/${process.env.REACT_APP_CLOUDINARY_CLOUD_NAME}/image/upload`, {
method: 'POST',
body: formData
})
.then((response) => response.json())
.then((data) => {
result = data;
})
.catch((error) => {
console.error('Error:', error);
});
return result;
}
I use jodit-react and upload img success ! the code is here hope to help you.
<JoditEditor
ref={this.editor}
value={'this.state.content'}
config={{
language: 'zh_cn',
toolbarButtonSize: 'large',
uploader: {
url: '/manage/upload', //your upload api url
insertImageAsBase64URI: false, not inster base64
imagesExtensions: ['jpg', 'png', 'jpeg', 'gif'],
//headers: {"token":`${db.token}`},
filesVariableName: function (t) {
return 'files[' + t + ']';
}, //"files",
withCredentials: false,
pathVariableName: 'path',
format: 'json',
method: 'POST',
prepareData: function (formdata) {
return formdata;
},
isSuccess: function (e) {
debugger;
return e.success;
},
getMessage: function (e) {
return void 0 !== e.data.messages && Array.isArray(e.data.messages)
? e.data.messages.join('')
: '';
},
process: function (resp: any) { //success callback transfrom data to defaultHandlerSuccess use.it's up to you.
let files = [];
files.unshift(resp.data);
return {
files: resp.data,
error: resp.msg,
msg: resp.msg,
};
},
error: function (this: any, e: Error) {
this.j.e.fire('errorMessage', e.message, 'error', 4000);
},
defaultHandlerSuccess: function (this: Uploader, resp: IUploaderData) { // `this` is the editor.
const j = this;
debugger;
if (resp.files && resp.files.length) {
const tagName = 'img';
resp.files.forEach((filename: string, index: number) => { //edetor insertimg function
const elm = j.createInside.element(tagName);
elm.setAttribute('src', filename);
j.s.insertImage(elm as HTMLImageElement, null, j.o.imageDefaultWidth);
});
}
},
defaultHandlerError: function (this: any, e) {
this.j.e.fire('errorMessage', e.message);
},
contentType: function (e) {
return (
(void 0 === this.jodit.ownerWindow.FormData || 'string' == typeof e) &&
'application/x-www-form-urlencoded; charset=UTF-8'
);
},
},
}}
/>
I have test ok.
Working on a requirement to upload images to AWS instance. UI and service is separated and connects via REST. Service is in nodejs. from UI we are making a ajax call to backend service to upload the images to AWS.
The problem:
When I upload the images via POSTMAN request, I can see that response as uploaded with files properly uploaded in AWS.
Whereas when I upload images via AJAX call, I get no response in browser, and also the images are not uploaded in aws.
Below is the piece of code in ajax:
var formData = new FormData();
formData.append('image', $('#tx_file_programa')[0]);
$.ajax({
method: 'POST',
type: "POST",
url: 'http://10.0.0.95:9999/photo/1',
contentType: false,
processData: false,
async: false,
cache: false,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + access_token );
},
data: formData,
success: function (data) {
console.log('response from server is : ', data);
}
//dataType: 'json'
});
This is the backend service.
server.post('/photo/:count', function (req, res) {
if (req.getContentType() == 'multipart/form-data') {
var form = new formidable.IncomingForm(),
files = [], fields = [];
var result = [];
var noOfFiles = req.params.count;
var count = 0;
console.log('noOfFiles', noOfFiles);
form.on('field', function(field, value) {
fields.push([field, value]);
console.log(fields);
})
form.on('progress', function(bytesReceived, bytesExpected) {
console.log('err');
});
form.on('error', function(err) {
console.log('err',err);
});
form.on('aborted', function() {
console.log('aborted', arguments);
});
new Promise(function(resolve, reject) {
var result = [];
form.onPart = function (part) {
var data = null;
const params = {
Bucket: 'xxxxx',
Key: uuidv4() + part.filename,
ACL: 'public-read'
};
var upload = s3Stream.upload(params);
upload.on('error', function (error) {
console.log('errr', error);
});
upload.on('part', function (details) {
console.log('part', details);
});
upload.on('uploaded', function (details) {
let extension = details.Location.split('.');
if(['JPG', 'PNG'].indexOf(extension[extension.length - 1].toUpperCase()) > -1) {
var ext = extension[extension.length - 1];
count++;
result.push(details.Location);
if(count == noOfFiles) {
resolve(result);
}
}
});
part.pipe(upload);
}
}).then(function(result){
console.log('end', result);
res.writeHead(200, {'content-type': 'text/plain'});
res.end('received files:\n\n ' + util.inspect(result));
})
form.parse(req, function (err, fields, files) {
})
return;
} else {
BadRequestResponse(res, "Invalid request type!");
}
})
#user3336194, Can you check with this, this is working thins
var appIconFormData = null
$(":file").change(function () {
var file = this.files[0], name = file.name, size = file.size, type = file.type;
var imageType = new Array("image/png", "image/jpeg", "image/gif", "image/bmp");
if (jQuery.inArray(type, imageType) == -1) {
return false;
} else {
appIconFormData = new FormData();
appIconFormData.append('appimage', $('input[type=file]')[0].files[0]);
}
});
$.ajax({
url: 'your/api/destination/url',
type: 'POST',
data: appIconFormData,
cache: false,
contentType: false,
processData: false,
success: function (data) {
console.log(data)
},
error: function (e) {
}
});
I think the way you are sending formdata is not correct.
Try these 2 ways:
You can give your whole form to FormData() for processing
var form = $('form')[0]; // You need to use standard javascript object here
var formData = new FormData(form);
or specify exact data for FormData()
var formData = new FormData();
// Attach file
formData.append('image', $('input[type=file]')[0].files[0]);