Trigger click on element dynamically created by AngularJS - angularjs

I'm using AngularJS to create a new tag in order to download a csv file. Below the code I use to trigger the download. The download starts on Chrome but not in Firefox. Do you have any clue why this happens?
var element = angular.element('<a/>');
element.attr({
href: exportedString,
target: '_self',
download: 'test.csv'
})[0].click();
EDIT: Firefox needs an existent DOM
JS:
var linkElem = $("#link");
var element = angular.element(linkElem);
HTML:
<a ng-hide=true id="link"></a>
EDIT 2: On Chrome, the downloaded file name is "download" and not the passed value ("test.csv" in this case). Any suggestions?
Here there is also a plunker

This is a bug in Chrome 35 reported in issue #377860.
Follow this answer for more details
I updated your plunker solution.
Basically you need to use it like follow:
var element = document.createElement('a');
var blob = new Blob([$scope.exportContent], {
type: 'text/csv'
});
var url = URL.createObjectURL(blob);
element.href = url;
element.setAttribute('download', 'test.csv');
document.body.appendChild(element); //Append the element to work in firefox
element.click();

To get both Chrome & FF to work, I actually found that I had to first check to see if element[0] was undefined (which it was in Chrome but not FF):
var link = $("#reportDownloadLink");
var element = angular.element(link)
.attr('href', dataUrl)
.attr('download', data.FileDownloadName)
.attr('target', '_blank');
(element[0] || element).click();

Related

How to download a text file based on a generated String using AngularJS?

I'm trying to get AngularJS to trigger a file download when a user clicks on a button.
The file that should download has to contain data that is generated during the script execution, so the text file's content should be built from a basic string in AngularJS.
How do I implement this?
Here is some mockup code on how I imagine this would work:
var fileContent = 'foobar';
$scope.download = function() {
filedownload.run(fileContent, 'filename.txt');
}
In order to achieve this you have to create an a tag in your HTML:
<a download="content.txt" ng-href="{{ url }}">download</a>
Controller:
var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );
And to enable the URL:
app = angular.module(...);
app.config(['$compileProvider',
function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/);
}]);
Source:
How do you serve a file for download with AngularJS or Javascript?
In simple cases, you can create a link with a Data URI:
var fileContent = 'foobar';
$scope.download = 'data:text/plain;base64,' + btoa(fileContent);
And then use it in your HTML template:
click here to download
You may need to adapt the MIME type, depending on your string.

ng-click event not defined after $compile in google maps infowindow

Within this angular google map, I want to give the ability for a link to appear in a dynamic infowindow thats generated when the user searchs an address.
Now Ive got the infowindow to load correctly but the ng-click event is coming back undefined.
I have compiled the HTML string but still having no joy. Here is the compile code:
google.maps.event.addListener(this.marker, 'click', function () {
var contentString2 = "<div><a ng-click='hello()'>Click me!</a></div>";
var compiled = $compile(contentString2)($q);
var infowindow = new google.maps.InfoWindow({
content: compiled[0]
});
this.selectedMarker = this.marker;
infowindow.open(this.map, this.marker);
});
};
The infowindow loads fine when the marker is selected but when the "ng-click" is clicked inside the infowindow it comes back with:
Uncaught TypeError: undefined is not a function
I've provided a jsbin link to show the code:
http://jsbin.com/zukefa/edit
Thanks in advance for your help.

Backbonejs: model not getting passed in underscore template

I am new to backbonejs. What I am trying to do is, render a template on page load and pass model as data parameter in _.template function. Here is my bacbone code:
var Trip = Backbone.Model.extend({
url: '/trips/' + trip_id + '/show'
});
var InviteTraveller = Backbone.View.extend({
el: '.page',
render: function () {
var that = this;
var trip = new Trip();
trip.fetch({
success: function(){
console.log(trip); //logs trip object correctly
var template = _.template($('#invite-traveller-template').html(), {trip: trip});
that.$el.html(template);
}
});
}
});
var Router = Backbone.Router.extend({
routes: {
'': 'fetchTrip'
}
});
var inviteTraveller = new InviteTraveller();
var router = new Router();
router.on('route:fetchTrip',function () {
inviteTraveller.render();
});
Backbone.history.start();
And here is my sample template:
<script type="text/template" id="invite-traveller-template">
<h3>Trip</h3>
<h3><%= trip.get('name') %></h3>
</script>
On running, I am getting the this in browser window and console shows:
trip is not defined
I am facing this issue since yesterday but could not figure out the solution yet. Not understanding what is going wrong, code also seems to be right. Any help would be greatly appreciated.
Update:
I removed
inviteTravellers.render();
from router.on() and then reloaded the page in browser. I still got same error which means that <script></script> (template) is being compiled before calling render() of InviteTraveller view. What can be the possible reason for this?
I had the same issue (underscore v1.8.2). My fix:
var template = _.template($('#invite-traveller-template').html());
var compiled = template({trip: trip});
that.$el.html(compiled);
You're passing the whole model to the template. Typically you would call model.toJSON and then pass its result to the template. Additionally using <%= in your template to render the attribute, which is meant for interpolating variables from that JSON object you're passing.
You can pass a whole model to the template and use <% ... %> to execute pure Javascript code and use print to get the attribute but it's probably overkill.
Have a look at this fiddle.
You code work perfectfly, here's it
I think that your problem came from another code, not the one you have posted, because there's no way for your view to render if you remove :
inviteTravellers.render();
Try to chaneg <h3><% trip.get('name'); %></h3> by <h3><%= trip.get('name') %></h3>
My code seems to be right but still my template was getting compiled on page load and I was getting trip is not defined error. I did not understand the reason of this behavior yet.
I solved this issue by using handlebarsjs instead of default underscore templates.

