How to Send the uploaded file to Apex using lightning:fileUpload - Salesforce lightning - salesforce

After the Alert how do I retrieve the files that were uploaded and send them to the Apex class?
Also on the APEX class what is the input parameter type we use for receiving the file sent?
Component Code
<lightning:fileUpload label="Upload Multiple files"
multiple="false"
accept=".pdf, .png, .jpg"
recordId="{!v.recordId}"
aura:id="multipleUpload"
onuploadfinished="{!c.handleUploadFinished}" />
JScontroller
({
handleUploadFinished: function (component, event, helper) {
// Get the list of uploaded files
var uploadedFiles = event.getParam("files");
alert("Files uploaded length : " + uploadedFiles.length);
}
})

Please review the documentation:
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/aura_compref_lightning_fileUpload.htm
The lightning file upload component, uploads files and attaches it to a record.
You specify the record to attach the files to with the below attribute:
recordId => String => The record Id of the record that the uploaded file is associated to.
If you want to validate the files or have some logic to execute on them, use the below callback function provided:
onuploadfinished => Action => The action triggered when files have finished uploading.
The docs show this example of a callback function:
({
handleUploadFinished: function (cmp, event) {
// Get the list of uploaded files
var uploadedFiles = event.getParam("files");
alert("Files uploaded : " + uploadedFiles.length);
}
})
As you can see the function receives an event called files that can be inspected.

instate of sending docId you can send file in string form using JSON.stringify(uploadedFiles[0])
({
handleUploadFinished: function (component, event, helper) {
var uploadedFiles = event.getParam("files");
var action = cmp.get("c.saveDoc");
action.setParams({
parentId : cmp.get("v.myRecordId"),
contentDocId : uploadedFiles[0].documentId
});
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var toastEvent = $A.get("e.force:showToast");
toastEvent.setParams({
"title": "Success!",
"message": "File "+uploadedFiles[0].name+" Uploaded successfully."
});
toastEvent.fire();
var cmpEvent = cmp.getEvent("cmpEvent");
cmpEvent.fire();
}
else {
console.log("Fail");
}
});
$A.enqueueAction(action);
}
})

Related

Create an Electron/React Local Application which can open a local JSON FIle - Edit it and export it

I'm new in React and trying to create an Application which can open a local JSON File with a list of elements like this in a dialouge:
{
"autor": "Name",
"selftext": "Text",
"title": "Title",
"date": "2019-11-18 18:36:40",
"content": "Content",
"link": "www.web.com",
"origin": "web.com",
"filename": "XY",
"id": 1
},
The imported JSON should be expandable and editable and after that export it with the changes.
Here I need some help with guidance where to start and what I need for that.
To read the file on the frontend, you will need to:
Construct a <form onSubmit={handleSubmit}> with an <input name='json' type='file' required>
Then create a callback, handleSubmit, that extracts and parses the chosen file:
function handleSubmit(e: Event) {
e.preventDefault(); // Prevents the form from refreshing the page
const formData = new FormData(e.target); // parses the data into a map
const file = formdata.get("json");
const filereader = new FileReader();
filereader.readAsText(file);
filereader.onload = () => handleResult(filereader.result);
}
function handleResult(result: string|ArrayBuffer|null) {
if (result) {
// Handle the file as you would like here. You will likely need to
// parse the file here w/ JSON.parse. You could cache it
// or pass it to the React.Context API so that it is available through
// the application.
}
}
To write/export the file on the frontend, you can push the JSON object into a Blob and temporarily construct an <a> element to initiate the download:
function save() {
const json = // retrieve JSON from wherever you stored it
const file = new Blob([json], {endings: 'native'});
const a = document.createElement('a');
a.download='config.cfg'
a.href = URL.createObjectURL(file);
a.click();
}
Granted because the process might be slightly different because of Electron, but that is how it would work with React in the Browser.

Nextjs Unable to setState after async function call

