React pdf onclick download - javascript

I have a problem with react. I have a program that embeds a pdf and a download button. I want to download the pdf upon clicking the button.
Instead, my program redirects me to another page where you download the pdf, meaning it exists in the app but I just want to stay in the same app and download the pdf in my app.
Are there any plugins that I can use to do this?
Please find below my code:
<div>
<object data={this.props.file} type='application/pdf'>
<embed src={this.props.file} type='application/pdf' />
</object>
{
this.props.author ==='bot' ?
<a href={this.props.file} download={this.props.file}>
<input alt='download' type={'image'} src={download} />
</a>
:
''
}
</div>

You can handle this with basic HTML. you do not need any plugins. I prefer using reactstrap instead of bootstrap.
import { Row, Col } from "reactstrap";
<Row>
{/* off set will middle the col */}
<Col md={{ size: 8, offset: 2 }}>
<div >
<a
//this will save the file as "your_cv.pdf"
download="your_cv.pdf"
//put the path of your pdf file
href="/static/resume.pdf"
//reactstrap classes. add green button
className="btn btn-success"
>
Download
</a>
</div>
<iframe
style={{ width: "100%", height: "800px" }}
src="/static/resume.pdf"
>
{" "}
</iframe>
</Col>
</Row>

You can download the pdf file as a blob and temporarily create a link to download that blob as a file. You can do something like:
fetch(this.props.file, {
method: 'GET',
headers: {...headers},
})
.then(res => res.blob())
.then(blob => {
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'YOUR_PDF_NAME.pdf');
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
});
Not sure how your pdf hosting server is configured, you can set the headers of request accordingly.

Try the following method using fetch call and save the file using FileReader object
fetch(this.props.file, {
method: "GET",
headers: {
Accept: "application/pdf",
"Content-Type": "application/pdf",
},
}).then(response => response.blob())
.then(response => {
var blob=response
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var base64data = reader.result;
window.open(base64data);
}
})
.catch(error => {
console.error(error);
});

Related

How to append fetched image URL to img src

