How do I trigger 'ajaxStart' and 'ajaxStop' from ASP.NET MVC 5 Html.BeginForm? - asp.net-mvc

I am working on a corporate ASP.NET MVC 5 website that has 159 *.cshtml View pages.
I am trying to incorporate a Wait Cursor to display whenever a query is run.
Some pages have queries that are called with jQuery/Ajax calls:
$.get("#Url.Action("SomeQuery", "ControllerN"));`
By adding the below div tag and jQuery to the Shared_ConsoleLayout.cshtml file, the Wait Cursor will show and hide anytime jQuery makes one of the Ajax calls:
<div id="waitDiv" style="position:fixed; top: 50%; left: 50%">
<p style="text-align: center">
Loading...<br />
<img src="~/Images/wait.gif" /><br />
Please Wait.
</p>
</div>
...
$(document).ready(function () {
$('#waitDiv').hide();
$(document).ajaxStart(function () {
$('#waitDiv').show();
})
$(document).ajaxStop(function () {
$('#waitDiv').hide();
});
});
But, I don't know how to show and hide the div using the ASP.NET MVC 5 Html.BeginForm syntax, and they account for over 90% of the calls on the corporate website.
#using (Html.BeginForm("SomeQuery", "ControllerN", FormMethod.Post))`
What can I do to allow the Wait Cursor to show and hide with the ASP.NET MVC 5 Html.BeginForm techniques?

The Html.BeginForm is just a syntax wrapper on the "form" tag. Submitting a form operates synchronously, and there are no such events. You can handle the submit event to show some indicator, which will be automatically hidden (overridden) within a new page HTML.
If you need to implement asynchronous data posting, you can modify your existing jQuery code - for example, use the jQuery ajax plugin instead and specify the request data manually (I guess this is why you are looking for a form usage). Otherwise, use the Ajax.BeginForm instead, which have the necessary events (similar to the jQuery get/ajax plugin): How to use Simple Ajax Beginform in Asp.net MVC 4?

Related

Angular.js in ASP.Net MVC -- need to reload page twice

I minimized the problem to this simple reproduction. Create new Asp.net MVC app, add Angular.js via nugget.
_Layout.cshtml:
<head>
<!-- Other stuff -->
#RenderSection("JavascriptInHead", required: false)
</head>
_Index.cshtml
#section JavascriptInHead {
<script src="~/Scripts/angular.min.js"></script>
}
<div ng-app>
{{2 + 2}}
</div>
So this works (obviously), however when I click, say About or Contact menu to reload another view and then go back to Home, I get
{{2 + 2}}
Then I click page reload two times and I get
4
Please help me understand this..
Angular bootstraps when the document loads. So if you are loading html that contains angular into your page without doing a full page refresh, you'll need to bootstrap angular manually. Try adding this script to your partial page:
angular.element(document).ready(function() {
angular.bootstrap(document);
});
btw, I for one appreciate you posting a concise example rather than 100 lines of code from your actual project. If your actual project has an app name, however, like this...
<div ng-app="myApp">
then the js you put into your partial page should look like this...
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
Documentation for manually bootstrapping Angular can be found here: https://docs.angularjs.org/guide/bootstrap

Jquery Mobile Javascript not working on ajax load

