Opening a PDF from $http.post crash when using _blank - javascript

I'm making a post to a WS and receive a PDF, I transform it into a blob, create a URL and open it.
If i'm opening the pdf in '_self', it works! I see the pdf.
I can also create a link with a download element and it works too!
But if i'm opening the pdf in '_blank', a new tab is created and instantly close.
Here is my code:
getDoc(id) {
const url = 'url';
this.$http.post(
url,
{
data: {
id,
},
},
{
responseType: 'arraybuffer',
}).then((response) => {
const blob = new Blob([response.data], { type: 'application/pdf;' });
const urlPdf = this.$window.URL.createObjectURL(blob);
const win = this.$window.open(urlPdf, '_blank');
win.focus();
});
}
Do I have to add something to allow it to open in a new tab/window?
Why does it works for _self but not _blank?
Thank you!

I had adblock enabled and this was the problem, once disabled the pdf is now working with _blank!
Thanks Alon Eitan for your comment!

Related

Angular/Javascript - Download file link is not working on mobile devices

I have a href link to download a template from my application. It is working fine in Chrome and IE but however it is not working in mobile devices( Android as well as iPhone)
I have this function which gets called by clicking on the link..
fileUrl: any;
getFileTemplate(): any {
this.productService.getFile().subscribe((response) => {
const fileContent = response;
// An application or a document that must be opened in an application
const blob = new Blob([fileContent], { type: 'application/octet-stream' });
if (window.navigator.msSaveBlob) {
// to download in IE
window.navigator.msSaveBlob(blob, 'abcd.csv');
} else {
this.fileUrl= this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(blob));
const a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = 'abcd.csv';
a.click();
}
});
}
And in HTML file
`<a href="javascript:void(null)"
(click)="getFileTemplate();"
id="link-inline-excel"
class="u-text--document u-text--document-link"
download="abcd.csv"><span>Title my file (7MB)</span></a>`
This is not working in mobile devices.
Am i missing something here?
You are more or less on the right track. The minimum modification I can offer to get your code to work is adding one more line to getFileTemplate:
getFileTemplate(): any {
this.productService.getFile().subscribe((response) => {
const fileContent = response;
// An application or a document that must be opened in an application
const blob = new Blob([fileContent], { type: 'application/octet-stream' });
if (window.navigator.msSaveBlob) {
// to download in IE
window.navigator.msSaveBlob(blob, 'abcd.csv');
} else {
this.fileUrl= this.sanitizer.bypassSecurityTrustResourceUrl(window.URL.createObjectURL(blob));
const a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = 'abcd.csv';
document.body.appendChild(a); //<-- Need to add the link to the DOM
a.click();
}
});
}
Of course, while this works, it's not a very clean solution. For one, the user will be able to see the newly appended link. For another, the Angular documentation suggests avoiding direct DOM manipulations, using Renderer2 instead.
Here's a StackBlitz example with both of these things in mind.
The example creates a separate Downloader component, that acts like a basic anchor element, but encapsulating the logic to trigger a download. You can then use this component wherever you want to trigger a file download.
The gist of the answer is this snippet:
...
constructor(
private element: ElementRef,
private renderer: Renderer2
) {}
...
download(data: Blob, filename: string) {
if(!data) {
return;
}
//Create the anchor element
const link: any = this.renderer.createElement('a');
//Create the URL
const url: any = URL.createObjectURL(data);
//Set the attributes for the anchor
this.renderer.setProperty(link, 'href', url);
this.renderer.setProperty(link, 'download', filename);
//Ensure that the anchor will be hidden, both visibly and from screen readers
this.renderer.setStyle(link, 'display', 'none');
//Add the anchor element to the DOM
this.renderer.appendChild(this.element.nativeElement, link);
//Trigger click on the anchor element to trigger the download
link.click();
//Cleanup by removing the element and revoking the URL.
this.renderer.removeChild(this.element.nativeElement, link);
URL.revokeObjectURL(url);
//Note: This is just a basic example, which does do DOM manipulation
//on every download. You could, instead, append the element in OnInit,
//adjusting its attributes when a download is triggered, and then
//remove the element in OnDestroy.
}

Cypress: Stub open window