I am trying to append the fetched url from a minted NFT jsons metadata to a <img src so that the picture can then be seen inside the dapp. I have fetched the tokenId from the receipt and then used the tokenId with the ipfs link to grab the metadata and then return the image URL which all works fine I have just hidden some code with the personal information.
.then(async(receipt) => {
console.log(receipt);
setMinted(true)
const tokenIds = {ipfslink}.json
const tokenMetadataResponse = await fetch(`/config/json/${tokenIds}.json`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
const tokenMetadata = await tokenMetadataResponse.json();
const image = tokenMetadata.image;
console.log(image)
const nftHolder = document.getElementById("nft_template").content.cloneNode(true)
nftHolder.querySelector("img").src = image.toString();
nftHolder.querySelector("img").alt = tokenMetadata.description
document.getElementById("nfts").append(nftHolder)
When I console.log the link I get the correct Image Url but when I try to append I get this error enter image description here (I can not embed yet my apologies) All help appreciated thank you.
Here is where the img element lies, I have a video that plays upon the receipt of the transaction that indicates a successful mint for the animation that I intend to play with the image.
So when the receipt occurs it turns the minted state to true which you can see in the above code
{minted ? <s.Screen id="nft">
<MintingVideo src="/config/mint.mp4" autoPlay={true} ></MintingVideo>
<template id="nft_template">
<section>
<h1></h1>
<a href="" target="_blank">
<img src={null} alt=""></img>
</a>
</section>
</template>
</s.Screen>
: null}
I have solved this I believe by giving the image a placeholder source that is just a white background.
<s.Screen> //Screen holding all components displayed whether minted is true or not
{minted ? <s.Screen id="nft">
<MintingVideo src="/config/mint.mp4" autoPlay={true} ></MintingVideo>
<NftBox id="nftBox"src="/config/images/plah.png"></NftBox>
</s.Screen>
: null}
And then here is where I target the element and change the source to the one provided
const tokenMetadataResponse = await fetch(`/config/json/${tokenIds}.json`, {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
const tokenMetadata = await tokenMetadataResponse.json();
let image = tokenMetadata.image
if(image.startsWith("ipfs://")) {
image = `https://ipfs.io/ipfs/${tokenMetadata.image.split("ipfs://")[1]} `
};
console.log(image)
const nftHolder = document.getElementById("nft").content
const dNftBox = document.getElementById("nftBox");
dNftBox.src = image;

File preview not available on loading the images from server in file pond

[checkout the code snippet, i have tried
Please checkout the code i tried to fetch the images from the s3 bucket. Fetching is accomplished but unable to preview the fetched image.
<FilePond
style = {{marginTop:'10px'}}
files={files}
allowMultiple={true}
allowReorder={true}
onupdatefiles={setFiles}
imagePreviewHeight = "125px"
server={{
load: (source, load, error, progress, abort, headers) => {
var myRequest = new Request(source);
fetch(myRequest).then(function(response) {
response.blob().then(function(myBlob) {
load(myBlob);
});
});
},
process: null
}}
labelIdle='Drag & Drop your files or <span class="filepond--label-action">Browse</span>'
/>
]1

How to export blob url from js file to vue file in nuxt.js?

I want to import a blob url generated by an external js file in nuxt.js into a vue file.
recorder.js
this.chunks.push(evt.data)
this.chunkType = evt.data.type
if (this.state !== 'inactive') {
return
}
let blob = new Blob(this.chunks, { 'type': this.chunkType })
let blobUrl = URL.createObjectURL(blob)
const recording = {
ts: new Date().getTime(),
blobUrl: blobUrl,
mimeType: blob.type,
size: blob.size,
}
console.log(blobUrl);`
I would like to convert the blob url generated by this code into a blob file in the vue page.
recorder.vue
<h4 class="mt-16 mb-10 ml-6">record file</h4>
<div v-for="(recording, idx) in recordings" :key="recording.ts">
<v-card class="mb-14" max-width="450">
<v-card-title primary-title>
<v-layout justify-center>
<div class="ml-3">
<v-card-title class="mb-3"
>file #{{ idx + 1 }}
</v-card-title>
<audio
id="recordFile"
:src="recording.blobUrl"
controls="true"
/>
script
submitFile(_idx) {
axios
.get(blobUrl, {
responseType: 'blob',
})
.then(({ data }) => {
console.log(data) // → Blob
})
.catch((err) => {
console.error(err)
})
I was able to turn the blob url into a blob file and output it to the console log using the above method inside the external file recorder.js.
However, I don't know how to export this blob url to a vue page.
recorder.js
export default class RecorderService {
constructor (baseUrl) {
this.baseUrl = baseUrl
I would like to output from export default class like this.

Vue + Laravel: How to properly download a PDF file?

THE SITUATION:
Frontend: Vue. Backend: Laravel.
Inside the web app I need to let the user download certain pdf files:
I need Laravel to take the file and return it as a response of an API GET request.
Then inside my Vue web app I need to get the file and download it.
THE CODE:
API:
$file = public_path() . "/path/test.pdf";
$headers = [
'Content-Type' => 'application/pdf',
];
return response()->download($file, 'test.pdf', $headers);
Web app:
downloadFile() {
this.$http.get(this.apiPath + '/download_pdf')
.then(response => {
let blob = new Blob([response.data], { type: 'application/pdf' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'test.pdf'
link.click()
})
}
OUTCOME:
Using this code I do manage to download a pdf file. The problem is that the pdf is blank.
Somehow the data got corrupted (not a problem of this particular pdf file, I have tried with several pdf files - same outcome)
RESPONSE FROM SERVER:
The response itself from the server is fine:
PDF:
The problem may be with the pdf file. It definitely looks corrupted data. This is an excerpt of how it looks like the response.data:
THE QUESTION:
How can I properly download a pdf file using Laravel for the API and Vue for the web app?
Thanks!
SOLUTION:
The code above was correct. What was missing was adding the proper responseType as arraybuffer.
I got scared by those ???? inside the response, and that was misleading me.
Those question marks were just okay since pdf is a binary data and is meant to be read by a proper reader.
THE ARRAYBUFFER:
And arraybuffer is precisely used to keep binary data.
This is the definition from the mozilla website:
The ArrayBuffer object is used to represent a generic, fixed-length
raw binary data buffer. You cannot directly manipulate the contents of
an ArrayBuffer; instead, you create one of the typed array objects or
a DataView object which represents the buffer in a specific format,
and use that to read and write the contents of the buffer.
And the ResponseType string indicates the type of the response. By telling its an arraybuffer, it then treats the data accordingly.
And just by adding the responseType I managed to properly download the pdf file.
THE CODE:
This is corrected Vue code (exactly as before, but with the addition of the responseType):
downloadFile() {
this.$http.get(this.appApiPath + '/testpdf', {responseType: 'arraybuffer'})
.then(response => {
let blob = new Blob([response.data], { type: 'application/pdf' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'test.pdf'
link.click()
})
}
EDIT:
This is a more complete solution that take into account other browsers behavior:
downloadContract(booking) {
this.$http.get(this.appApiPath + '/download_contract/' + booking.id, {responseType: 'arraybuffer'})
.then(response => {
this.downloadFile(response, 'customFilename')
}, response => {
console.warn('error from download_contract')
console.log(response)
// Manage errors
}
})
},
downloadFile(response, filename) {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([response.body], {type: 'application/pdf'})
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob)
return
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob)
var link = document.createElement('a')
link.href = data
link.download = filename + '.pdf'
link.click()
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data)
}, 100)
},
You won't be able to do the download from Laravel to Vue since both are running at different ports I assume.
Even if you try something like this.
public function getDownload()
{
//PDF file is stored under project/public/download/info.pdf
$file= public_path(). "/download/info.pdf";
$headers = [
'Content-Type' => 'application/pdf',
];
return response()->download($file, 'filename.pdf', $headers);
}
It won't help as you are sending headers to the Laravel Port Try using Vue js libraries and try to send that pdf content on the library
Try this
Get help from here
it's works for me.
from laravel backend:
$pdf = PDF::loadView('your_view_name', ['data' => $data]);
return $pdf->output();
from vuejs frontend:
axios({
url: 'http://localhost:8000/api/your-route',
method: 'GET',
responseType: 'blob',
}).then((response) => {
var fileURL = window.URL.createObjectURL(new Blob([response.data]));
var fileLink = document.createElement('a');
fileLink.href = fileURL;
fileLink.setAttribute('download', 'file.pdf');
document.body.appendChild(fileLink);
fileLink.click();
});
downloadFile: function () {
this.$http.post('{{ route('download.download') }}', {
_token: "{{ csrf_token() }}",
inputs: this.inputs
},{responseType: 'arraybuffer'}).then(response => {
var filename = response.headers.get('content-disposition').split('=')[1].replace(/^\"+|\"+$/g, '')
var url = window.URL.createObjectURL(new Blob([response.body],{type:response.headers.get('content-type')}))
var link = document.createElement('a')
link.href = url
link.setAttribute('download', filename)
document.body.appendChild(link)
link.click()
});
},

Axios for Vue not uploading image to server

When I want to upload an image and send the other data using FormData. Axios seems to serialize the image. Therefore, when i upload the image using Axios, the image is inside the body's payload as a string. As a result, I'm unable to use Multer on the server side to retrieve the uploaded image from the request.
This is my Vue code:
export default () {
name: 'app',
data () {
image: ''
},
methods: {
onFileChange (e) {
var files = e.target.files || e.dataTransfer.files
if (!files.length) {
return
}
// console.log(files[0])
// var x = files[0]
return this.createImage(files[0])
// return new Buffer(x)
},
createImage (file) {
// var image = new Image()
var reader = new FileReader()
var vm = this
reader.onload = (e) => {
// vm.image = e.target.result
vm.image = file.toString('base64')
console.log(vm.image)
}
reader.readAsDataURL(file)
},
submitStaff () {
const formData = new FormData()
formData.append('file', this.image)
formData.append('name', this.data.name)
formData.append('username', this.data.username)
formData.append('password', this.data.password)
axios.post('api/myApiUrl', formData)
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})
}
}
<input type="file" #change="onFileChange">
Request Payload (Error with Vue)
Request Payload (Successful with Postman)
How do i fix this? Thank you!
I faced a problem related to it and in my case I was setting Content-Type as a default configuration for all my requests, doing this:
axios.defaults.headers.common['Content-Type'] = 'application/json [or something]';
And, as I remember, part of my solution was to remove this configuration to make the upload works. I just erased that line from my code and all requests worked well. As soon I removed it, I could notice that my headers request changed to this (see attached image and notice the Content-Type entry):
Another thing you should be alert is the field name to your <input type="file" name="file">. I have a java backend expecting a parameter named as "file", so, in my case, my input file HAS to be set as "file" on my HTML and on my server side, like this:
public ResponseEntity<Show> create(
#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) { ... }
Observe the entry #RequestParam("file")...
And in the HTML file:
<form enctype="multipart/form-data" novalidate v-if="isInitial || isSaving">
<div class="well">
<div class="form-group">
<label>* Selecione o arquivo excel. O sistema fará o upload automaticamente!</label>
<div class="dropbox">
<input type="file" single name="file" :disabled="isSaving" #change="filesChange($event.target.name, $event.target.files); fileCount = $event.target.files.length"
accept="application/vnd.ms-excel" class="input-file">
<p v-if="isInitial">
Solte o arquivo excel aqui<br> ou clique para buscar.
</p>
<p v-if="isSaving">
Carregando arquivo...
</p>
</div>
</div>
</div>
</form>
You also can take a look at this tutorial, it my help you: https://scotch.io/tutorials/how-to-handle-file-uploads-in-vue-2
I hope it helps you!

Categories

Resources