Have the following markup in my html page to toggle a search bar based on if a search icon is clicked:
<a id="searchIcon" href="/"></a>
<div id="searchWrapOuter" style="display:none;">
<div id="searchWrapInner">
<div id="formContainer">
<form id="searchForm" action="#">
<div>
<input type="search" name="search-mini" id="search-mini" value="" data-mini="true" />
</div>
</form>
</div>
</div>
</div>
Width the following javascipt/jquery:
$(function() {
$(document).on("click", "#searchIcon", function () {
var searchWrapper = $("#searchWrapOuter");
$(searchWrapper).slideToggle();
return false;
});
});
This code works as expected on a page load direct off a Url. When coming into the page off a link which is Ajax loaded, loads the contents of the page into the DOM, and the DOM ready handler only executes for the first page.
I have read about using the
$(document).on('pageinit'), not $(document).ready()/$(function()
I still haven't been able to get this to work when coming in off an ajax link however. What would be the correct way to implement these events to get the code to work coming in from an Ajax link?
Thanks,
Most likely it is because you are using IDs instead of classes. jQuery Mobile doesn't work well with IDs because it caches pages into the DOM so if you open a page, close it, then go back to the page, you might have your page twice inside the DOM (one visible, one hidden/cached). So when you do $("#searchWrapOuter") you don't know which element you are actually dealing with (in your case, probably the hidden one).
The solution is to change your IDs to classes. This is not very intuitive but I found that is the best way to work with jQuery Mobile.
Also note this comment in the doc which might also be relevant to you:
The id attribute of all your elements must be not only unique on a given page, but also unique across the pages in a site. This is because jQuery Mobile's single-page navigation model allows many different "pages" to be present in the DOM at the same time. This also applies when using a multi-page template, since all "pages" on the template are loaded at once.
http://jquerymobile.com/demos/1.2.0/docs/pages/page-anatomy.html
You can manually adjust delay time to 500ms and 1s.
$(searchWrapper).delay(1000).slideToggle();
My issue is that the page id was below the pages tags. So once I moved the page div above it, the javascript was included in the ajax page load. Previous to this

MVC 3 unobtrusive javascript links in refreshed partial view results

I have noticed that if you add a unobtrusive link in a refreshable partial view such as
<a href="/" data-delete-chapter="#Model.Chapter.ChapterId" class="delete-chapter" >
Delete
</a>
wired up in javascript file in order to do a (less ugly) Jquery popup delete confirmation):
$("[data-delete-chapter]").each(function () {
$(this).click( ...
then upon refresh of the partial view via ajax these javascript handlers dispappear so you end up having to refresh them each ajax call. You can do this with OnSuccess AjaxOption:
or directly in html as data-ajax-success such as my page previous button:
<a data-ajax="true" data-ajax-loading="#chapterAjaxImage" data-ajax-method="GET"
data-ajax-mode="replace" data-ajax-update="#chapterContainer"
href="ScrollChapterPrev/#(Model.VideoId)?pageNumber=#(Model.PageNumber)"
data-ajax-success="afterChapterRefresh()" class="gallery-prev">
<img src="#Url.Content("~/Content/Images/play/chapter-slider-prev.png")" alt="prev" />
</a>
however I feel that having
data-ajax-success="afterChapterRefresh()"
in the multiple places that refreshes my chapter list is not a lot less unobtrusive than making my original delete link use javascript thereby avoid the need to reference a refresh JS function:
<a href="javascript:deleteChapter(10)" class="delete-chapter" >
Delete
</a>
is there a better way or am I as close as unobtrusive that I can get in this special case?
Loading the content via ajax means , you are injecting something to the DOM , after the events ( click or whatever) bounded. So the newly injected elements wont have that event binding.
jQuery on would help. on will work on current elements and future elements
Change this
$("[data-delete-chapter]").each(function () {
$(this).click(function(){
//do something
});
});
to this
$(document).on("click","[data-delete-chapter]"(function(){
//do something
});

how does unobstrusive javascript work in ASP.NET MVC3?

Is there a tutorial or explanation how MVC3 implements unobstrusive javascript using HTML5 data tags? I would like to know how I can extend this practice for my own javascript, espescially, how are the data tags efficiently parsed to execute javascript, to attach event handlers, etc.?
In ASP.NET MVC 1 and 2, client side validation and any AJAX behavior meant that ASP.NET MVC would automatically generate javascript for validation or AJAX class. The result was a <script> tag with javascript embedded that would be outputted on the HTML page or data in the event handlers of an input (like onclick).
Unobtrusive javascript eliminates the need to embedded javascript in the HTML page by placing all necessary things in data- attributes on the element. With this in place, jquery.validate.unobtrusive will validate and do AJAX class based on the information in the data- attributes of the input control.
For more details, take a look at this asp.net mvc 3 tutorial which offers a quick example. The unobtrusive explanation is towards the end under the second Enabling Client-Side Validation.
Take a look at this blog post which displays the difference of output for unobtrusive and normal validation.
Basically it's just using jQuery to attach event handlers rather than putting script directly in the html attributes.
For example a document ready event containing
$("#button1").click(DoStuff);
and the html
<button id="button1" />
is equivalent to
<button id="button1" onclick="DoStuff()" />
In this example it's not a huge difference, but for more complex cases it makes the code much cleaner, especially if you want to use anonymous callback functions.
Look in the unobtrusive script files (like jquery.unobtrusive-ajax.js) where you'll find it's just a case of using selectors to find elements with data- attributes.
For example:
$("a[data-ajax=true]").live("click", function (evt) {
evt.preventDefault();
...
});
$("form[data-ajax=true]").live("submit", function (evt) {
...
});
I've started using my own data- attributes to hookup features like autocomplete and datepicker. For example, adding an input with a data-autocomplete attribute pointing to a remote data source, then using jQuery to wire it up unobtrusively.
$(":input[data-autocomplete]").each(function () {
$(this).autocomplete({ source: $(this).attr("data-autocomplete") });
});
Demonstrated here, if you are interested: http://www.pluralsight-training.net/microsoft/players/PSODPlayer.aspx?author=scott-allen&name=mvc3-building-ajax&mode=live&clip=0&course=aspdotnet-mvc3-intro

How do I create a MVC 'Wizard' similar in functionality to Webforms Wizards?

I'd like to create a wizard in ASP.NET MVC similar to the wizard control functionality found in ASP.NET webforms.
What is the best way to do this?
With ASP.NET MVC I would suggest using javascript/jquery to create a wizard in a web page; something like
<script type="text/javascript">
$().ready(InitializeWizard);
function InitializeWizard() {
$(".step").hide();
$("#step1").show();
}
function Step1OK() {
$("#step1").hide();
$("#step2").show();
}
function Step2OK() {
$("#step2").hide();
$("#stepComplete").show();
}
</script>
<div id="step1" class="step">
Step 1
<input type="button" onclick="Step1OK();" value="OK" />
</div>
<div id="step2" class="step">
Step 2
<input type="button" onclick="Step2OK();" value="OK" />
</div>
<div id="stepComplete" class="step">
Complete
</div>
NB! Remember, in the top of the document, to load jquery, e.g. by referencing the google link:
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1.3.2");
</script>
There is no simple way to use a wizard control in ASP.NET MVC. Because ASP.NET MVC is not Web forms, so you should stop thinking webformy and start thinking the MVC way. A better thing to do would be to leverage jQuery and partials (Partial Views) to come up with a nice user experience which walks the user through some predefined steps.
ASP.NET MVC itself is a stateless design pattern meaning between requests there is no form of state. If you would like to hold some sort of state you would have to use some sort of persistant mechanism like a cookie, querystring (blah?page=2), session or maybe even in the database.
Try this one.
It uses jQuery and contains a sample project.
You can use the simple component MVCWizard.Wizard available on NuGet.
The WizardController allows you to create a wizard using partial view.
There is also the AutoWizardController that renders the entire wizard in a single view.
All these components operate with the session to store the model state.

Resources