MVC Layout with Menu - asp.net-mvc

I'm new to MVC and I'm trying to make use of the Layout Page So far I have the following layout page:
...
<div class="container-full body-content">
<h2>#ViewBag.Title</h2>
<div class="row">
#if (Request.IsAuthenticated)
{
<div class="col-sm-3">
#{Html.RenderAction("MenuPartial", "Layout");}
</div>
<div class="col-sm-9" style="background-color:aqua">
#RenderBody()
</div>
}
else
{
#RenderBody()
}
</div>
...
Is there a way to get MVC to just re-render the render body rather than doing a full post back and re-loading the navigation menu each time a page changes?

First, MVC doesn't do "postbacks". If you click a link, that's just a GET request. If you actually submit a form, it will send the request as a POST, but the destination could be an entirely different view or the same.
Second, taking an action like clicking a link or submitting a form within a web browser by default sends a request to the server and then entirely replaces the user's rendered view with a the response from the server. That necessitates the the server send back a full HTML document, including any associated layout.
If you want to replace just a portion of the HTML page without changing the user's view, that requires using AJAX. You send an AJAX request to request an action that will return a partial view. In other words, it will not utilize the layout you've defined for the web application. You, then, are responsible for replacing the appropriate portion of the DOM client-side with the server's response. There's a plethora of client-side JavaScript libraries that can help you manage this type of workflow, but they're all frameworks in their own right. In other words, they handle routing, models, views, etc. These are what's referred to as SPAs, or Single Page Applications. When you create a SPA, the server is relegated to a pure support role, only providing endpoints allowing you to retrieve or update data. Web Api is a popular choice here exactly for that reason; as all the MVC machinery is unnecessary.
If you're just looking to optimize things by say not having to render the child action that returns the menu, you can employ OutputCache on the child action so that for a period of time, the action will not need to run again, and the HTML output it generated can just be dumped directly into the appropriate place in the layout.

Related

How to accomplish this MVC layout

Being relatively new to MVC I have been struggling for the past several weeks getting my layout to work.
I have managed to get myself really twisted into knots. So instead of trying to explain and unravel my mess perhaps instead someone could explain how I would accomplish the following at a high level.
_Layout this would have all the css js etc. It would also have basic structure.
Of course HTML tags not allowed in code block....each render is in a div.
#RenderPartial(Header)</div>
#RenderBody()</div>
#RenderPartial(Footer)</div>
RenderBody is Index.cshtml and it would be broken into three pieces
#
#Html.Partial(NavMenu, model)</div>
#Html.Partial(SubNavMenu, model)</div>
#Html.Partial(MainContent, model)</div>
I have this basic layout and it looks fine until you click one of the menu items.
The menu items render as:
<a class="k-link" href="/stuffroute">Stuff</a>
That route goes to a controller that returns a view and that navigates away from the above arrangement in Index.cshtml. So I end up with the header, footer, and subdash nav....
So the question is...
How do I route / orchestrate my layout to not lose the differing pieces?
Partials don't do anything for you here. You're essentially asking about how to create SPA (single page application), although in this case your application will have other pages, it's just that the index view will act like a SPA.
That requires JavaScript, specifically AJAX, to make requests to endpoints that will return HTML fragments you can use to replace portions of the DOM with. For example, clicking "Stuff 1" causes an AJAX request to be made to the URL that routes to FooController.GetSubNav([stuff identifier]). That action then would use what was passed to it to retrieve the correct sub-nav and return a partial view that renders that sub-nav. Your AJAX callback will then take this response, select a portion of the DOM (specifically the parent of the sub-nav) and insert the new HTML as its innerHTML.
If you're going to be doing a lot of this, you'll want to make use of some client-side MVC-style JavaScript library, like Angular for example. These make it trivial to wire everything up.

Direct BeginUmbracoForm action to another page

I am trying to set up a global search box that posts to a search page in umbraco 7. This template uses a shared partial containing Html.BeginUmbracoForm() that points to a SurfaceController.
Since this is a global control, I want the form to be posted to the /search page instead of the current page. BeginUmbracoForm only seems to be able to post to the current page unless I'm mistaken.
I want something like RedirectToUmbracoPage(id), but clears this post values on redirect.
Is there a way to get an ActionResult like CurrentUmbracoPage which keeps the post values?
I would not try using surfacecontrollers for that purpose. Surfacecontrollers are auto routed. They are created to (e.g.) make #Html.Action(...) work on every umbraco page. Including postbacks on these actions or macros.
If you only need a "redirect" to the /search page, you don't need a surface controller. A simple partial will do the job.
<form action="/search" method="get">
Search <input type="search" name="q" />
</form>
Of course you can replace the url using some Umbraco logic like #Umbraco.TypedContentSingleAtXPath("//Search") or other Umbraco magic.
In the umbraco documentation project is an example where Html.Action is used.

