Can you tell me why this code is not working?
Note: file is native plugin
var blob = new Blob(["This is my blob content"], { type: "text/plain" });
this.file.writeFile(this.file.dataDirectory, 'myletter.txt', blob, { replace: true })
.then(() => {
//code
})
.catch((err) => {
console.error(err); //it comes to here
});
It gives this exception:
FileError
code : 5
message : "ENCODING_ERR"
__proto__ : Object
I have found the issue here. That was due to this path this.file.dataDirectory.
Solution: Use this instead this.file.externalApplicationStorageDirectory
Related
I am trying to run a WebApp which allows files sharing.
After few google search, I found Web Share API like the standard to do so.
According to the documentation it should works like this using plain JS
This is the code for html page
<p><button>Share MDN!</button></p>
<p class="result"></p>
The code to share all sort "textbased" metadata:
let shareData = {
title: 'MDN',
text: 'Learn web development on MDN!',
url: 'https://developer.mozilla.org',
}
const resultPara = document.querySelector('.result');
if (!navigator.canShare) {
resultPara.textContent = 'navigator.canShare() not supported.';
}
else if (navigator.canShare(shareData)) {
resultPara.textContent = 'navigator.canShare() supported. We can use navigator.share() to send the data.';
} else {
resultPara.textContent = 'Specified data cannot be shared.';
}
The code above works fine, the trouble happens when I try to share files.
According to the documentation it should works like this:
// filesArray is an array of files we want to share (audios, images, videos, pdf)
if (navigator.canShare && navigator.canShare({ files: filesArray })) {
navigator.share({
files: filesArray,
title: 'Pictures',
text: 'Our Pictures.',
})
.then(() => console.log('Share was successful.'))
.catch((error) => console.log('Sharing failed', error));
} else {
console.log(`Your system doesn't support sharing files.`);
}
I started my code from this example and I never success to share a file.
My actual code using React and Typescript looks like this:
//some react code here
const shareNow = async () => {
let imageResponse = await window.fetch('https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png', {mode: "no-cors"});
let imageBuffer = await imageResponse.arrayBuffer();
let fileArray = [new File([imageBuffer], "File Name", {
type: "image/png",
lastModified: Date.now()
})];
if (navigator.canShare && navigator.canShare({ files: filesArray })) {
navigator.share({
files: filesArray
}).then(() => {
console.log('Thanks for sharing!');
})
.catch(console.error);
}
}
//some react code here too
At this point, my typescript compiler yell at me.
Apparently, the navigator object has no method canShare()
I am new to typescript, but I don't understand how and why the navigator could have less attribute since TypeScript is JavaScript superset.
Anyone has an idea on how to solve that except running normal JS ?
Thank you for your time reading this, and I hope to thank you for your answers.
P.S: I also tried a react-component based solution, but all the component I found in open source which wraps Web Share API does not allow file sharing.
Edit
Hey, #DenverCoder9
There is the same use case but using vanilla JS, could anyone try it and tell me what I am doing wrong please ?
<html>
<head>
<title>Sharing Image</title>
<meta charset="UTF-8" />
</head>
<body>
<div className="App">
<img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"/>
<button id="button">Share</button>
</div>
</body>
<script>
async function shareImage(title, imageUrl) {
const image = await fetch(imageUrl, {mode: "no-cors"});
const blob = await image.blob();
const file = new File([blob], title, { type: 'image/png' });
const filesArray = [file];
const shareData = {
files : filesArray
}
// add it to the shareData
const navigator = window.navigator
const canShare = navigator.canShare && navigator.canShare(shareData) //navigator.canShare()navigator.share //navigator.canShare()
if(canShare){
navigator.share(shareData)
.then(() => console.log('Successful share'))
.catch((error) => console.log('Error sharing', error));
}
else {
console.log("cannot share this file in this context")
}
}
document.getElementById('button').onclick = function() {
shareImage("Title", "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png")
};
</script>
</html>
I am running this on safari for mac
This is more of a TypeScript issue than a coding issue. Support for the Web Share API (Level 2) was added in this PR, so you can either update to a version of TypeScript that includes this, or alternatively teach your current TypeScript version the relevant types as follows:
type ShareData = {
title? : string;
text? : string;
url? : string;
files?: ReadonlyArray<File>;
};
interface Navigator
{
share? : (data? : ShareData) => Promise<void>;
canShare?: (data?: ShareData) => boolean;
}
I can't seem to figure out what the problem is. I'm trying to use EvaporateJS to upload files to S3, I'm also using React. Here is what my code looks like:
Blockquote
useEffect(() => {
Evaporate.create({
aws_key: AWS_ACCESS_KEY,
bucket: S3_BUCKET,
awsRegion: 'us-west-1', // s3 region
signerUrl: '/api/videos/signv4_auth',
awsSignatureVersion: '4',
computeContentMd5: true,
cloudfront: true,
cryptoMd5Method: (data) => {
return AWS.util.crypto.md5(data, 'base64');
},
cryptoHexEncodedHash256: (data) => {
return AWS.util.crypto.sha256(data, 'hex');
}
}).then(evaporate => {
console.log(evaporate);
// evaporate.add(); // showing as not a function
});
}, []);
But I get an error message: evaporate.add is not a function. When I inspect the evaporate variable that's being passed with then, it doesn't contain the add function, nor some of the other functions mentioned in documentation. Not sure why it's not working, any help would be highly appreciated.
Console output of evaporate
Error Message
i've been struggling with this behaviour of Cypress that i do not understand and i need help.
When i set route and wait for the request i can see that the response body is in BLOB, when in chrome devtools response body arrives as JSON, so is in application. I have Content-type set to application/vnd.api+json. Cypress version 3.7.0. I also disabled Fetch because Cypress have problems with that Cypress documentation #wait
cy.server();
cy.route('POST', '**/services').as('postService');
cy.get('[data-cy=AddServices_submit]').click();
cy.wait('#postService').then((xhr) => {
//xhr.response.body is BLOB
//xhr.responseBody is BLOB
})
Found similar question: Stackoverflow Similar question but this is not helpful for me.
Did any one had similar problems with response arriving as BLOB?
Any help would be great, if you need more information feel free to ask. Thanks
EDIT
I have a workaround to this problem if anyone needed one. But the problem Still occurs
cy.wait('#postService').then(async (xhr) => {
const response = await new Response(xhr.responseBody).text();
const jsonResponse = JSON.parse(response);
// jsonResponse is real json
});
I got the same problem and it was solved by adding cypress fetch polyfill as here
If the link won't be available, I copy the content here:
In directory cypress/support/ in file hooks.js add this code:
// Cypress does not support listening to the fetch method
// Therefore, as a workaround we polyfill `fetch` with traditional XHR which
// are supported. See: https://github.com/cypress-io/cypress/issues/687
enableFetchWorkaround();
// private helpers
function enableFetchWorkaround() {
let polyfill;
before(() => {
console.info('Load fetch XHR polyfill')
cy.readFile('./cypress/support/polyfills/unfetch.umd.js').then((content) => {
polyfill = content
})
});
Cypress.on('window:before:load', (win) => {
delete win.fetch;
// since the application code does not ship with a polyfill
// load a polyfilled "fetch" from the test
win.eval(polyfill);
win.fetch = win.unfetch;
})
}
In directory cypress/support/ in file index.js import hooks.js
import './hooks'
In directory cypress/support/ add directory polyfills and add there file unfetch.umd.js with this code:
// cypress/support/polyfills/unfetch.umd.js
// Version: 4.1.0
// from: https://unpkg.com/unfetch/dist/unfetch.umd.js
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):e.unfetch=n()}(this,function(){return function(e,n){return n=n||{},new Promise(function(t,o){var r=new XMLHttpRequest,s=[],u=[],i={},f=function(){return{ok:2==(r.status/100|0),statusText:r.statusText,status:r.status,url:r.responseURL,text:function(){return Promise.resolve(r.responseText)},json:function(){return Promise.resolve(JSON.parse(r.responseText))},blob:function(){return Promise.resolve(new Blob([r.response]))},clone:f,headers:{keys:function(){return s},entries:function(){return u},get:function(e){return i[e.toLowerCase()]},has:function(e){return e.toLowerCase()in i}}}};for(var a in r.open(n.method||"get",e,!0),r.onload=function(){r.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,function(e,n,t){s.push(n=n.toLowerCase()),u.push([n,t]),i[n]=i[n]?i[n]+","+t:t}),t(f())},r.onerror=o,r.withCredentials="include"==n.credentials,n.headers)r.setRequestHeader(a,n.headers[a]);r.send(n.body||null)})}});
So, it worked for me
Same problem here...
I manage to get the data as JSON when I use cy.request() but I can't when I use an alias with cy.wait()
Could you try this as a workaround ?
const setBodyAsJson = async (xhr) => ({ ...xhr, body: JSON.parse(String.fromCharCode.apply(null, new Uint8Array(await xhr.response.body.arrayBuffer()))) })
cy.server();
cy.route('POST', '**/services').as('postService');
cy.get('[data-cy=AddServices_submit]').click();
cy.wait('#postService').then(setBodyAsJson).then((res) => {
// res should contain body as JSON
})
This does not explain why but in case your response.body is a Blob but responseBody is null, you can use this to read it:
cy.wait('#postService', TIMEOUT)
.its('response.body')
.then(body => {
return new Promise(done => {
const reader = new FileReader();
reader.onload = function() {
done(JSON.parse(this.result));
};
reader.readAsText(body);
});
})
.then(object => {
expect(typeof object).to.equal('object')
});
I am using Angular2. I am getting PDF response as BLOB from backend API. The PDF is showing fine in iframe but it is showing title as 'anonymous'. Can someone please guide?
html code:
<iframe id="showPDFIframe" allowtransparency="false" title="TestPDF" width="100%" height="800" [attr.src]="dataLocalUrl" type="application/pdf"></iframe>
pdf.component.ts
pdfDownload: any;
protected dataLocalUrl: SafeResourceUrl;
ngOnInit() {
this.requestOptions = this.createRequestOptions();
this.requestOptions.responseType = ResponseContentType.Blob;
this._pdfModelService.showPDF(this.requestOptions)
.subscribe( (res) => {
this.pdfDownload = res;
this.dataLocalUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(res));
}, err => {
console.log(err);
})
}
pdfModelService.ts
showPDF(options?: RequestOptions): any {
return this._http.get(this.endpoints.showPDF.uri, options)
.map( (res) => {
return new Blob([res], { type: 'application/pdf' })
});
}
See below image 'Anonymous' is showing
Note: backend API gives the bytes which we cast in BLOB.
have you tried providing title in the options:
showPDF(options?: RequestOptions): any {
return this._http.get(this.endpoints.showPDF.uri, options)
.map( (res) => {
return new Blob([res], { type: 'application/pdf', title: 'testpdf' })
});
}
Although I am not certain why the specified title field "TestPDF" in the code is not appearing on the page, the "(anonymous)" value that is displaying could simply be pulling the meta data from the PDF file itself. A possible solution would be to check the title field in the PDF document properties to set the title there. In Adobe Acrobat, from the file menu select Properties > Description to check/update the title field.
Reference article from W3.org: https://www.w3.org/TR/WCAG20-TECHS/PDF18.html
I just want my app download a file from the server by using react-native-fetch-blob. The problem is, where do the file stored? I just console.log the callback from react-native-fetch-blob and got this object
React-native-fetch-blob object callback
this is my code
alert("downloading");
RNFetchBlob
.config({
useDownloadManager : true,
fileCache : true
})
.fetch('GET', 'http://fontawesome.io/assets/font-awesome-4.7.0.zip', {})
.then((res) => {
console.log(res);
alert("Download");
alert('The file saved to ', res.path());
})
Any solution?
To download a file directly with rn-fetch-blob, you need to set fileCache as true.
btw, react-native-fetch-blob is not maintained anymore, use rn-fetch-blob instead
document of download file directly
RNFetchBlob
.config({
// add this option that makes response data to be stored as a file,
// this is much more performant.
fileCache : true,
})
.fetch('GET', 'http://www.example.com/file/example.zip', {
//some headers ..
})
.then((res) => {
// the temp file path
console.log('The file saved to ', res.path())
})
function downloadFile(url,fileName) {
const { config, fs } = RNFetchBlob;
const downloads = fs.dirs.DownloadDir;
return config({
// add this option that makes response data to be stored as a file,
// this is much more performant.
fileCache : true,
addAndroidDownloads : {
useDownloadManager : true,
notification : false,
path: downloads + '/' + fileName + '.pdf',
}
})
.fetch('GET', url);
}
use this answer it will work for sure
I am using it and it works perfectly.
You just need to get the path like this.
var filePath = res.path();
this is where your file is stored.