in my app there is an recommendations list, which on click opens a new window with a dynamic address:
$window.open(_shopURL, '_blank');
Now I'm trying to stub the windows.open event as shown in https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/stubbing-spying__window/cypress/integration/window-stubbing.spec.js
Cypress.on('window:before:load', (win) => {
win.open = cy.stub().as('windowOpen')
})
describe('Shop integration', () => {
beforeEach(function () {
cy.visitHome(countryCode, resellerId)
})
it('can stub the window open event', function () {
cy.get(`.recommendations-list .recommendations-cover:nth-of-type(1)`)
.click()
cy.get('#windowOpen').should('be.calledWith', 'page1.html')
})
But it's always opening the new tab and the logs are wrong:
Cypress: stub open window
Does anybody has an idea why it's not working?
Cheers!
Code below will help you to stub window.open and further assert it that function has been triggered:
it('opens the about page', () => {
cy.visit('/')
cy.window().then(win => {
cy.stub(win, 'open').as('Open')
})
cy.get('.your-selector').click()
cy.get('#Open').should('have.been.calledOnceWithExactly', yourUrl)
})
You also can stub window.open in cy.on hook as you did, what helps you to yield new window object each time after page reload. However, if you want to actually open the new Url in existing tab instead of new one you can use this code below by passing "_self" param to overwrite old "_blank":
cy.window().then(win => {
cy.stub(win, 'open').callsFake((url) => {
return win.open.wrappedMethod.call(win, url, '_self');
}).as('Open');
});
callsFake function dynamically withdraws url which has been placed into original window.open(url, "_blank"), or you can manually change url inside .call(win, url, '_self'); with static one, so regardless on which link or button you clicked, which triggers window.open, they all will open the same url.
I'm using page-objects for every page I want to test. So in my parent page-object which gets inherited by every other PO I do the following when opening a url:
public navigateTo(url: string, defaultTimeout: number = 5000) {
return cy.visit(url, {
onBeforeLoad: (win: any) => {
cy.stub(win, 'open');
},
timeout: defaultTimeOut
});
}
This prevents window to open a new page.
You also can use this easy way:
const newUrl = 'your url';
cy.window().then((win) => {
cy.stub(win, 'open').callsFake(url => {
newUrl = url
}).as('windowOpen')
})
cy.get('your path').click()
cy.get('#windowOpen').should('be.called')
cy.visit(newUrl)

Opening PDF from angular blob in Internet explorer browser

I have the following server side code in web api
tempResponse = Request.CreateResponse(HttpStatusCode.OK);
tempResponse.Content = new StreamContent(stream);
tempResponse.Content.Headers.Add(#"Content-type", "application/pdf");
tempResponse.Content.Headers.ContentType = new
System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
tempResponse.Content.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("inline");
I am using angular JS and following is the code in my javascript file.
$http.post(apiURL + "/DownloadPdf", data, { responseType: 'arraybuffer'}, config)
.then(function (result) {
var file = new Blob([result.data], { type: 'application/pdf' })
var fileName = "CommissionStatement.pdf"
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.location.href = 'Assets/Document CheckList.pdf'
window.navigator.msSaveOrOpenBlob(file, fileName)
} else {
var objectUrl = URL.createObjectURL(file)
window.open(window.location.href = 'Assets/Document CheckList.pdf', '_blank')
window.open(objectUrl, '_blank')
$window.location.href =
window.location.protocol + "//" +
window.location.host + "?BrokerId=" +
AgentInfo.Data.BrokerId +
"&OfficeCode=" +
AgentInfo.Data.OfficeCode;
}
});
console.log($scope.Result)
},
function (error) {
$scope.Error = error.data
})
This blob opens fine in Google Chrome and FireFox. But IE will prompt for open or save. But I would like it to open in the browser. I would appreciate any input in making it open without prompting. Thanks
How about just excluding the if/else statement and just open the ObjectURL in IE as well? Otherwise pdf.js is a alternative if you want to render it in a browser using canvas
Another problem I see with your code is that you are trying to open up a new window with window.open() the problem is that they can become very easy blocked unless it happens within 1 sec after a user interaction event like onclick for example. A xhr.onload is not an user interaction event
So if you are experience some issue like that try doing something like
// Untested, just to give a ruffly idea
btn.onclick = () => {
var win = window.open('', '_blank')
win.document.body.innerHTML = 'loading...'
$http.post(...).then(res => {
var url = URL.createObjectURL(blob)
// redirect
win.location.href = url
})
}
Another thing. Why are you using responseType = arrayBuffer? you could set it to a blob directly...?

pass input file to background script