Understanding MVC tags for nopCommerce

I am new to MVC , and in the application i downloaded and trying to debug i see this mark up
#Html.Widget("body_start_html_tag_after")
#Html.Partial("_Notifications")
#Html.Action("AdminHeaderLinks", "Common")
What does this mean?, #Html.Partial where can I find where the value "body_start_html_tag_after") is defined ?
And this one:
<div class="master-wrapper-main">
#RenderBody()
</div>
Where can i find what #RenderBody does?, this is in a .cshtml file.
I would suggest that you look at a reference like http://www.asp.net/mvc to gain a greater understanding of ASP.Net MVC. Having said that the #HTML.Widget, etc is server side code that gets called during the HTML generation process.
I have heard of nopCommerce but I am unfamiliar with the structure, but #Html is usually used for server side helper methods.
#Html.Partial("_Notifications") is used to add the _Notifications Partial view to the page being rendered.
#Html.Action method will render a html A tag with the href link to the controller and action to be performed.
#Html.Widget I am unfamiliar with but one could assume that it is a helper method.
#RenderBody is used on a master page (usually the shared/_Layout.cshtml) as a server side marker to render the view that comes from the associated controller.

How to hide a content placeholder if it has no children without client code (MVC)

I have a ContentPlaceholder inside of a MasterPageView. All of my other pages come from the same master and I have one page that needs about 70% of the behavior in this master. There is a navigation panel in the master that is spitting out un-necessary html even if left blank by the page. Looks like this:
<div class="span3">
<div class="side_navigation">
<ul>
<asp:ContentPlaceHolder ID="SideNavigation" runat="server" />
</ul>
</div>
</div><%-- /master sub-navigation --%>
I simply want to hide ALL of this markup whenever my placeholder (SideNavigation) has 0 children. I don't want to use javascript. I'd rather do this work on the server and deliver it to the client with less responsibility and markup. I've already tried doing "this.SideNavigation.Controls.Count" but it always ends up being 0. If there was a way I could tie into a loaded event and then test this logic that would be great. I am ok with making a code-behind file for my master, but it would be nice to be able to accomplish my goal in the .master file only.
Let me know what you think.
I would probably recommend using a different master page for the page without the navigation. You can have nested master pages so you don't necessarily need to duplicate code to do this.
However if you do wish to keep it like this, I would personally use a bit of javascript (with jquery) as follows
$(function(){
if($('.span3 .side_navigation ul li').length() == 0){
$('.span3').hide();
}
});
obviously i'd give span3 an ID to make it not hide every span3 but you hopefully get the idea.

How to post only a specific ASCX partial instead of the whole page

I've got an ASPX page rendering a search ascx page which in turn will fill a grid on the main ASPX page.
Aside that, I've also got an ascx page which uploads files, like this:
<form method="post" action="<%= Url.Action("UploadFile") %>" enctype="multipart/form-data">
<fieldset>
<input type="file" name="file" id="file" />
<%=Html.ButtonSubmit("Upload") %>
</fieldset></form>
Here's the problem: imagine I have searched for a single entry to be displayed on the grid. The grid displays this single entry and after wards, I upload a file and press the button "Upload". The whole page gets posted and the content in the grid is lost, now displaying all the results available.
What could I do to prevent this from happening, maintaining the grid state (we're not using ViewState) or otherwise not posting back the whole page but only the ascx with the file upload?
Note: I'm new to MVC.
Your partial view is rendered inside your HTML... this results in a single "static" HTML-file without the option to submit and reload only parts of it.
I can imagine two ways to solve your problem:
1) Place your upload-formular inside an HTML-iFrame... now only this iFrame will reload on submit. Problem: Communication between parent and child-frame to have the uploaded data available, depending on what kind of action you would like to have after uploading.
2) Use jQuery/AJAX to make a javascript-based submit (http://api.jquery.com/jQuery.post/) and refresh your page content dynamically with jQuery/JavaScript. This would be my prefered way but needs some more knowledge about jQuery/JavaScript.
BTW: jQuery is nearly a must-have for any asp.net mvc application ;-)
Welcome to MVC :-)

Resources