ASP.Net MVC Loading In Progress Indicator - asp.net-mvc

I have an MVC Controller that runs through a process, sets some View Data, and then returns the results of this data back to the user in a View. The process time is dependent on the amount of data that is being processed. I need a good way to display an animated .gif within the View while the process is running, letting the user know that something is going on.
I've looked at various AJAX methods and partial views but still cannot find a good way to accomplish this. What I really wished I could do was have an ActionFilter that would return a View or Partial View during the OnActionExecuting event that displays this animated .gif, then once the Controller completed processsing and returned the ViewData, the view or partial view with the actual View Data could be displayed.
It also seems like jQuery would be able to provide a nice asynchronous way to call the controller action in the background and then render the View. Any help would be appreciated.

In your controller:
public JsonResult GetSomething(int id)
{
return Json(service.GetSomething(id));
}
In the view (javascript, using JQuery):
$('#someLink').click(function()
{
var action = '<%=Html.ResolveUrl("~/MyController.mvc/GetSomething/")%>' + $('#someId').val() + '?x=' + new Date().getTime();
$('#loading').show()
$.getJSON(action, null, function(something)
{
do stuff with something
$('#loading').hide()
});
});
Note that this assumes a route where 'id' comes after action. The 'x' parameter on the action is to defeat aggressive caching in IE.
In the view (markup):
<img id="loading" src="images/ajax-loader.gif" alt=""/>
<!-- use a css stlye to make display:none -->
Get loader gifs here.
Also note that you do not have to do this with Json. You can fetch other things like HTML or XML from the controller action if you prefer.

Related

How to load TreeView data only once in a _Layout page

