I have long operation which retrieves data from my Active Directory and than shows this data in MVC view as table. All works except that it takes 20 seconds to present data. I have question how can i avoid UI blocking and show spinner while data is loading.
You can show a loading grpahic, then make an ajax call to fetch the data and when you receive a response from your asynchronous ajax call, show that to the user and hide(or replace) the loading image.
<div id="userTable">
<p>Loading...</p>
<img src="~/Content/images/loadingimage.png" alt="Please wait" />
</div>
and in the document ready event make the ajax call to get the data you want. You can use the jquery load() method.
$(function(){
$("#userTable").load("#Url.Action("UserList","Users")");
});
Assuming UserList() action method in UsersController will return a partial view with the markup of tabular data for your user list.
public ActionResult UserList()
{
var useViewModelList = new List<YourUserViewModel>();
useViewModelList.Add(new YourUserViewModel { Name="Scott" });
return PartialView(useViewModelList);
}
And in your partial view ( ~/Views/Shared/UserList.cshtml),
#model List<YourUserViewModel>
<table>
<tr><th>Name</th></tr>
#foreach(var item in Model)
{
<tr><td>#item.Name</td></tr>
}
</table>
Related
I want to show a popup using bootstrap which is defined in another view(e.g. SaveRecord.chhtml).
Is there any way to access bootstrap dialog box from any View(e.g. Registration.cshtml)
like give below
$(document).ready(function () {
$('/BootStrap/SaveRecord/.mymodal').modal('show');
}
where "mymodal" is bootstrap-id of given below
You really can't access elements like this as jQuery on it's own would require those elements to be present in the DOM in order to access them.
Create A Partial View And Load It As Needed
You could consider creating a Partial View that contained all of the necessary markup for your specific Modal and then when you needed to access it, simply load it into the DOM (if it doesn't already exist) via an AJAX call and then display it :
$(function(){
// Load your Partial View (assumes a Controller Action will route to it)
$.get('#Url.Action("GetYourPartialView","YourController")', function(html){
// Insert this element into the DOM
$('body').append(html);
// At this point it should exist, so load it
$('.myModal').modal('show');
});
});
This would assume that a Controller Action existed that would point to your specific Partial View that contained your modal (and only your modal) :
public ActionResult GetYourPartialView()
{
return View("YourPartialViewName");
}
Consider Using the Layout
Another solution that you could consider using would be to define your various modal "templates" that you might use throughout your solution at the Layout-level so that any pages that would rely on those would be able to access them.
You can use Partial Views.
Create your partial view _MyModal.cshtml under Views/Shared folder
In every view where you want to use it:
#Html.Partial("~/Views/Shared/_MyModal.cshtml")
On your javascript file: $('#mymodal').modal('show');
Here are the steps:
1.Make your bootstrap popup view a partial view
2.In your regular view, add a div which will have the modal content
<div id="divModalContent">
</div>
3. In your regular view, Add html button with onclick function
<input type="button" class="btn btn-default" value="{Your Text}" onclick="LoadSaveRecordModal()" />
4.Your JS:
function LoadSaveRecordModal()
{
$.ajax(
{
type: 'POST',
url: '{your url}',
data: data, //if required
success: function (result) {
$("#divModalContent").html(result); //load your modal content inside the div
$("#mymodal").modal('show'); //show the popup
},
failure: function (ex) {}
}
);
}
4.Your action method
public ActionResult GetSaveRecordModal(//get data if its post request)
{
//code
return PartialView("SaveRecord");
}
I have managed to get the JQuery Modal dialog to show and within it, I load a partial view:
var url = '#Url.Action("ShowCarDetail", "Car")?id=' + id;
$('#dialog-modal').dialog(
{
title: "Car Detail",
width: 600,
height: 500,
draggable: false,
close: function (event, ui) {
$(this).dialog('close');
}
});
$('#dialog-modal').load(url, function()
{
$(this).dialog('open');
});
So that works fine. The problem is that when the dialog is closed, and I re-open it, the data is not refreshed. I have a DateTime on that partial view that tells me this so leaving it for a few seconds still shows me the old values.
how can I force the modal dialog to load correctly (without it using the old html that may have been rendered from the previous request)?
also - if the partial view has some actions like a submit or something, will the dialog still remain open or will this refresh the page fully? I want to be able to have that modal dialog similar to an iframe style where any actions that happen within the page in the modal will still be there and be updated without the page having a full refresh and the dialog closing.
thanks
Regarding your question:
also - if the partial view has some actions like a submit or
something, will the dialog still remain open or will this refresh the
page fully? I want to be able to have that modal dialog similar to an
iframe style where any actions that happen within the page in the
modal will still be there and be updated without the page having a
full refresh and the dialog closing.
The page will be refreshed fully with a normal form. To achieve what you describe, use an ajax form which does a post to a controller method and returns a partial view. Then have a success callback for the ajax form, which would replace the contents of a div (within the open dialog) with the response content (which would be the partial view returned from the post).
Simplified example...
View:
<div id="dialog-modal">
<p>Some optional static content here (within the dialog)
that should not change when the form is submitted.</p>
<div id="dialog-content">
#using (Html.BeginForm("MyAction", "MyController", null, FormMethod.Post, new { #id="MyForm" }))
{
#Html.EditorFor(x => x.Foo)
<input type="submit" value="OK" />
}
</div>
</div>
Controller:
[HttpPost]
public ActionResult MyAction(MyModel model)
{
// Do some stuff here with the model if you want
MyNewModel newModel = new MyNewModel();
return PartialView("_MyPartialView", newModel);
}
JavaScript:
$(function () {
$('#MyForm').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (xhr) {
$('#dialog-content').html(xhr);
}
});
return false;
});
});
Note that this implementation will replace the form, so you could put the form outside the div that gets replaced if needed, or have a different form in the partial view that gets returned if you want different forms submitted within the dialog in series. It's flexible to tweak to your needs. It also will not close the dialog until you explicitly call close on it, or affect any content outside of the replaced div's content. Hope this helps!
I have forms located in multiple areas in my layout page (not nested).
I have a partial view which performs a post to controller action.
What action result do I return in that post to keep the user on the current page?
Is jquery/ajax my only option? I would rather a solution that didn't depend on javascript, maybe even a solution that degrades nicely.
You can use the Request.Referrer property to see what page the user has come from and then just use that to redirect them back there.
This does introduce other issues, e.g. losing ModelState, so you'll have to design for that. Also note that some users can block sending referrer information in their requests to the server - so the Referrer property can be null.
I would recommend using AJAX and then falling back on this.
You just need to do a RedirectToAction("") back to your main view.
To post a form without submitting the whole page, which refreshes the browser, you need to use Ajax/jQuery. The degraded solution is to submit the whole page like you would with a normal form.
Here's how I do it with jQuery.
Html:
<div id="RequestButtonDiv">
<button id="RequestButton" name="Request" type="button">Request</button>
</div>
This calls AddToCart on my Request controller when the RequestButton button is clicked. The response is placed inside the RequestButtonDiv element.
<script type="text/javascript">
$(document).ready(function () {
$('#RequestButton').click(function (event) {
$('#RequestButton').text('Processing...');
$('#RequestButton').attr('disabled', true);
submitRequest();
});
});
function submitRequest() {
$.ajax({
url: '<%: Url.Action("AddToCart", "Request", new { id = Model.RowId, randomId = new Random().Next(1, 999999) } ) %>',
success: function (response) {
// update status element
$('#RequestButtonDiv').html(response);
}
});
}
</script>
Controller action:
public ActionResult AddToCart(int id)
{
var user = AccountController.GetUserFromSession();
user.RequestCart.AddAsset(id);
return View("~/Views/Assets/Details_AddToCart.ascx");
}
The controller returns a partial view. You could also return Content("some stuff") instead.
Holler if you have questions or need more detail.
I have a delegate method with is called periodic while WritingAnObject uploading the file. I would like to update div (ProgressUpdate) in my MVC page with args.PercentDone value. I appreciate any idea?
Thanks,
//delegate method
private void displayProgress(object sender, ProgressArgs args)
{
//Console.WriteLine(args.PercentDone); //I want to display args.PercentDone in the page
}
//Controller
[HttpPost]
public ActionResult WritingAnObject(MyViewModel bovModel)
{
//DoSomeStuff which is cause calling displayProgress
return RedirectToAction("ListingSomeInfo", "testpart");
}
//View
<%using (Html.BeginForm("WritingAnObject", "testpart", FormMethod.Post, new { enctype = "multipart/form-data" }))
{%>
<%:Html.TextBox("catname") %>
<input type="file" id="fileupload" name="fileupload" />
<input type="submit" value="Upload" />
<%} %>
<div id= “ProgressUpdate”</div>
Here is one approach you could take to display progress back to a user while an operaton on the server is completing. (requires javascript)
1) Write an action that starts the process on the server. This method should update a progress value in session state (so that it is specific to each session the user is running).
2) Write an action that the client can call to return progress. This would read the value in session state. Generally this action will return either a small HTML fragment containing the progress bar filled in to the right amount, or a JSON object containing the progress value.
3) From your client, make a jQuery.ajax() call to asynchronously poll the server for progress while the operation is running and update the UI.
Additional bells&whistles:
- an Action to cancel a long running operation
- running the task outside the web application (Azure has some excellent features regarding running tasks asynchronously from a web app)
- Have the action that returns progress also let the client know if the operation is completed or canceled.
I'm using ASP.Net MVC to create a web site which needs to do some processing (5 - 10 seconds) before it can return a view to the user. Rather than leaving the user staring at the glacial progress bar I'd like to show some sort of "Please Wait/We'll be right back" animated gif to keep them interested.
Does anyone know a good approach to achieving this?
(I found this answer but its not quite what I need, this uses jQuery to fetch data once the view has been returned. I'd like to display the "Please Wait" while they're waiting for the view to appear)
Thanks
I think the solution you referenced will work for you. You just need to have your initial controller action return right away with the "please wait message", then have the AJAX call do the actual retrieval of the contents based on your processing. If the request really takes 5-10 seconds you may also need to adjust the timeout value on the AJAX request so that it is able to complete. I don't know what the default timeout is but is may be less than what you need.
EDIT Example:
View code:
<script type="text/javascript">
$(document).ready( function() {
$.ajax({
type: "POST",
url: '<$= Url.Action("GetSlowData","Controller") %>',
data: 'id=<%= ViewData["modelID"] %>',
timeout: 15000, // wait upto 15 secs
success: function(content){
$("#container").html(content);
}
});
});
</script>
...
<div id="#container">
Please wait while I retrieve the data.
</div>
Controller
public ActionResult ViewMyData( int id )
{
ViewData["modelID"] = id;
return View();
}
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult GetSlowData( int id )
{
var model = ... do what you need to do to get the model...
return PartialView(model);
}
You'll also need a partial view (ViewUserControl) that takes your model and renders the view of the model. Note that this isn't complete -- you'll need to add error handling, you may want to consider what happens if javascript isn't enabled, ...