Not sure how to add saveAs to angular controller below
var app = angular.module("myNoteApp", [])
.controller("myNoteCtrl", function($scope) {
$scope.message = "";
$scope.clear = function() {$scope.message = "";};
$scope.save = function() {
var blob = new Blob($scope.message, {type: "text/plain;charset=utf-8"});
saveAs(blob, "hello world.txt")};
});
assuming text is in some textarea
Simple solution, based on: Download file from an ASP.NET Web API method using AngularJS
HTML
<a ng-click="downloadFile('fileName.txt', message)" >Download </a>
Controller
$scope.downloadFile = function(filename, data) {
var success = false;
var contentType = 'text/plain;charset=utf-8';
try
{
// Try using msSaveBlob if supported
var blob = new Blob([data], { type: contentType });
if(navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
// Try using other saveBlob implementations, if available
var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
if(saveBlob === undefined) throw "Not supported";
saveBlob(blob, filename);
}
success = true;
} catch(ex)
{
console.log("saveBlob method failed with the following exception:");
console.log(ex);
}
if(!success)
{
// Get the blob url creator
var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
if(urlCreator)
{
// Try to use a download link
var link = document.createElement('a');
if('download' in link)
{
// Try to simulate a click
try
{
// Prepare a blob URL
var blob = new Blob([data], { type: contentType });
var url = urlCreator.createObjectURL(blob);
link.setAttribute('href', url);
// Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
link.setAttribute("download", filename);
// Simulate clicking the download link
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(event);
console.log("Download link method with simulated click succeeded");
success = true;
} catch(ex) {
console.log("Download link method with simulated click failed with the following exception:");
console.log(ex);
}
}
if(!success)
{
// Fallback to window.location method
try
{
// Prepare a blob URL
// Use application/octet-stream when using window.location to force download
console.log("Trying download link method with window.location ...");
var blob = new Blob([data], { type: octetStreamMime });
var url = urlCreator.createObjectURL(blob);
window.location = url;
console.log("Download link method with window.location succeeded");
success = true;
} catch(ex) {
console.log("Download link method with window.location failed with the following exception:");
console.log(ex);
}
}
}
}
if(!success)
{
// Fallback to window.open method
console.log("No methods worked for saving the arraybuffer, using last resort window.open. Not Implemented");
//window.open(httpPath, '_blank', '');
}
};
Related
I am building a chrome extension which will get all the opened tabs and convert them to PNG file and download on the system.
What i have done till now
My code gets the URLs of all opened tabs and then gets the HTML DOM of each tab by using a for loop. Not i am using html2canvas to convert the html to png format, but i am getting the following error
Uncaught (in promise) Error: Document is not attached to a Window
at html2canvas.min.js:20
at html2canvas.min.js:20
at Object.next (html2canvas.min.js:20)
at html2canvas.min.js:20
at new Promise (<anonymous>)
at a (html2canvas.min.js:20)
at Vs (html2canvas.min.js:20)
at html2canvas.min.js:20
at getAllOpenWindows (popup.js:38)
My popup.js code is as follows:
// script for popup.html
window.onload = () => {
let btn = document.querySelector("#btnDL");
btn.innerHTML = "Download";
function display(){
// alert('Click button is pressed')
}
btn.addEventListener('click', display);
}
chrome.windows.getAll({populate:true}, getAllOpenWindows);
function getAllOpenWindows(winData) {
var tabs = [];
for (var i in winData) {
if (winData[i].focused === true) {
var winTabs = winData[i].tabs;
var totTabs = winTabs.length;
console.log("Number of opened tabs: "+ totTabs);
for (var j=0; j<totTabs;j++) {
tabs.push(winTabs[j].url);
tab_html_string = get_html_string(winTabs[j].url)
// get the HTML document of each tab
tab_document = get_html_document(tab_html_string)
console.log('======================')
console.log(tab_document)
html2canvas(tab_document.body, {
onrendered: function(canvas) {
var img = canvas.toDataURL("image/png")
chrome.windows.open(img);
}
});
console.log('======================')
}
}
}
console.log(tabs);
}
function get_html_document(tab_html_string){
/**
* Convert a template string into HTML DOM nodes
*/
var parser = new DOMParser();
var doc = parser.parseFromString(tab_html_string, 'text/html');
return doc;
}
function get_html_string(URL_string){
let xhr = new XMLHttpRequest();
xhr.open('GET', URL_string, false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`Error ${xhr.status}: ${xhr.statusText}`);
} else {
return xhr.response
}
} catch(err) {
// instead of onerror
alert("Request failed");
}
}
In the below image you can see the opened 6 tabs in chrome with output of each tabs in the console as document reference, but the error above is irritating me. Please help me out.
output image
I'd like to change the URLs from data:image base64 to blob. This is the original code that produces the base64 urls:
<script>
$(window).load(function(){
function readURL() {
var $input = $(this);
var $newinput = $(this).parent().parent().parent().find('.portimg ');
if (this.files && this.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
reset($newinput.next('.delbtn'), true);
$newinput.attr('src', e.target.result).show();
$newinput.after('<div class="delbtn delete_upload" title="Remove"><span class="bbb-icon bbb-i-remove2"></span></div>');
$("form").on('click', '.delbtn', function (e) {
reset($(this));
$("form").find('#rright-<?php echo $i;?>').hide();
});
}
reader.readAsDataURL(this.files[0]);
}
}
$(".file").change(readURL);
function reset(elm, prserveFileName) {
if (elm && elm.length > 0) {
var $input = elm;
$input.prev('.portimg').attr('src', '').hide();
if (!prserveFileName) {
$($input).parent().parent().parent().find('input.file ').val("");
//input.fileUpload and input#uploadre both need to empty values for particular div
}
elm.remove();
}
}
});
</script>
What I want is to call Object.createObjectURL(this.files[0]) to get the object URL, and use that as the src of your img; (just don't even bother with the FileReader).
Something like this?
function readURL() {
var file = this.files[0]
var reader = new FileReader();
var base64string = getBase64(file);
reader.onload = function () {
reset($newinput.next('.delbtn'), true);
$newinput.attr('src', e.target.result).show();
$newinput.after('<div class="delbtn delete_upload" title="Remove"><span class="bbb-icon bbb-i-remove2"></span></div>');
var blob = dataURItoBlob(base64string);
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
}
I'm not sure if this will work and due to the vagaries of Stack Snippets, can't demonstrate its viability here on Stack Overflow, but theoretically, you should be able to use URL.createObjectURL to create the appropriate URL for your image, without going through the whole base 64 rigmarole.
var $newinput = $(this).parent().parent().parent().find('.portimg ');
if (this.files && this.files[0]) {
$newinput.attr('src', URL.createObjectURL(this.files[0]));
// if the above doesn't work, you could try to create a new Blob
var fileBlob = new Blob(this.files[0], { type: "image/png" })
// Substitute "image/png" with whatever image type it is
$newinput.attr('src', URL.createObjectURL(fileBlob));
That should render the appropriate URL for the image's source.
Note that it is best practice to revoke the object URL when you are done with it. I'm not sure that's necessary in this case, since presumably you want to show the image until the page is closed. However, if the user can upload a new image, do something like:
if ($newinput.attr('src').indexOf('blob') > -1) {
URL.revokeObjectURL($newinput.attr('src'));
}
Add that before setting the new source and you shouldn't need to worry about memory leaks (from this use of createObjectURL anyway...).
For more information on Blob URLs, see this answer by a now-anonymous user to What is a blob URL and why it is used?
I'm working inside a Kendo Grid in a Kendo.MVC, Razor, C# project. I want the user to click on a row and download a file associated with that row. I got the on click event working. I found code to download the file that works in Chrome, but not IE 11. The code creates a new hyperlink and then calls a mouse click event. How do I do the same thing for IE11?
Here's the code (from SO, many thanks to lajarre for getting me this far!)
function onChange(arg)
{
var filePath = this.dataItem(this.select()).InvoicePath;
SaveToDisk(filePath, "PastInvoice");
}
function SaveToDisk(fileURL, fileName)
{
var save = document.createElement('a');
save.href = fileURL;
save.target = '_blank';
save.download = fileName || 'unknown';
var evt = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': false
});
save.dispatchEvent(evt);
(window.URL || window.webkitURL).revokeObjectURL(save.href);
}
The original author suggested using window.open(fileURL, fileName), but this just creates the file in a new tab, which do not meet my requirements.
Brief summation: this code works in Chrome, how do I get the same functionality for IE11?
** UPDATE # 1 **
I've been trying several methods I've found online, but can't get any of them to work. See the "catch" portion of the code where I've got different ways to download a file in IE. I've listed what happens and the related links. I think several of these are close, I just am missing something. Can someone help me get this to work?
function SaveToDisk(fileURL, fileName)
{
var save = document.createElement('a');
save.href = fileURL;
save.target = '_blank';
save.download = fileName || 'unknown';
try
{
var evt = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': false
});
save.dispatchEvent(evt);
(window.URL || window.webkitURL).revokeObjectURL(save.href);
}
catch (ex)
{
// Just opens the file in a new window https://www.codeproject.com/Tips/893254/JavaScript-Triggering-Event-Manually-in-Internet-E
//var event = document.createEvent("MouseEvent");
//event.initMouseEvent("click",true,false,window,0,0,0,0,0,false,false,false,false,0,null);
//save.dispatchEvent(event)
// Blob is undefined https://stackoverflow.com/questions/18394871/download-attribute-on-a-tag-not-working-in-ie
//navigator.msSaveBlob(blob, fileName);
// Nothing happened, no errors, no download https://stackoverflow.com/questions/18394871/download-attribute-on-a-tag-not-working-in-ie
//var oIframe = window.document.createElement('iframe');
//var $body = jQuery(document.body);
//var $oIframe = jQuery(oIframe).attr({
// src: fileURL,
// style: 'display:none'
//});
//$body.append($oIframe);
// Throw error, angular undefined https://stackoverflow.com/questions/18394871/download-attribute-on-a-tag-not-working-in-ie
//var blob = new Blob([fileURL], { type: "text/plain;charset=utf-8;" });
//var anchor = angular.element('<a/>');
//if (window.navigator.msSaveBlob)
//{ // IE
// window.navigator.msSaveOrOpenBlob(blob, fileName)
//} else if (navigator.userAgent.search("Firefox") !== -1)
//{ // Firefox
// anchor.css({ display: 'none' });
// angular.element(document.body).append(anchor);
// anchor.attr({
// href: 'data:attachment/csv;charset=utf-8,' + encodeURIComponent(data),
// target: '_blank',
// download: fileName
// })[0].click();
// anchor.remove();
//} else
//{ // Chrome
// anchor.attr({
// href: URL.createObjectURL(blob),
// target: '_blank',
// download: fileName
// })[0].click();
//}
// Throws error "no such interface supported" on createObjectURL
// https://msdn.microsoft.com/library/hh779016.aspx
// https://stackoverflow.com/questions/15904374/how-to-create-a-blob-object-from-image-url
//var blobObject = URL.createObjectURL(fileURL);
//window.navigator.msSaveBlob(blobObject, 'msSaveBlob_testFile.txt'); // The user only has the option of clicking the Save button.
// Nothing happened, no errors no download
// https://msdn.microsoft.com/library/hh779016.aspx
//https://stackoverflow.com/questions/11876175/how-to-get-a-file-or-blob-from-an-object-url
//var xhr = new XMLHttpRequest();
//xhr.open('GET', fileURL, true);
//xhr.responseType = 'blob';
//xhr.onload = function (e)
//{
// if (this.status == 200)
// {
// var myBlob = this.response;
// // myBlob is now the blob that the object URL pointed to.
// window.navigator.msSaveBlob(myBlob, 'msSaveBlob_testFile.txt'); // The user only has the option of clicking the Save button.
// }
//};
}
}
** UPDATE #2 **
Also tried using the following as a separate function. Like the first example in my last update, it opens the file in a new browser tab instead of downloading the file. The requirement is that the file be downloaded so that the user can't see the address of the file being downloaded.
(function (window)
{
try
{
new MouseEvent('test');
return false; // No need to polyfill
} catch (e)
{
// Need to polyfill - fall through
}
// Polyfills DOM4 MouseEvent
var MouseEvent = function (eventType, params)
{
params = params || { bubbles: false, cancelable: false };
var mouseEvent = document.createEvent('MouseEvent');
mouseEvent.initMouseEvent(eventType, params.bubbles, params.cancelable, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
return mouseEvent;
}
MouseEvent.prototype = Event.prototype;
window.MouseEvent = MouseEvent;
})(window);
I've created a simple web app using .NET (With Entity Framework) and AngularJS to retrieve PDF files. I'm able to have the app work perfectly on Desktop browsers and iOS browsers. Unfortunately I'm having issues with getting this to work on any Android browser.
Inside my controller is a function triggered by ng-click on a simple button that requests and displays the pdf. I was able to use the solution here to get the PDF's working correctly on iOS and Edge browsers.
appModule.controller("cellController", ['$scope','$http','$routeParams','$window','$sce', function ($scope, $http, $routeParams,$window,$sce) {
....
$scope.getLayout = function () {
var attachmentPromise = $http.get("/api/pdf" + $routeParams.ID, { responseType: 'blob' }).then(function (result) {
var file = new Blob([result.data], { type: 'application/pdf' });
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(file, "Layout.pdf");
}
else if (window.navigator.userAgent.match('CriOS')) {
var reader = new FileReader();
reader.onloadend = function () { $window.open(reader.result); };
reader.readAsDataURL(file);
}
else if (window.navigator.userAgent.match(/iPad/i) || window.navigator.userAgent.match(/iPhone/i)) {
var url = $window.URL.createObjectURL(file);
window.location.href = url;
}
else {
var url = window.URL || window.webkitURL;
window.open(url.createObjectURL(file));
}
});
};
}]);
As mentioned above the above code works well on desktop and iOS, but will either open a blank blob page on Android or fail to download the file on Android.
Any suggestions on this would be greatly appreciated :).
Let me know if I can provide any additional information
I was unable to get it to work as needed. As a work around, in the event the user is using an Android device I just download the document to local storage by opening a window to the file address. I hope this is something that is addressed in the future.
var attachmentPromise = $http.get("/api/" + $routeParams.ID, { responseType: 'blob' }).then(function (result) {
var file = new Blob([result.data], { type: 'application/pdf' });
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(file, "Layout.pdf");
}
else if (window.navigator.userAgent.match(/Chrome/i) && window.navigator.userAgent.match(/Mobile/i)) {
window.open("/api/" + $routeParams.ID)
}
else if (window.navigator.userAgent.match('CriOS')) {
var reader = new FileReader();
reader.onloadend = function () { $window.open(reader.result); };
reader.readAsDataURL(file);
}
else if (window.navigator.userAgent.match(/iPad/i) || window.navigator.userAgent.match(/iPhone/i)) {
var url = $window.URL.createObjectURL(file);
window.location.href = url;
}
else {
var url = window.URL || window.webkitURL;
window.open(url.createObjectURL(file));
}
})
This is my function:
FileCropped.prototype.change = function () {
var obj = $(this).data("plugin.file-cropped");
var files = obj.$element[0].files;
var file;
var URL = window.URL || window.webkitURL;
var blobURL;
if (files && files.length) {
file = files[0];
console.log("I have files");
if (/^image\/\w+$/.test(file.type)) {
blobURL = URL.createObjectURL(file);
obj.$element.val('');
obj.$hidden[0].value = blobURL;
//URL.revokeObjectURL(blobURL);
} else {
window.alert('Please choose an image file.');
}
} else
{
console.log("No files?");
}
}
I am trying right now to attach the blob to an existing form input but it does not work. With the chrome debugger I see the method works fine and follow the expected path, but at the time of submit the server gets nothing.
Any hint?
Edit: of course the function has no value right now. I could just use the normal file input. The goal is to be able to manipulate the blob before attaching it to the form.
You can use FileReader to read the file as data URL
var fileReader = new FileReader();
fileReader.addEventListener('load', function () {
blobURL = fileReader.result;
obj.$hidden[0].value = blobURL;
});
fileReader.readAsDataURL(file);