I have a Nextjs Form with fields like FirstName , Age and place to Upload Image.
After populating the form and uploading the image( saving uploaded File in the state variable using URL.createObjectURL() at this moment, works fine), i want to do the below steps :
First upload the image from state variable to cloudinary server.
After upload is complete, fetch the image url and setForm with rest of the fields.
//helper function to upload images to Cloudinary server
uploadImageToCloudinary(imageFile)
.then((res)=>{
setForm({
...form,
"picUploaded" : "true", //hard coded value for testing
"profilePic" : res.url //url is retrieved here successfully
});
//run validationafter upload to make sure required fields are there
let errs = validate();
setError(errs);
})
Validation Code
const validate= () => {
console.log(form.picUploaded);// Output : true
let err = {};
if(!form.firstName){
err.firstName= 'First Name is required.';
}
if(!form.lastName){
err.lastName= 'Last Name is required.';
}
if(!form.profilePic){ //Issue : Profile pic is not set here
err.profilePic= 'Profile Pic is required.';
}
return err;
}
Issue : The uploaded image url is not set in the form(field profilePic), but a hardcoded value picUploaded is set.
Can someone please guide me on what am i missing here.
The problem is you run the validation right after the setForm call, it's async so your validation will hit previous form values, not the new ones.
To avoid this you would need to run validation separately like so.
useEffect(() => {
setError(validate())
}, [form])
that will run validation on every form update, which is something you may or may not want, depending on the use case.
uploadImageToCloudinary(imageFile)
.then((res)=>{
setForm({
...form,
"picUploaded" : "true", //hard coded value for testing
"profilePic" : res.url //url is retrieved here successfully
});
})

react.js file not uploading spring server

