I have this piece of code on a site that exports the contents of local storage to a file in JSON format.
For some reason it stopped working. I tested it in multiple browsers but it's all the same...
No errors get displayed, yet it doesn't export either.
The different variables seem fine, yet it just isn't exporting.
To be honest I have no clue how to do this differently so any help would be appreciated.
Thx
function exportHistory() {
console.log("started");
var _myArray = JSON.stringify(localStorage , null, 4); //indentation in json format, human readable
var vLink = document.getElementById('exportHistory'),
var vBlob = new Blob([_myArray], {type: "octet/stream"}),
vName = 'working_history_' + todayDate() + '.json',
vUrl = window.URL.createObjectURL(vBlob);
console.log(vLink);
vLink.setAttribute('href', vUrl);
vLink.setAttribute('download', vName );
console.log("finished");
}
<button class="btn btn-outline-secondary btn-sm" id="exportHistory" onclick="exportHistory()">Export History</button >
Here you need to add the download attribute to an anchor tag <a> rather than the clicking button itself. You need to create an anchor tag with display:none and programmatically click it to download the file. Here is an example. Notice the button only used to execute the function and href and download attributes are added to the <a> tag.
function exportHistory() {
console.log("started");
var _myArray = JSON.stringify(localStorage , null, 4); //indentation in json format, human readable
//Note: We use the anchor tag here instead button.
var vLink = document.getElementById('exportHistoryLink');
var vBlob = new Blob([_myArray], {type: "octet/stream"});
vName = 'working_history_' + todayDate() + '.json';
vUrl = window.URL.createObjectURL(vBlob);
console.log(vLink);
vLink.setAttribute('href', vUrl);
vLink.setAttribute('download', vName );
//Note: Programmatically click the link to download the file
vLink.click();
console.log("finished");
}
Now add an empty anchor tag to the DOM.
<button class="btn btn-outline-secondary btn-sm" id="exportHistory" onclick="exportHistory()">Export History</button >
<a id="exportHistoryLink" style="display: none;">Export</a>
Related
I have a function where i can download my table data into csv. But the button function only works when i place it in my index.html page, while my table's on the subpage.html page. But somehow, my button in the index page is able to download my table data in that subpage.html when i navigate to there.
Index.html : The button here works
<body>
<header ng-include="'views/header.html'"></header>
<main ng-view></main>
<button type="button" id="btnDownload"> Download as CSV</button>
</body>
Subpage.html : If i place the button here it doesn't work
<div>
<table id="tabletodownload" ng-show="auditoriums === 'none'" style="border:1px solid #000;">
<tr> <th> Customer Name </th> <th> Order Value </th> <th> Ordered On </th> </tr>
<tr ng-repeat="audit in auditoriums| limitTo: 1 - auditoriums.length">
<td>{{audit.NAME}}</td>
<td>{{audit.ADDRESSBLOCKHOUSENUMBER}}</td>
<td>{{audit.ADDRESSPOSTALCODE}}</td>
<td>{{audit.ADDRESSSTREETNAME}}</td>
</tr>
</table>
<br />
</div>
<button type="button" id="btnDownload"> Download as CSV</button>
Javascript code to DL to csv :
$(function() {
$('#btnDownload').click(function() {
$("#tabletodownload").tableToCSV({
filename: 'CustomerList'
});
});
});
jQuery.fn.tableToCSV = function (options) {
var settings = $.extend({
filename: ""
}, options);
var clean_text = function (text) {
text = $.trim(text.replace(/"/g, '""'));
return '"' + text + '"';
};
$(this).each(function () {
var table = $(this);
var caption = settings.filename;
var title = [];
var rows = [];
$(this).find('tr').each(function () {
var data = [];
$(this).find('th').each(function () {
var text = clean_text($(this).text());
title.push(text);
});
$(this).find('td').each(function () {
var text = clean_text($(this).text());
data.push(text);
});
data = data.join(",");
rows.push(data);
});
title = title.join(",");
rows = rows.join("\n");
var csv = title + rows;
var uri = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
var download_link = document.createElement('a');
download_link.href = uri;
var ts = new Date().getTime();
if (caption == "") {
download_link.download = ts + ".csv";
} else {
download_link.download = caption + "-" + ts + ".csv";
}
document.body.appendChild(download_link);
download_link.click();
document.body.removeChild(download_link);
});
};
If the index.html and subpage.html are 2 different pages (and not an angularjs template or something like that) then it's probably because the code that is handling the button click and the rest of your function doesn't exist in the subpage.html.
quick and dirty
I assume you're not using any build tools. The simplest way is to move the button function to a script tag inside subpage.html
the angularjs way
I see you're using angularjs in the project. Manually attaching evenlisterens like a button click isn't the angularjs way of doing thing. You could easily move the functionality to your angular controller that control's that page and add a ng-click attribute to the button that calls that function. This way you're letting the framework decide when and hpw to attach the click event listener instead of managing that yourself.
Btw...
Using a framework like angular/react/vue most of the times makes jQuery unnecessary. In this case you could also use a library that made for amgularjs to make a csv from a table. jQuery is very DOM way of thinking while angular is more of a DATA way of thinking. In my opinion is that why it's better to not mix these things.
This might help you:
https://github.com/kollavarsham/ng-table-to-csv
I currently have a Javascript function which exports my AngularJS table of JSON data to a .csv file by div ID as shown:
$scope.exportToExcel = function (tableId) { // ex: '#my-table'
var exportHref = Excel.tableToExcel(tableId, 'WireWorkbenchDataExport');
$timeout(function () { location.href = exportHref; }, 100); // trigger download
}
Which I call like so
<button style="float: right;" class="btn btn-link" ng-click="exportToExcel('#codeProjectsTable')" filename="test.csv">
<span class="glyphicon glyphicon-share"></span>
Export table
</button>
This works well for data sets with ~400 records or less (20 columns per record), but I'm trying to export nearly 1,000 records for further reporting and I am simply being directed to an about:blank page.
I'm suspecting that it is either
Unable to export this large of a file
Timing out because of a long request
Thanks in advance.
I used following logic for to export
var fileName = 'users_export_' + moment().format('YYYY-MM-DD') + '.csv';
var url = URL.createObjectURL(new Blob([response.data]));
var a = document.createElement('a');
a.href = url;
a.download = fileName;
a.target = '_blank';
a.click();
And its working for large for large file/data
In some part of an html page, I have a link with the following code :
<a id="idname" class="classname" href="www.MySite.com/image-name.jpg">link-text</a>
I would like to automatically display the same link in another part of the same page by using a javascript.
What would be the script to insert in my page ?
Thank you in advance for any help in this matter.
Patrick
Try this:
myVar = document.getElementById("idname");
varLink = (myVar.attributes.href);
As son as you know the target id:
<div id="targetID">New Link: </div>
<div id="targetID2">New Link 2: </div>
And If you are using jQuery you can do like this:
var link = $("#idname").clone();
link.attr("id",link.attr("id") + (Math.random() * 10));
$("#targetID").append(link);
If not:
var link = document.getElementById("idname");
var newLink = document.createElement("a");
newLink.href = link.href;
newLink.className = link.className;
newLink.innerHTML = link.innerHTML;
newLink.id = link.id + (Math.random() * 10);
document.getElementById("targetID2").appendChild(newLink);
See this Example
<script>
window.onload = function() {
// get data from link we want to copy
var aHref = document.getElementById('idname').href;
var aText = document.getElementById('idname').innerHTML;
// create new link element with data above
var a = document.createElement('a');
a.innerHTML = aText;
a.href = aHref;
// paste our link to needed place
var placeToCopy = document.getElementById('anotherplace');
placeToCopy.appendChild(a);
}
</script>
Use code above, if you want just to copy your link to another place. JSFiddle
First, I want to point out that if you will just copy the element that will throw an error because the copied element will have the same id of the first one, so if you will create a copy of your element you don't have to give it the same id.
Try this code:
function copyLink(newDestination){
var dest=document.getElementById(newDestination);
var newLink=document.createElement("a");
var myLink=document.getElementsByClassName("classname")[0];
newLink.href=myLink.href;
newLink.className = myLink.className;
newLink.innerHTML = myLink.innerHTML;
newDestination.appendChild(newLink);
}
The newDestination parameter is the container element of the new Link.
For example if the new Container element has the id "div1":
window.onload = function() {
copyLink(div1);
}
Here's a DEMO.
Thank you very much to everyone for so many prompt replies.
Finally, I was able to use Jquery.
So, I tried the solution given by Andrew Lancaster.
In my page, I added the codes as follows, in this order :
1-
<span id="span1">
<a class="classname" href="www.MySite.com/image-name.jpg">link-text</a>
</span>
<p>
<span id="span2"></span>
</p>
and further down the page :
2-
<script type="text/javascript">
var span1val = $('#span1').html();
$('#span2').html(span1val);
</script>
Therefore, the two expected identical links are properly displayed.
But, unfortunately, I forgot to say something in my initial request:
the original link is in the bottom part of my page
I would like to have the duplicated link in a upper part of my page
So, would you know how to have the duplicated link above the original link ?
By the way, to solve the invalid markup mentioned by David, I just deleted id="idname" from the original link (that I could ignored or replaced by other means).
Thank you again in advance for any new reply.
Patrick
Using Jquery you could wrap your link in a span with an ID and then get the value of that ID and push it into another span id.
HTML
<span id="span1">
<a id="idname" class="classname" href="www.MySite.com/image-name.jpg">link-text</a>
</span>
<p>
<span id="span2"></span>
</p>
jQuery
var span1val = $('#span1').html();
$('#span2').html(span1val);
Example can be found here.
http://jsfiddle.net/3en2Lgmu/5/
I tried to register an onClick-handler using jQuery, which functionality should be to change the query string in the URL and to launch a reload whilst I assign a new URL to window.location.href.
// sets a new URL with lang as query parameter indicating the language
setNewLang: function( lang ) {
var that = this;
// the url that shall be changed
var url = window.location.href;
// save possible other query parameters
var tokenizedUrl = url.split("&");
// first string in the array contains language query parameter
var tokenZero = tokenizedUrl[0].split("l=");
// set the new language query parameter in the first part of the url
tokenizedUrl[0] = tokenZero[0] + "l=" + lang;
// concatenate the splitted url
var retVal = tokenizedUrl[0];
for(i=1; i<tokenizedUrl.length; i++) {
retVal = retVal + "&" + tokenizedUrl[i];
}
console.log(retVal);
// reload page with new query parameter for language
window.location = retVal;
return false;
}
/* language selection for navbar-right*/
$("#navbarRightLanguageListEnglish").on("click", function() {
console.log("DBG-INFO"); /* even the log never appears */
that.setNewLang("en_US");
});
I tried it with firefox and it worked.
Is there a bug in chromium? Or is it a problem of scope or jQuery or ...?
If there is another solution available to change and reload the site, I would be glad to know it.
Thanks for your help.
Hey folks!
I've forgotten to post the HTML and to say that I'm using bootstrap too.
By the way, I found the bug by myself, but thank you for your help.
<!-- Language Selection -->
<div id="navbarTopLanguage" class="dropdown dd-top">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" >Language<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li id="navbarTopLanguageListEnglish" role="presentation"><a role="menuitem" tabindex="-1" href="">English</a></li>
<li id="navbarTopLanguageListDeutsch" role="presentation"><a role="menuitem" tabindex="-1" href="">Deutsch</a></li>
</ul>
</div>
<!-- End of Language Selection -->
The "href"-attributes are empty and that was my fault. Chromium gives them are (wrong) value so that clicking it has not the wwanted effect.
I fixed it with changing the javascript.
// sets a new URL with lang as query parameter indicating the language
setNewLang: function( id, lang ) {
// selfie-pattern
var that = this;
// the url that shall be changed
var url = window.location.href;
// save possible other query parameters
var tokenizedUrl = url.split("&");
// first string in the array contains language query parameter
var tokenZero = tokenizedUrl[0].split("l=");
// set the new language query parameter in the first part of the url
tokenizedUrl[0] = tokenZero[0] + "l=" + lang;
// concatenate the splitted url
var retVal = tokenizedUrl[0];
for(i=1; i<tokenizedUrl.length; i++) {
retVal = retVal + "&" + tokenizedUrl[i];
}
console.log(retVal);
// reload page with new query parameter for language
$(id).attr("href",retVal);
}
The new function replaces the value of the specified "href"-attribute (parameter "id") with the new URL.
Thanks for your help.
Please try
window.location.href = retVal;
instead of
window.location = '...'
If you don't want previous URL to go to browser history, try
window.location.replace(retVal)
Hope this helps.
I am trying to follow this example to show progress bar without using ajax to download file.
I use knockout,html and webapi. I am having below code which calls href on click event of button
this.getMeData= function () {
uRlPath("/api/GetSomeData?id=" + 12)
+ "&name=" + getName.toString()
+ "&downloadtoken=" + new Date().getTime());
$('#myLink').click();
location.href = $('#myLink').attr('href');
};
This is my html
<tr>
<td class="labelText">
<button data-bind="click: getMeData">
Download Data
</button>
</td>
</tr>
<tr>
<td>
<a id="myLink" data-bind="attr: { href: uRlPath }" style="visibility: hidden">Open </a>
</td>
</tr>
I now want to call some function on click event of my href
This is my webapi method which returns me cookie and binary file
public HttpResponseMessage GetSomeData(int id, string name, string downloadtoken)
{
var returnData= new HttpResponseMessage(HttpStatusCode.OK);
returnData.Content = new ByteArrayContent(mybyteArray);
var cookie = new CookieHeaderValue("downloadtoken", downloadtoken);
returnData.Headers.AddCookies(new CookieHeaderValue[] { cookie });
returnData.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
returnData.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
returnData.Content.Headers.ContentDisposition.FileName = "myfile.pdf";
return returnData;
}
To be very precise i want to have same behaviour as provided in example. In example they use form to submit but i dont have any form as i just use html,knockout. I have included all libraries mentioned in example.
Do let me know if you need more inputs.
I found solution myself. I used below code to check constantly for cookie
var attempts = 30;
var checkTime
startProgressBar(true)
checkTime= window.setInterval(function () {
var cookieValue = $.cookie('downloadtoken');
if ((cookieValue == token) || (attempts == 0)){
stopDownload();
}
attempts --;
}, 1000);
In finishDownload function i clear cookie and stop progress bar
function stopDownload() {
window.clearInterval(checkTime);
$.cookie('downloadtoken', null); //clears this cookie value
stopProgressBar(false);
}
This is html code for progress bar
<div data-bind="visible: stopProgressBar" style="top:248px;left: 320px;">
<img src="../images/ProgressBar.jpg" />
</div>
If you just want to call the blockUIForDownload function when the link is clicked, you can do it with a "click" binding, just like you did for the button:
<a id="myLink" data-bind="attr: {href: uRlPath}, click: blockUIForDownload" style="visibility: hidden">Open</a>
(This assumes the function is already defined within the viewModel.)
See official documentation for the "click" binding here: http://knockoutjs.com/documentation/click-binding.html
However, it looks to me like you're overcomplicating it a bit - in the example you posted, a hidden input field is required because they're using a form input as a means to transfer the token to the server.
In your case the token is passed as a part of an href attribute, so you can greatly simplify the code:
1) Remove the invisible link completely
2) Replace the getMeData function with the following:
this.getMeData= function () {
window.open("/api/GetSomeData?id=" + 12
+ "&name=" + getName.toString()
+ "&downloadtoken=" + new Date().getTime());
blockUIForDownload();
};