Our users asked to have the Kendo Tree show up in the MVC web app in a panel on the left hand side of the page. They want that left hand panel to be present on every screen.
Currently I have a section of my _Layout.cshtml page that renders the Kendo Tree:
<div>
#{Html.RenderAction("GetTree", "Tree");}
</div>
Inside that Action I make a database call to get the contents of the tree and bind the model to the view as follows:
#model IEnumerable<TreeViewItemModel>
But obviously with this pattern every page I go to the _Layout gets called and the tree data is fetched from the database again. This is not very efficient.
What is a better way so that I only make a single database call?
I'm going to assume that the content of the tree is the same for every page and every user.
In that case, you can cache the retrieved database data so that you don't have to retrieve it on every page render. There are lots of ways to cache it: the simplest is probably to use ASP.NET's own caching, which is described in detail (with walkthroughs) here.
You probably will still have to render it on every page (unless you want to get into partial page caching, and I'm not sure how that works in MVC) but you definitely can avoid the repeated database hit.
ETA: You can create a wrapper or helper class that retrieves the necessary tree data by company. The relevant method would look a bit like this:
public IEnumerable<TreeViewItemModel> GetCachedTreeDataByCompany(int companyId)
{
var data = Cache["TreeData"] as IEnumerable<TreeViewItemModel>;
if(data == null)
{
data = GetTreeData(); // whatever you need to do to get the data
Cache.Insert("TreeData", data);
}
return data.Where(tvim => tvim.CompanyId == companyId).ToArray();
}

MVC 3 Passing Data From HTML to Controller to Another Controller via HTTPPOST

I don't know if I'm doing this wrong, but here's my problem. I need to pass a View's data to another Controller/Action.
In my HTML Form, I have
#using (Html.BeginForm("Preprocess", "Item", FormMethod.Post))
{
...some html...
...loop for each item in Items collection
<button type="submit" name="itemInfo" value="#Model.someValue">Submit</submit>
}
I receive the Form's data on my Item/Preprocess Action (strongly-typed view). However, I need to pass this to a 'central processor' that process the data depending on a certain flag. How do I pass the values I receive on this controller to another controller? I'm a beginner in MVC and I'm not even sure if this is the right way to do it.
Basically, I have three HTML forms similar from the above form, but with different Controllers and Views. I need them to call a single central master-Controller/Action and of course pass the data from the Form to the master Controller via HTTPPOST. Of course, each Controller has to format its own data to a class the master Controller can accept. What should I put in place of Return View() or RedirectToAction(...)?
Can you guys suggest a way to do this?
Or maybe you guys can suggest another way. It may not follow what I want, but basically my requirement is a central Controller/Action (or some other Centralized code) can receive the data and do operations depending on a value
You can do this:
return RedirectToAction("SomeAction", "SomeController",new { id=someString} );
Not sure I follow exactly what you are trying to do here. But from your description it does sound like your design is wrong.
If you are trying to perform some common set of actions once data is received and processed by your controllers then you should promote your "central controller" to be some kind of service class that can be accessed by all three controllers. The service class could return a ActionResult if necessary:
return new ViewResult { ViewName = "MyForm" };
However if you want to intercept the data and perform some common actions you could write a custom ActionFilter to do whatever your central controller is doing and leave the other controllers clean.

Display partialview based on a url

I have a partialview in _Layout.cshtml that I only want to display for certain urls.
My first thought was in my partial I would use a string as the model #model String .
In the actionmethod that is called I would return this
return PartialView("_MyPartial", new string{Request.FilePath});
In the partial I would have an if block wrapping my outer div that would check the model to see if the url it contained was the url that can display the partial.
I don't like this way because I would have to hardcode the url in if block check
#if( Model == "/Test/Home")
{
<div>
Just an example
</div>
}
What would be the best way to do this?
Thanks
You shouldn't need to use hard coded strings, even if you did the validation within your view like you initially intended.
You can use
Request.Url.AbsolutePath
to get your current url and
Url.Action("action", "controller")
to generate the inacceptable locations.
That said, I would keep your logic determining whether to show the partial view within your controller.
if(showPartialView)
return PartialView("_MyPartial");
else
return new EmptyResult();
Deciding actions based on the request is the responsibility of the Controller. Since the controller chooses the view, why not have it choose the partial as well? Figure out what, if any, partial you want in your controller, and pass it to the view on your view model.

Call js from MVC Controller

I have a web site written using ASP.NET MVC3.
The site has one single web page and what I want to do is to have the controller handle the request, do some parsing and processing and thereafter trigger a certain javascript method in the single webpage based on part of the data from the request.
How would I do this in the MVC controller?
You can't directly trigger actions in the View from the controller.
However, what you can do is return an ActionResult from the Controller Action to the View that instructs the View to execute your Javascript.
This could be a PartialView that includes the Javascript (in which case, you'll need a placeholder in your view for the PartialView to be rendered 'into') or something like a JSONResult that contains a property instructing the logic within the View what to do.
Either way, the call to the Controller Action is going to be triggered by client-side Javascript and your desired logic executed when the Controller Action finishes executing.
You'll probably find it easier to use jQuery.

Can a controller influence the _layout.cshtml file?

I'm stuck! I'm under the impression that the _layout.cshtml file is used for MasterPage-like content. Everything there is rendered on every page. Naturally, I want to write the code for rendering my sidebar menu in that file.
I want to dynamically display a list of Categories from my DB, but I'm having a problem with passing the actual model of categories to Layout.cshtml since it seems no controller actually touches it.
Any suggestions?
Otherwise please tell me how to approach this problem. I've been wracking my brain for the past three days and still no elegant solution.
I need to:
Dynamically fetch a list of Categories from the DB.
Display this list of Categories on every single view. (Hence the use of _layout.cshtml)
Elegantly handle each different categories click.
I'm at my wits end. :P How would you solve this?
_layout.cshtml
#if(isSectionDefined("Categories"))
{
<div id="sidebar">
#RenderSection("Categories", required: false )
</div>
}
index.cshtml
#section Categories {
<ul>
<li>Category One</li>
<li>Category Two</li>
<li>Category Three</li>
</ul>
}
see this : http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx
Any viewmodel that you pass to your view is automatically available within your master page. If you do not use RenderAction/Action which is the best approach, then you must create the necessary master page data in every action and add it to viewdata - either by having a common base class for your strongly typed viewmodel that contains all master page data or by using the viewdata dictionary.
I would strongly recommend that you go down the html.action approach though. In this way, you have a totally separate controller action for dealing with your list of categories. This action can retrieve the neccesary category data and return the categorylist usercontrol as a partialview and you will not have to worry about polluting all your other actions with this data.
As I see it, ViewData (and its relatives like ViewBag, Model, etc.) is meant for the specific current view. Your _Layout.cshtml is not specific to the current view; and it would be awkward if EVERY controller would have to pass the categories data in addition to whatever else data it needs to pass for the view.
Instead, what I do, is provide a static method in one of my helper classes that retrieves the categories from the DB. I also do some caching there, so that I do not have to hit the DB on every single request. The _Layout.cshtml then simply calls this static method. Simple and elegant.
If you wish, you can bring this out to a partial view, make it a helper method, whatever.
One note of caution though - my custom error view also uses the same _Layout.cshtml, and if the DB goes down, you get an exception trying to display the exception. ASP.NET MVC is smart enough to detect this and abort processing, but you're left with a nondescript default error page. What I did was to place try...catch statements around these dangerous calls, which quietly ignore the exception if the current page is the error view.
I've achieved something similar by having my ViewModels implement an Interface which has members that contain the menu data. In my action method I set that data. Then in my view I check to see if my view-model implements that inteface, pull the menu data out and render the menu (in a partial view actually)

Resources