still the navigate triggers and upate my url, the method is not calling

In my backbone app, i use the requirejs to load the js files. as well i need different views, there is no.of links are there in my drop down menu. according to the drop down menu i a adding the #url example:
http://localhost:85/bino/html/interface-I.html#projectName/project11
the navigate method works fine and updating the url, also whenever i copy and paste this url to any other browser / refresh with current hash state my router methods works fine.
But click on link in the drop down menu not working, the method not calling... what would be the reason and how can i fix this..?
my code: main js file (part of code)
var extender = _.extend({},backBone.Events);
var params ={
boardHolder :$('.boardHolder'),
column :3,
space :30,
extender :extender
};
var listApp = new routerer(params);
backBone.history.start();
extender.bind("list:selected",function(post){
listApp.navigate(post.category+'/'+post.filter);
});
my router code :
define(["backBone","singleton","listCollection","listView","listViews"],function(Backbone,singleton,listCollection,listView,listViews){
singleton.router = Backbone.Router.extend({
routes:{
"" :"appView",
"post" :"postView",
"projectName/:id" :"projectNameView",
"assignedTo/:id" :"assignedToView",
"sortBy/:id" :"sortByView"
},
initialize:function(params){
this.params = params;
this.collection = new listCollection;
console.log('i am called');
},
hashView:function(){
console.log('from hash view');
},
appView:function(){
var that = this;
// var defaultApp = new listCollection();
this.collection.fetch({
success:function(data){
new listViews({model:data,params:that.params})
}
})
},
projectNameView:function(thisView){ // not calling not sync
console.log('called',thisView); // on click not works
},
assignedToView:function(thisView){ // not calling not sync
console.log(thisView); // on click not works
},
sortByView:function(thisView){ // not calling not sync
console.log(thisView); // on click not works
}
});
return singleton.router;
})
thanks in advance.
navigate only updates the url, you also have to call the route function by setting the trigger option to true. If you'd like to update the URL without creating an entry in the browser's history, also set the replace option to true.
listApp.navigate(post.category+'/'+post.filter);
would become
listApp.navigate(post.category+'/'+post.filter, {trigger: true});

Force download of 'data:text/plain' URL

I was wondering whether it is possible to force a browser (at least Chrome) to download a data:text/plain URL.
Chrome does download binary URLs (e.g. data:application/zip;base64,...), but it does not download files that can be viewed inside the browser (such as text files).
What I already tried with no luck so far is this:
data:text/plain;content-disposition=attachment;filename=test.txt;...
But it seems like I cannot add headers like this.
Is there any way to make Chrome download a data:text/plain,... URL?
As of now, it has been made possible to use <a download> in Chrome. Using dispatchEvent, you can download any string as file (even with a custom filename) whenever you want. Here's a utility function to use it:
var downloadFile = function(filename, content) {
var blob = new Blob([content]);
var evt = document.createEvent("HTMLEvents");
evt.initEvent("click");
$("<a>", {
download: filename,
href: webkitURL.createObjectURL(blob)
}).get(0).dispatchEvent(evt);
};
Usage:
downloadFile("foo.txt", "bar");
It uses jQuery and the webkit prefix, but both can be avoided.
Try this:
<a download="file_downloaded_via_data_URL.txt"
href="data:text/plain;base64,SGVsbG8sIHdvcmxkISBJJ20gZG93bmxvYWRlZCB2aWEgImRhdGE6dGV4dC9wbGFpbjsuLi4iIFVSTCB1c2luZyA8YSBkb3dubG9hZD0iZmlsZV9uYW1lIi4uLj4uDQpNeSBiaXJ0aHBsYWNlOiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzY0Njg1MTcvDQoNCk1vcmUgYWJvdXQ6DQpodHRwOi8vd3d3LnczLm9yZy9UUi9odG1sL2xpbmtzLmh0bWwjYXR0ci1oeXBlcmxpbmstZG93bmxvYWQNCmh0dHA6Ly93d3cudzMub3JnL1RSL2h0bWwvbGlua3MuaHRtbCNkb3dubG9hZGluZy1yZXNvdXJjZXMNCg0KQnJvd3NlciBzdXBwb3J0OiBodHRwOi8vY2FuaXVzZS5jb20vZG93bmxvYWQ=">
Download text file
</a>
It uses HTML5 attribute download="filename.ext". (no JS needed:)
More about:
http://www.w3.org/TR/html/links.html#downloading-resources
Browser support can be checked at http://caniuse.com/download
(As for now, 2013, no IE nor Safari support)
I think, you can make a fallback for not-supporting browsers: use JS to change value of href="..." to the URL of your server script (which will return the file contents with appropriate HTTP header Content-disposition: attachment;filename=filename.txt).
Here is a pure Javascript solution for creating a text blob and download as text file
var fileContent = 'This is sample text file';
var fileName = 'sampleFile.txt';
const blob = new Blob([fileContent], { type: 'text/plain' });
const a = document.createElement('a');
a.setAttribute('download', fileName);
a.setAttribute('href', window.URL.createObjectURL(blob));
a.click();
What I did was sending the data to a server, which sends them back with the following HTTP header:
Content-disposition: attachment;filename=test.txt
I don't like this, but it works rather well.
This works as hell ...
<div class="tags-style-one dragme" draggable="true" data-transfer="33343">some value is 33343</div>
<script type="text/javascript">
(function ($) {
$(document).ready(function () {
$('.dragme').on("dragstart",function(evt) {
evt.originalEvent
.dataTransfer
.setData(
"text/plain",
$(this).data('transfer').toString()
);
});
})(jQuery);
</script>

Resources