I want to upload a file using the extjs6 modern toolkit. Therefor I display a MessageBox with a file chooser. How can I retrieve the selected file into a javascript object after clicking the OK button to upload it (via HTTP POST e.g.)?
this.createUploadMsgBox("File Upload", function (clickedButton) {
if (clickedButton == 'ok') {
console.log("file: " + file);
}
createUploadMsgBox: function (title, callback) {
Ext.Msg.show({
title: title,
width: 300,
buttons: Ext.MessageBox.OKCANCEL,
fn: callback,
items: [
{
xtype: 'filefield',
label: "File:",
name: 'file'
}
]
});
}
You can rum my example here:
https://fiddle.sencha.com/#view/editor&fiddle/1kro
You have two posible solutions.
One is to use a form, and send the file via form.submit() (use form.isValid() before the submit). You can retrieve the file in the server with a MultipartFile.
The other way is to use JS File API. In you createUploadMsgBox function:
this.createUploadMsgBox("File Upload", function (clickedButton) {
if (clickedButton == 'ok') {
//console.log("file: " + file);
var filefield = Ext.ComponentQuery.query('filefield')[0];
var file = filefield.el.down('input[type=file]').dom.files[0];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
console.log(e.target.result);
};
})(file);
reader.readAsBinaryString(file);
}
});
In the file object you have the basic info of the file, and then you will see in the console the content of the file.
Hope this helps!
Related
I've created a button for downloading and saving a file returned from an api endpoint.
In common browser, after clicking the button, a save file dialog appears with title Save As and Save as type displayed by file's extension. But in electron, the title seems to be a file url (in my case it shows blob://https:... cause mine is created with URL.createObjectURl).
So is that any options I need to set to a tag to make the dialog title is Save As and correct the save type of file (without using native dialog of electron)?
...
<a hidden href='/' ref={downloadRef}>download</a>
<button onClick={handleSaveFile}>download</button>
...
const handleSaveFiles = (file: Blob, fileName: string): void => {
const fileDownloadUrl = window.URL.createObjectURL(file);
if (downloadRef.current) {
downloadRef.current.href = fileDownloadUrl;
downloadRef.current.download = fileName;
downloadRef.current.click();
}
};
Actually, the dialog opened when clicking that button already is electron's dialog, then I could edit the title and filters by will-download event.
...
this.browserWindow = new BrowserWindow(option);
...
this.browserWindow.webContents.session.on('will-download', (event, item) => {
let filters = [];
switch (item.getMimeType()) {
case 'text/csv':
filters = [{ name: 'Microsoft Excel Comma Separated Values File', extensions: ['csv'] }];
break;
case 'application/octet-stream':
filters = [{ name: 'Zip archive', extensions: ['zip'] }];
break;
default:
break;
}
item.setSaveDialogOptions({
title: 'Save As',
filters: [...filters, { name: 'All Files', extensions: ['*'] }],
});
});
Refer to https://www.electronjs.org/docs/latest/api/download-item#downloaditemsetsavedialogoptionsoptions
I have a project where it uses Filepond to upload files and I need it to load file from server.
I already follow the docs but It doesn't work. The Filepond gives error Error during load 400 and it even doesn't send the request to load the file from server
This is my javascript
let pond = FilePond.create(value, {
files: [
{
// the server file reference
source: 'e958818e-92de-4953-960a-d8157467b766',
// set type to local to indicate an already uploaded file
options: {
type: 'local'
}
}
]
});
FilePond.setOptions({
labelFileProcessingError: (error) => {
return error.body;
},
server: {
headers: {
'#tokenSet.HeaderName' : '#tokenSet.RequestToken'
},
url: window.location.origin,
process: (fieldName, file, metadata, load, error, progress, abort) => {
// We ignore the metadata property and only send the file
fieldName = "File";
const formData = new FormData();
formData.append(fieldName, file, file.name);
const request = new XMLHttpRequest();
request.open('POST', '/UploadFileTemp/Process');
request.setRequestHeader('#tokenSet.HeaderName', '#tokenSet.RequestToken');
request.upload.onprogress = (e) => {
progress(e.lengthComputable, e.loaded, e.total);
};
request.onload = function () {
if (request.status >= 200 && request.status < 300) {
load(request.responseText);
}
else {
let errorMessageFromServer = request.responseText;
error('oh no');
}
};
request.send(formData);
},
revert: "/UploadFileTemp/revert/",
load: "/UploadFileTemp/load"
}
})
This is my controller
public async Task<IActionResult> Load(string p_fileId)
{
//Code to get the files
//Return the file
Response.Headers.Add("Content-Disposition", cd.ToString());
Response.Headers.Add("X-Content-Type-Options", "nosniff");
return PhysicalFile(filePath, "text/plain");
}
NB
I already test my controller via postman and it works. I also check the content-disposition header
I'd advise to first set all the options and then set the files property.
You're setting the files, and then you're telling FilePond where to find them, it's probably already trying to load them but doesn't have an endpoint (yet).
Restructuring the code to look like this should do the trick.
let pond = FilePond.create(value, {
server: {
headers: {
'#tokenSet.HeaderName': '#tokenSet.RequestToken',
},
url: window.location.origin,
process: (fieldName, file, metadata, load, error, progress, abort) => {
// your processing method
},
revert: '/UploadFileTemp/revert',
load: '/UploadFileTemp/load',
},
files: [
{
// the server file reference
source: 'e958818e-92de-4953-960a-d8157467b766',
// set type to local to indicate an already uploaded file
options: {
type: 'local',
},
},
],
});
I am trying to create a simple editor for writing a storyline. Right now I could show the html to markup in the editor where bold text are shown in bold and etc. I could also send the data in html form to server but I could not show the image in an editor and also could not upload the image in editor. I have created a codesandbox of it. Here is the link
https://codesandbox.io/s/5w4rp50qkp
The line of code is a bit huge. That is why I am posting the code in codesandbox where you can see the demo either.
Can anyone please help me to make this possible?
I originally posted my answer here
I copied it below for your convenience:
Took a while to figure out how to insert image after checking Draft.js source code.
insertImage = (editorState, base64) => {
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'image',
'IMMUTABLE',
{ src: base64 },
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(
editorState,
{ currentContent: contentStateWithEntity },
);
return AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, ' ');
};
Then you can use
const base64 = 'aValidBase64String';
const newEditorState = this.insertImage(this.state.editorState, base64);
this.setState({ editorState: newEditorState });
For render image, you can use Draft.js image plugin.
Live demo: codesandbox
The demo inserts a Twitter logo image.
If you want to insert a image from local file, you can try to use FileReader API to get that base64.
For how to get base64, it is simple, check
Live demo: jsbin
Now go ahead to put them together, you can upload image from local file!
Set uploadEnable to true
and call uploadCallBack
<Editor ref='textEditor'
editorState={this.state.editorState}
toolbar={{
options: ['image',],
image: {
uploadEnabled: true,
uploadCallback: this.uploadCallback,
previewImage: true,
inputAccept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg',
alt: { present: false, mandatory: false },
defaultSize: {
height: 'auto',
width: 'auto',
},
},
}}
onEditorStateChange={this.onEditorStateChange}
/>
then define your uploadCallback if you want to read file directly from local
uploadCallback = (file) => {
return new Promise(
(resolve, reject) => {
if (file) {
let reader = new FileReader();
reader.onload = (e) => {
resolve({ data: { link: e.target.result } })
};
reader.readAsDataURL(file);
}
}
);
}
Or if you want to use a file server to keep files then you might want to upload image on server and then simply put the link
uploadCallback = (file) => {
return new Promise((resolve, reject) => {
const data = new FormData();
data.append("storyImage", file)
axios.post(Upload file API call, data).then(responseImage => {
resolve({ data: { link: PATH TO IMAGE ON SERVER } });
})
});
}
Ho to everyone. I followed this tutorial to create a modal view with a pdf generated with pdfmake.
http://gonehybrid.com/how-to-create-and-display-a-pdf-file-in-your-ionic-app/
My simply question is how can i save the pdf in my local storage on in cache? I need that to send the pdf by email or open it with openfile2. I'm using Ionic and cordova.
I don't know how you code it, but I know what plugin you should use:
https://github.com/apache/cordova-plugin-file
The git contains a complete documentation of the plugin so everything you could need should be there.
Sample code to write pdf file in device using cordova file and file transfer plugin:
var fileTransfer = new FileTransfer();
if (sessionStorage.platform.toLowerCase() == "android") {
window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, onFileSystemSuccess, onError);
} else {
// for iOS
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, onError);
}
function onError(e) {
navigator.notification.alert("Error : Downloading Failed");
};
function onFileSystemSuccess(fileSystem) {
var entry = "";
if (sessionStorage.platform.toLowerCase() == "android") {
entry = fileSystem;
} else {
entry = fileSystem.root;
}
entry.getDirectory("Cordova", {
create: true,
exclusive: false
}, onGetDirectorySuccess, onGetDirectoryFail);
};
function onGetDirectorySuccess(dir) {
cdr = dir;
dir.getFile(filename, {
create: true,
exclusive: false
}, gotFileEntry, errorHandler);
};
function gotFileEntry(fileEntry) {
// URL in which the pdf is available
var documentUrl = "http://localhost:8080/testapp/test.pdf";
var uri = encodeURI(documentUrl);
fileTransfer.download(uri, cdr.nativeURL + "test.pdf",
function(entry) {
// Logic to open file using file opener plugin
},
function(error) {
navigator.notification.alert(ajaxErrorMsg);
},
false
);
};
i have a grid with an toolbar and on that toolbar an upload option is added, so the upload is alright and it works , but after the file was uploaded to the server the success function does not react.
here my upload code:
upload: function () {
Ext.create('Ext.window.Window', {
title: 'Upload',
width: 300,
layout: 'fit',
draggable: false,
resizable: false,
modal: true,
bodyPadding: 5,
items: [{
xtype: 'form',
bodyPadding: 10,
frame: true,
items: [{
xtype:'filefield',
name:'file',
fieldLabel: 'File',
buttonText: 'Select File',
labelWidth: 30,
anchor: '100%'
}, {
xtype: 'button',
text: 'Upload',
handler: function(){
var form = this.up('form').getForm();
if(form.isValid()){
form.submit({
method: 'POST',
url: 'http://localhost:3000/upload',
success: function (form, action) {
Ext.Msg.alert('Success', 'Your File has been uploaded.');
console.log(action);
},
failure : function (form,action) {
Ext.Msg.alert('Error', 'Failed to upload file.');
}
})
}
}
}]
}],
}).show();
},
});
and the server response :
app.post('/upload', function(req, res) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Content-Type','application/json; charset=UTF8');
var tmp_path = req.files.file.path;
var newPath = __dirname + '/files/' + req.files.file.name;
fs.rename(tmp_path, newPath, function (err){
if (err) throw err;
});
var path = newPath;
var name = req.files.file.name;
connection.query('SELECT name FROM audio WHERE name = ?', [name] , function(err,result) {
if (result[0]) {
console.log('File already exist');
res.status(400).send(JSON.stringify());
} else {
connection.query('INSERT INTO audio (name, path) VALUES (?,?)', [name,path], function (err,result) {
if (err) throw err;
var test = {
success: true
};
res.send({success:true});
console.log('success');
});
}
});
});
i can provide more code if necessary, thanks in advance
The error message is explicit: your response is lost due to cross-domain iframe issue.
See the doc explanation of how file upload form are handled: a hidden iframe is created to receive the response from the server (because, before HTML5 it was not possible to upload a file using XHR). When the iframe is loaded, Ext parses its content to read the response.
But, it is only allowed for a page to manipulate its iframes content if both are on the same domain, including the port number.
Most probably you're accessing your page at http://localhost/, while you're posting your form to http://localhost:3000. So forbidden: error, and no response for you!
This is a Ext js bug identified by Uberdude in the Sencha Forum.
Description of the problem :
When you make an Ext.Ajax.request with a form containing a file input to be uploaded, or manually set the isUpload option to true, rather than doing a proper Ajax request Ext submits the form in the standard HTML way to a dynamically generated hidden . The json response body is then read out of the iframe to create a faked-up Ajax response. A problem arises if the page making the upload Ajax request has changed its document.domain property, e.g. a page at home.example.com includes resources from static.example.com which it wishes to manipulate with javascript without violating the browser's same-origin-policy, so both set their document.domain to "example.com". If home.example.com then makes an upload Ajax request to a url on the home.example.com server, the iframe into which the response is written will have its document.domain as "home.example.com". Thus when the ExtJS code within Ajax.request on the home.example.com page tries to extract the document body from the iframe, it will be blocked by the same-origin-policy and the response passed to the callback functions will incorrectly have empty responseText.
Work Around :
1. Pass the document.domain to the server when making the upload request.
2. In your server response, add the document.domain in your response text/html.
response.setHeader('Content-Type', 'text/html');
response.write('document.domain = "' + params.__domain + '";');
response.write(JSON.stringify({msg: 'Welcome ' + params.name}));
response.end('');
Detail :
Please refer to :
http://www.sencha.com/forum/showthread.php?136092-Response-lost-from-upload-Ajax-request-to-iframe-if-document.domain-changed