MVC 4: How to create visual Indicator while FileResult Action generates PDF to be sent back to browser? - asp.net-mvc-4

I have FileResult Controller Action that can take a couple minutes to run under some circumstances. I would like to provide our users a visual indication that the Action is running, such as a message, a spinner, or a progress bar. The trouble is, I'm having a tough time figuring out how to "detect" on the front end that the Action has completed.
I have been toying with Ajax calls to the FileResult Action, but that doesn't work because Ajax can't return a file to the browser. I also looked at Asynchronous Actions and Tasks, but it looks like FileResult does not support the "await" keyword, which I think is necessary.
At this point, I don't know what to try next, and am very open to thoughts/ideas.
Edit:
I got this working as bobek suggested. Basically, I saved the PDF file to disk, and returned the file path as an ActionResult Content(fullFilePath). Then, on my page, I used something like this to display a little spinner gif while the Action executed, and then a link to the file after it completed.
var img = $("img#reportLoadingIcon");
var link = $('a#exportedFileLink');
link.hide();
img.show();
$.ajax({
url: url,
success: function (result) {
link.attr({target: '_blank', href: result});
link.show();
img.hide();
}
});

You could make it a regular POST action called via AJAX, and instead of returning a File you can return path to file and redirect the user to that path.

Related

Is there a way to simulate a link/button click in mink?

I'm using a headless browser (phantomjs) in conjunction with Mink to do some functional testing on my Website.
Now in this setting, files can not be downloaded regularly e.g: by clicking a link. So I have to extract the url from the link or the button, and download the file manually.
As I just stated sometimes there is no link () for the download, but a button in a Form (e.g: Inputting data for a report in the form, and receiving the report file on submission).
So what I need to do is simulate clicking the link or button and extract the Data for the Request that would have been sent, and use that data to download the file manually.
Is there a way to do this?
Note: I'm using guzzle to actually download the file.
Mmmm... I don't know if you solved this and only as an alternative to typical mink methods. As Phantomjs is a javascript based browser engine, did you tried with javascript?
You could try something like this:
public function getElementHref($element)
{
/* #var FeatureContext $this */
$function = "(function(){
//Javascript method to get the href.
})()";
try {
return $this->featureContext->getSession()->evaluateScript($function);
} catch (Exception $e) {
throw new Exception('Element not found');
}
}
You can find a method to do this in javascript here: How to get anchor text/href on click using jQuery?
Then use the URL returned with file_get_contents (depending on the file type) and that's it.

How to a hide a page

I have a pop up that is called through a java script, the same pop up without a JavaScript is an ctp page in cakephp. How can I hide that page from users and search engines going to access it like: /users/register
Is there anything that can be done in .htaccess or cakephp to prevent access to it through /users/register
Remove register.ctp file from users folder and create one in ajax folder users/ajax/register.ctp, then use RequestHandler component to inspect request type:
public function register()
{
if($this->request->is('ajax')){
// add registration code here
} else {
//Throw new error
}
}

Is there any way to cancel an in-progress upload in dojo?

I have a file uploader that handles very large files. Lots of times the users will cancel an upload. There does not appear to be any way to make the browser cancel the XHR POST that is handling it. Consequently, progress and complete events fire much later and the upload actually completes. Presumably there must be an XHR object embedded in the uploader somewhere that I could call abort on, but I see nothing in the API docs, or in a console dump of the uploader object.
If your goal is to support only the HTML5 uploader (and not the Iframe or the Flash version), then you can do something like that:
Create a new uploader widget with the following (code not tested, might need some adjustment):
define(['dojo/_base/declare', 'dojox/form/Uploader'], function(declare, Uploader) {
return declare([Uploader], {
xhrRequest: null,
createXhr: function() {
this.xhrRequest = this.inherited(arguments);
return this.xhrRequest;
},
cancel: function() {
if (this.xhrRequest && this.xhrRequest.abort) {
this.xhrRequest.abort();
}
}
});
});
Use your new widget instead of dojox.form.Uploader
Call the cancel method when you want to cancel the upload.
But remember: this will work only with the HTML5 uploader.

Rails asset pipeline & coffeescript files, how to bind actions in various files to ajax calls?

Using rails 3 asset pipeline, I've structured the javascript (by using coffeescript) to files regarding the model. For example, all comment writing related javascript is stored to /app/assets/javascripts/comments.js.coffee, and user overlay related (fetching a:href's and triggering ajax on them) are stored in /app/assets/javascripts/users.js.coffee.
However, now I'm using more and more AJAX calls, where HTML content is pulled dynamically to the site. The problem is that I need to execute the javascript in various files, but as coffeescript is scoped inside a function, I can not access them.
Let's say that I've got a general.js.coffee file with following code
$(document).ready ->
# Parse all images with action
$("img.clickableaction").click ->
# Fetch some content
$.ajax
url: "something.php"
dataType: "html"
complete: (xhr, status) ->
# We got the content, set it up to a container
$("#somecontainer").html(receiveddata)
# The tricky part:
# run code in comments.js.coffee for #somecontainer (or for the whole dom)
# run code in users.js.coffee for #somecontainer (or for the whole dom)
And comments.js.coffee contains for example the following:
$(document).ready ->
commentDiv = $('div#commentsContainer')
commentsFetch = $('a.commentsFetch')
# Set commentid for comments fetch
commentsFetch.bind 'ajax:beforeSend', (event, xhr, settings) ->
# do stuff
The comments.js.coffee code works for the initial page view, e.g. the HTML code that was received when user loaded the page. But now, I need to parse the comments.js.coffee code for the content returned from the ajax call.
I can not make a function inside comments.js because it is scoped away, and can not be accessed from the general.js. This is what coffeescript produces:
(function() {
$(document).ready(function() {
var commentDiv, commentsFetch;
commentDiv = $('div#commentsContainer');
commentsFetch = $('a.commentsFetch');
}
})
I could make a global function for each separate file, e.g. window.comments && window.users, but then I'd need to call window.comments from the many places where I need to have ajax oncomplete call. On the long term, that will produce duplicate and hard to maintain -code.
How could something like this be made:
// comments.js
window.ajaxExecuteBlocks.push(function() { // comments related stuff });
// user.js
window.ajaxExecuteBlocks.push(function() { // user related stuff });
// general.js ajax on complete:
window.runExecuteBlocks()
Then, runExecuteBlocks would somehow run through all the functions that have been initialized in various controller-specific javascript files.
Anyone implemented similar system?

How can I cancel a file upload using the jQuery forms plugin

I'm using the jQuery Forms plugin to do an asynchronous file upload. Currently, the only way for the user to abort that upload is to press the "Stop" button on their browser, which may cause other javascript and ajax requests to stop as well. I'd like to provide a cancel button, but I haven't found any way to cancel an upload as it is happening using the API.
Is there a built-in way, or at least a robust hack I can use, to cancel the upload as it occurs?
The ajaxForm method takes all the same options that jQuery.ajax takes, so it is possible to capture the dummy xhr that it produces in a beforeSend handler. The xhr has an abort method that aborts the file upload:
f.ajaxForm({
beforeSend: function(xhr) {
cancelBtn.click(xhr.abort);
}});
Since Dec 2012 it is possible to access xhr directly:
var form = $('#myForm').ajaxSubmit({ ... });
var xhr = form.data('jqxhr');
....
$('#cancel').on('click', function(){
xhr.abort();
});
I use it to cancel ajax file upload.
link - https://github.com/malsup/form/issues/221