I want to pass the input file from content page to extension background script, and then load it with FileReader() in the extension background script.
So in the web page I have a <input type="file"> and from onchange event I pass the file from content script to background page like this:
var myfile = document.getElementById('fileid').files[0];
chrome.runtime.sendMessage({myevent: "start", inputfile: myfile}, function(response) {});
in the background script I have this:
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
if(message.myevent==="start")
{
var reader = new FileReader();
reader.onload = function(e) {
// file is loaded
}
reader.readAsArrayBuffer(message.inputfile);
}
});
but FileReader not load it, I'm not sure if this is correct way , but all i need is to pass the input file element to background script and load it with FileReader to send it with HTTP POST from background script. Please tell me what is wrong or how to do it correctly. It will help a lot if I see a sample code, because I'm new to chrome extension development, and not so experienced.
All messages send through the Chrome extension messaging API MUST be JSON-serializable.
If you want to get the contents of a file at the background page, you'd better create a (temporary) URL for the File object, pass this URL to the background page and use XMLHttpRequest to grab its contents:
// Create URL
var url = URL.createObjectURL(myfile);
// Pass URL to background page (ommited for brevity) and load it..
var x = new XMLHttpRequest();
x.onload = function() {
var result = x.response;
// TODO: Use [object ArrayBuffer]
};
x.open('GET', url); // <-- blob:-url created in content script
x.responseType = 'arraybuffer';
x.send();
Though why do you want to send the file to the background page? Content scripts can also send cross-origin requests.
This works for chrome. You could find the whole production code here.
https://github.com/Leslie-Wong-H/BoostPic/tree/7513b3b8d67fc6f57718dc8b9ff1d5646ad03c75/BoostPic_Chrome/js
main.js:
// Crossbrowser support for URL
const URLObj = window.URL || webkitURL;
// Creates a DOMString containing a URL representing the object given in the parameter
// namely the original Blob
const blobUrl = URLObj.createObjectURL(imageBlob);
console.log(blobUrl);
chrome.runtime.sendMessage(blobUrl, (res) => {
imgUrl = res;
console.log(imgUrl);
clearInterval(refreshIntervalId);
// To prevent that it happens to halt at " Image uploading ..."
setTimeout(() => {
var imgUrlText = document.querySelector(imgUrlTextBoxId);
imgUrlText.value = imgUrl;
}, 1000);
// double check to clear interval to prevent infinite error loop of LoadingStateOne
// Hope it works.
setTimeout(() => {
clearInterval(refreshIntervalId);
}, 500);
console.log("Stop uploading state message");
background.js:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.startsWith("blob")) {
console.log("RECEIVED");
getBase64Url(request).then((res) => {
console.log("Arrived here");
// Acquired from https://stackoverflow.com/questions/18650168/convert-blob-to-base64/18650249#
const reader = new FileReader();
reader.readAsDataURL(res);
reader.onloadend = function () {
const base64data = reader.result;
console.log(base64data);

How to download a pdf file using ExtJS 4.2.1?

I am developing a personal web site and i have a pdf in my resources.
I need a button with the handler to save pdf file in browser.
My application only have client side.
How i can download pdf file in browser with Extjs ?
The following code used to download the pdf using extjs. Add the following code should be invoked for button action. This downloads the file directly insteadof opening in new tab.
Make sure that server side has
Server side
In the server side once you generate the report, you should set the following headers
header.set("application/pdf");
header.set("Content-disposition: inline; filename=Test.pdf");
Client Side
1. Add the button in the view
{
xtype: 'button',
text: 'Print PDF',
cls: 'printPdfBtn',
listeners: {
click: 'printReport'
//click: 'openReport'
}
}
2. Add the listener method in controller.
Option:1 Use hidden iframe to download the pdf file.
use an iframe like this:
/**
* prints the file
*/
printReport: function () {
var url = 'downloadURL';
Ext.Ajax.request({
url: url,
method: 'GET',
autoAbort: false,
success: function(result) {
if(result.status == 204) {
Ext.Msg.alert('Empty Report', 'There is no data');
} else if(result.status == 200) {
Ext.DomHelper.append(Ext.getBody(), {
tag: 'iframe',
frameBorder: 0,
width: 0,
height: 0,
css: 'display:none;visibility:hidden;height:0px;',
src: url
});
}
},
failure: function() {
// failure action
}
});
}
Copied the answer from extjs forum
The following code used to download the file using extjs. Add the following code to method and invoke this for button action. PDF will be opened in new tab.
option:2 Open pdf in tab.
If you want to open the file in new tab
/**
* open file in tab
*/
openReport: function () {
var url = 'downloadURL';
Ext.Ajax.request({
url: url,
method: 'GET',
autoAbort: false,
success: function(result) {
if(result.status == 204) {
Ext.Msg.alert('Empty Report', 'There is no data');
} else if(result.status == 200) {
var win = window.open('', '_blank');
win.location = url;
win.focus();
}
},
failure: function() {
// failure action
}
});
}
I think just this:
window.open("your_pdf_url.pdf", "_blank")
Hope this helps. Cheers
This is not specific to Ext JS. Just open a new window with the path to the PDF file.

Categories