In my project, I have Spring Boot in the back-end and React.js in the front.
My back-end is working fine, I know, because I have tested it with Postman.
In the front-end to upload file, I have a named SubmitAssignment, which looks like this:
state={file:''};
uploadFile = (e) =>{
e.preventDefault();
var formData = new FormData();
formData.append("file", this.state.file);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8080/uploadFile");
xhr.onload = function() {
console.log(xhr.responseText);
var response = JSON.parse(xhr.responseText);
if(xhr.status === 200) {
console.log("upload successful");
} else {
console.log("upload failed");
}
};
xhr.send(formData);
};
onInputChange = (e) =>{
this.state.file=e.target.value;
console.log(this.state.file);
};
render() {
return (
<div>
<h1>Please select file(s):</h1>
<form>
<input className="input-file" id="my-file" type="file" onChange={this.onInputChange}/>
<button onClick={this.uploadFile}>Upload</button>
</form>
</div>
);
}
But the problem is upload is failing every time. Maybe the reason is the path, not sure. I tried to console.log the path. And what I got is C:\fakepath\Screenshot (187).png
Now my question if it is because of path, how can I do it correctly(as far as I know browser doesn't allow it for security concern)?
Otherwise, what is the problem? How to solve it ?
The error in browser console :
POST http://localhost:8080/uploadFile 400
And,
{"timestamp":"2019-09-16T07:20:30.382+0000","status":400,"error":"Bad Request","message":"Required request part 'file' is not present","trace":"org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present\r\n\tat
.......
Here is the full error message.
If the REST is needed, for any reason :
#PostMapping("/uploadFile")
public UploadFileResponse uploadFile(#RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/downloadFile/")
.path(fileName)
.toUriString();
return new UploadFileResponse(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
From what I could see, in onInputChange() you are assigning the target value this.state.file=e.target.value; (This has the file path not the actual file)
Instead change to below, Important !
this.state.file=e.target.files[0];
And some suggestions are, use Fetch Api to send post request rather than using Plain old Javascript
const formData = new FormData();
formData.append("file", this.state.file);
fetch('http://localhost:8080/uploadFile', {
method: 'POST',
body: formData
})
.then(success => console.log(success))
.catch(error => console.log(error));
In your Spring boot controller use #RequestPart("file")
#PostMapping("/uploadFile")
public UploadFileResponse uploadFile(#RequestPart("file") MultipartFile file) {
//Logic
}

how can i add multiple images and preview them using react and express?

im trying to add multiple images using react app and send them to backend code to store them in mongodb
here is the code for the backend :
link
and this is the frontend link
so this code works for just one image
i need to be able to add multiple images
Server
Since you are using multer, change the upload.single() function to upload.array().
For example:
app.post("/addItem",
upload.array('product-image', 4), // 'product-image' is field name and 4 is the max number of files allowed
(req, res) => {
console.log(req.files);
// ... rest of the logic
}
)
Check out docs for upload.array()
Client
Change current <input> to allow multiple files:
<input type="file" name="product-image" onChange={this.fileChangeHandler} multiple>
Now save all the images user picked not only the event.target.files[0]:
fileChangeHandler(event) {
let files = event.target.files
this.setState({ selectedFiles: files })
}
Now add them in FormData and upload as usual:
let formData = new FormData()
formData.append("product-image", this.state.selectedFiles)
That's it! Hope it helps.
PS: I don't think files should be added to state. You can simply add them to a class variable. In this answer I explained why and how to do that.
Update:
You need to loop over the files now. Your /addItem endpoint's code will look something like this:
app.post("/addItem", upload.array('product-image', 4), (req, res) => {
console.log(req.files);
let paths = [];
req.files.forEach(file => {
console.log("new file location", file.path)
let extension = file.originalname.split(".").pop()
fs.rename(file.path, file.path + "." + extension, () => {})
paths.push("/" + file.filename + "." + extension);
});
console.log("body", req.body)
let itemToStore = {
paths: paths, // notice this `paths` now, it was `path`
description: req.body.description
}
console.log("we are adding", itemToStore)
itemData.push(itemToStore)
console.log("updated itemData:", itemData)
res.send(JSON.stringify(itemData))
})
I didn't modify your code, just added a loop. Your 'path' of undefined error should go away.

Angular - update services object during asynchronous function

Folks: Creating an app in angular and node webkit - where users queue up files for downloading, navigate to their dashboard view and this initiates the downloads.
I've created a service which holds an object of the files data:
..
var downloadObj = {};
// fileObj = {'name':'The file name'; 'download_progress' : dlProgress}
showcaseFactory.myDownloads = function(eventId, fileObj) {
if(eventId){
console.log('update the object');
downloadObj['event_'+eventId] = fileObj;
}
console.log(downloadObj);
};
showcaseFactory.getDownloads = function() {
return downloadObj;
};
..
When the dashboard view loads - ng-repeat loops over $scope.downloadFiles which references this object returning the data.
<div ng-repeat="file in downloadFiles">
<div><span>{{file.name}}</span> [{{file.download_progress}}%]</div>
</div>
I've created a custom module which utilises node_modules to perform the download of the files:
nwjsDownloadFactory.commenceDownload = function(event_id, url, dest, cb) {
var http = require('http');
var fs = require('fs');
var statusBar = require('status-bar');
var path = require('path');
// THIS UPDATES THE OBJECT AND DISPLAYS FINE --------- >>
var id = 7;
var testFileObj = {
'name' : 'This is the file name prior to the download...',
'download_progress' : 10
};
ShowCase.myDownloads(id, testFileObj);
// <<< THIS UPDATES THE OBJECT AND DISPLAYS FINE ---------
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
bar = statusBar.create({ total: response.headers['content-length'] })
.on('render', function (stats) {
// var percentage = this.format.percentage(stats.percentage);
// console.log(event_id + '....' + percentage);
var id = 7;
var testFileObj = {
'name' : 'This is the new file name during the download...',
'download_progress' : 35 // this will be replaced with percentage
};
ShowCase.myDownloads(id, testFileObj);
});
response.pipe(bar);
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
}
QUESTION: Prior to the line var request = http.get(url, function(response) the object gets updated, and the changes are reflected in the UI. However, I need to constantly update the object with download complete % so I can create a progress bar.. However, as this asynchronous function executes, the object
appears to be updating - see the attached screen shot - but the UI is not reflecting this.
Can somebody please steer me in the right direction - I need the object to update during the function bar = statusBar.create({ and for the changes to reflect in the UI..
Call $scope.$apply() after making changes to your model to notify Angular that it has to update the UI.
showcaseFactory.myDownloads = function(eventId, fileObj) {
if(eventId){
console.log('update the object');
downloadObj['event_'+eventId] = fileObj;
$scope.$apply();
}
console.log(downloadObj);
};
If you use Angular's $http object, this is handled automatically for you, but if you update your model from other asynchronous callbacks, you have to take care of it yourself.
See this blog post and this documentation page for more in-depth explanations about what's going on.

Resources