ASP.NET MVC 3: Append to sections - asp.net-mvc-3

I'm trying to figure out if it is possible to append to a section. Here is my structure:
_Layout.cshtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<link href="#Url.Content("~/Content/style.css")" rel="stylesheet" type="text/css" />
#RenderSection("Css", false)
<script type="text/javascript" src="#Url.Content("~/Content/scripts/head.load.min.js")"></script>
</head>
<body class="bg_g">
#RenderBody()
<script type="text/javascript">
#RenderSection("Javascript", false)
</script>
</body>
</html>
Logon.cshtml
#{
Layout = "~/Views/Shared/_DMZ.cshtml";
ViewBag.Title = "Logon";
}
#section Javascript += {
// JAVASCRIPT CODE;
}
<div>
Stuff
#{ Html.RenderAction("Register", "Account"); }
#{ Html.RenderAction("Register2", "Account"); }
</div>
Register.cshtml
#{
Layout = null;
}
#section Javascript += {
// More javascript code
}
<div>
Register stuff
</div>
Register2.cshtml
#{
Layout = null;
}
#section Javascript += {
// Even More javascript code
}
<div>
Register stuff part 2
</div>
Hopefully that explains what I'm really trying to do. I would also like to do the same thing with my css section. It would be even better if I could also get it to render the Javascript like this:
head.js(
"#Url.Content("~/Content/scripts/jquery-1.6.2.min.js")",
"#Url.Content("~/Content/scripts/jquery.tools.min.js")",
"#Url.Content("~/Content/lib/jquery-validation/jquery.validate.js")",
// Loop through all javascript files included from the sub views and add them just like above
function () {
loginTabs.init();
// Loop through all javascript functions that have been added to the InitFunctions section?
}
)
Maybe sections aren't the correct solution to this problem, but I know that there has to be a way to accomplish something like this. Any Ideas?

A bit of a late entry - but hopefully still useful to someone out there:
I don't know if there is a native method to achieve it but i have been using this for some time now and it's really helpful:
public static IHtmlString Resource( this HtmlHelper HtmlHelper, Func<object, HelperResult> Template, string Type )
{
if( HtmlHelper.ViewContext.HttpContext.Items[Type] != null ) ( (List<Func<object, HelperResult>>)HtmlHelper.ViewContext.HttpContext.Items[Type] ).Add( Template );
else HtmlHelper.ViewContext.HttpContext.Items[Type] = new List<Func<object, HelperResult>> { Template };
return new HtmlString( String.Empty );
}
public static IHtmlString RenderResources( this HtmlHelper HtmlHelper, string Type )
{
if( HtmlHelper.ViewContext.HttpContext.Items[Type] == null ) return new HtmlString( String.Empty );
var Resources = (List<Func<object, HelperResult>>)HtmlHelper.ViewContext.HttpContext.Items[Type];
foreach( var Resource in Resources.Where( Resource => Resource != null ) )
{
HtmlHelper.ViewContext.Writer.Write( Resource( null ) );
}
return new HtmlString( String.Empty );
}
The usage is:
//This is how you save it
#Html.Resource(#<style>.test{color: #4e4e4e}</style>, "css")
//This is how you read it
#Html.RenderResources("css")

Related

Append HTML code to a existing Razor section

Is it possible to append the HTML code to a existing razor section?
Below is my scenario:
My _layout.cshtml contains something like this:
#RenderSection("BottomSection", required: false)
and in one of the view - _article.cshtml, I have defined the section like below:
#section BottomSection
{
<script src='~/Scripts/module/article_details.js' type='text/javascript'></script>
<script src='~/Scripts/module/modal.js' type='text/javascript'></script>
#MvcHtmlString.Create(Model.ExtraStuff)
}
and in a partial view named _counter.cshtml, which is used by the above view; I would like to add more HTML code to the same section i.e., BottomSection.
I tried declaring the BottomSection section again in the partial view:
#section BottomSection{
<text>More data</text>
}
But it didn't worked out.
Is there any way to achieve this - dynamically append more code to an already defined razor section in MVC 4?
Please note that the partial view doesn't expects any data from the parent view/model.
And I'm using MVC 4 with .Net Framework 4.0/VS2010.
I don't know how to append stuff to sections (in fact I would like to know that myself), but I know a trick that might produce similar result. Instead of using sections one can use TempData. TempData is a lot like ViewBag, but once a variable is set it'll live there for current user until one tries to access it again (it can live through a few successive requests for current user, so extra caution is advised). Below is an example of how it could be used.
In layout:
#Html.Raw(new MvcHtmlString((string)TempData["BottomSection"]));
In the view:
#{
var bottomSection = (string)TempData["BottomSection"];
if (bottomSection == null)
{
bottomSection = "";
}
bottomSection += "<script src='~/Scripts/module/article_details.js' type='text/javascript'></script>\n";
bottomSection += "<script src='~/Scripts/module/modal.js' type='text/javascript'></script>\n";
bottomSection += Model.ExtraStuff + "\n";
TempData["BottomSection"] = bottomSection;
}
In the partial view:
#{
var bottomSection = (string)TempData["BottomSection"];
if (bottomSection == null)
{
bottomSection = "";
}
bottomSection += "More data";
TempData["BottomSection"] = bottomSection;
}
This can be further improved by writing a helper for those pseudo sections and\or by moving the contents of the sections a separate partials (look below).
bottomSection += Html.Partial("_StuffToAddToSection").ToString();
Helper class:
public static class PseudoSectionsHelper
{
public static MvcHtmlString AppendToPseudoSection<T>(this TempDataDictionary TempData, string sectionName, T model, Func<T, HelperResult> content, bool addNewLineCharacter = true)
where T : class
{
return AppendToPseudoSection(TempData, sectionName, content(model).ToString(), addNewLineCharacter);
}
public static MvcHtmlString AppendToPseudoSection(this TempDataDictionary TempData, string sectionName, MvcHtmlString content, bool addNewLineCharacter = true)
{
return AppendToPseudoSection(TempData, sectionName, content.ToString(), addNewLineCharacter);
}
public static MvcHtmlString AppendToPseudoSection(this TempDataDictionary TempData, string sectionName, string content, bool addNewLineCharacter = true)
{
var section = (string)TempData[sectionName];
if (section == null)
{
section = "";
}
else if (addNewLineCharacter)
{
section += "\n";
}
section += content;
TempData[sectionName] = section;
// We return empty MvcHtmlString to be able to use this helper inline (without declaring code block #{ some code... } in view)
return new MvcHtmlString("");
}
public static MvcHtmlString PseudoSection(this TempDataDictionary TempData, string sectionName)
{
var section = (string)TempData[sectionName];
return new MvcHtmlString(section);
}
}
Use example
In layout add:
#TempData.PseudoSection("BottomSection")
In view:
#TempData.AppendToPseudoSection("BottomSection", Model, #<text>
<script src='~/Scripts/module/article_details.js' type='text/javascript'></script>
<script src='~/Scripts/module/modal.js' type='text/javascript'></script>
#MvcHtmlString.Create(Model.ExtraStuff)
</text>)
or
#{
TempData.AppendToPseudoSection("BottomSection", Model, #<text>
<script src='~/Scripts/module/article_details.js' type='text/javascript'></script>
<script src='~/Scripts/module/modal.js' type='text/javascript'></script>
#MvcHtmlString.Create(Model.ExtraStuff)
</text>);
}
or even
#TempData.AppendToPseudoSection("BottomSection", Html.Partial("BottomSectionScriptsAndStuff"))
And in partial:
#TempData.AppendToPseudoSection("BottomSection", "More data")
Maybe i dont understand your question but why you dont using nested partial views???
for example :
PartialView1
`<script src='~/Scripts/module/article_details.js' type='text/javascript'></script>
<script src='~/Scripts/module/modal.js' type='text/javascript'></script>
#MvcHtmlString.Create(Model.ExtraStuff)
#{Html.RenderPartial("PartialView2",Model.ExtraStuff );}`
PartialView2
`<text>More data</text>`
Using Ajax you can load the partial view and can render in your target division.
Try using jquery ajax
$.ajax({
type: 'GET',
url: '#Url.Action("Action","Controller")',
cache: false,
timeout: 20000,
contentType: "application/json; charset=utf-8",
success: function (_results) {
$("#TargetDiv").html(_results);
},
error: function (_results) {
}
});

mvc3 jquery mobile how to use Html.BeginForm

I have already written an entire site in MVC3. I am trying to build the mobile version with Jquery Mobile. I haven't changed my controller code, except to add a check for whether or not it should return a mobile page. I have the following in the document head of my mobile logon page:
<head>
<title>Mobile Logon</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
$(document).bind("mobileinit", function(){
$.extend( $.mobile , {
ajaxEnabled: false
});
});
<script src="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.js"></script>
</head>
I have a page with a header and content. In the content, I want to let the user redirect to the register form. the following seems to work:
<form action="Register" method="get" data-ajax="false">
<button type="submit" value="Register for an account"></button>
</form>
This does not work: (the url seems correct in the browser, but all that loads is a blank, white page)
#using(Html.BeginForm("Register", "Account", FormMethod.Get, null ))
{
<button type="submit" value="Register for an account"></button>
}
When I look in the page source, I notice two differences: The first one gives a form tag with
action="Register"
while the second gives a form tag with
action="Account/Register"
The other difference is the "data-ajax=false" in the form tag.
Questions:
Am I able to use #Html.BeginForm() with Jquery Mobile? If not, how do I redirect to a different controller?
How come my code in the head section doesn't turn off the default ajax behavior of Jquery Mobile? (I tried using the form tag above without data-ajax=false, and I got the same blank, white screen as the #Html.BeginForm gave me).
EDIT: here is my logon controller code (Account controller)
public ActionResult LogOn()
{
//return View();
return SelectView("Logon", null);
}
private ActionResult SelectView(string viewName, object model, string outputType = "html")
{
if (outputType.ToLower() == "json")
{
return Json(model, JsonRequestBehavior.AllowGet);
}
else
{
#if MOBILE
return View(viewName + ".Mobile", model);
#else
if (Request.Browser.IsMobileDevice)
{
return View(viewName + ".Mobile", model);
}
else
{
return View(viewName, model);
}
#endif
}
}
here is my Register controller code: (Account controller)
public ActionResult Register(string returnUrl = "")
{
//if no return url supplied, use referrer url.
//Protect against endless loop by checking for empty referrer.
if (String.IsNullOrEmpty(returnUrl) && Request.UrlReferrer != null && Request.UrlReferrer.ToString().Length > 0)
{
return RedirectToAction("Register", new { returnUrl = Request.UrlReferrer.ToString() });
}
return View();
}

MVC Partial view hides main view

I am new to MVC. using MVC 3.
I have PersonMaster Controller as below... having following two Actions.
public ActionResult TopTenPersons()
{
Thread.Sleep(2000);
var persons = DatabaseHelper.Instance.Database.Query<Person_Master>("select top(10) from person_master").ToList();
return View("_PersonGrid", persons);
}
public ActionResult Index()
{
var persons = DatabaseHelper.Instance.Database.Query<Person_Master>("select * from person_master").ToList();
return View("_PersonGrid",persons);
//return View();
}
Then, index.cshtml view is as follows..
#model System.Collections.Generic.ICollection<MyPracticeApp1.Models.Person_Master>
#section scripts{
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
}
<h2>Persons</h2>
<p>
#Ajax.ActionLink("Click to top 10 Persons","TopTenPersons", new AjaxOptions{
UpdateTargetId="tbl_person",
InsertionMode=InsertionMode.Replace,
HttpMethod="GET"
})
</p>
<div id="tbl_person">
#Html.Action("Index","PersonMaster");
</div>
..and partial view _PersonGrid.cshtml which is called above in index view is as follows...
#model System.Collections.Generic.ICollection<MyPracticeApp1.Models.Person_Master>
#{
var persongrid = new WebGrid(Model);
}
#persongrid.GetHtml()
....But problem is that it directly shows partial view. It is not rendering Ajax Actionlink of index view. So, where is the mistake?
Change TopTenPersons to return a Partial View, not a View
public ActionResult Index()
{
var persons = DatabaseHelper.Instance.Database.Query<Person_Master>("select * from person_master").ToList();
return PartialView("_PersonGrid",persons);
}
add layout=null to _PersonGrid.cshtml
seems like
#{
Layout = null;
}
when you add this code It is not rendering full view..

How to write a recursive function in a Razor View?

I have the following ViewModel:
public class AllQuestionsInCategoriesViewModel
{
public string Category_Name { get; set; }
public string Category_Number { get; set; }
public List<ShowQuestionViewModel> questions { get; set; }
public List<AllQuestionsInCategoriesViewModel> SubCategories { get; set; }
public AllQuestionsInCategoriesViewModel()
{
questions = new List<ShowQuestionViewModel>();
SubCategories = new List<AllQuestionsInCategoriesViewModel>();
}
}
I've been following this thread:
ASP.NET MVC 3 Razor recursive function
And i ended up with this code:
#model List<MvcApplication3.Models.ViewModels.Category.AllQuestionsInCategoriesViewModel>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>PrintSchema</title>
<link type="text/css" href="../../Content/Print.css" rel="Stylesheet" />
</head>
<body>
#{
foreach(var cq in Model) {
ShowSubItems(cq);
}
}
#helper ShowSubItems(MvcApplication3.Models.ViewModels.Category.AllQuestionsInCategoriesViewModel MyObj)
{
<h1>#MyObj.Category_Number #MyObj.Category_Name</h1>
foreach (var question in MyObj.questions)
{
#Html.DisplayFor(x => question, question.GetType().Name + "Print")
}
if (MyObj.SubCategories.Count != null || MyObj.SubCategories.Count != 0)
{
foreach(var subitem in MyObj.SubCategories)
{
ShowSubItems(subitem);
}
}
}
</body>
</html>
The problem is that the ShowSubItems method doesnt Display anything. The model is not empty, and the View can display
#Html.DisplayFor(x => x.question, question.GetType().Name + "Print")
just fine, outside of the ShowSubItems method. But nothing gets rendere to the View in the ShowSubItems method. Howcome?
I think it's because your call to ShowSubItems is inside a code block and not in a render block.
Try this:
#{
foreach(var cq in Model) {
#ShowSubItems(cq)
}
}
Try calling it like this:
#foreach(var cq in Model) {
#ShowSubItems(cq);
}
Also inside the helper:
#ShowSubItems(subitem);
put a '#' tag before the if statement. That will make everything inside it razor syntax unless you add a html tag anywhere inside it.

Ajaxified link in MVC3/JQuery not working in IE8 (missing header)

Consider the following code (it is based on a default EMPTY MVC3 project created in visual web developer express 2010sp1):
_Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
</head>
<body>
<div id="header">header</div>
<div id="main">#RenderBody()</div>
</body>
</html>
Index method of HomeController:
public ActionResult Index()
{
if (Request.IsAjaxRequest())
{
ViewBag.Message = "partial";
return PartialView();
}
else
{
ViewBag.Message = "full";
return View();
}
}
Index.cshtml:
<script type="text/javascript">
$(function () {
$('#myLink').click(function () {
$.post(this.href, function (result) {
$('#main').html(result);
alert(result);
});
return false;
//$('#main').load(this.href);
//return false;
});
});
</script>
HomeController index. #ViewBag.Message
#Html.ActionLink("Index", "Index", new { controller = "Home" }, new { id = "myLink" } );
The problem is that in IE8 when the myLink link is clicked, it doesn't update the main div with only the partial html from Index.cshtml but the complete html including the layout. Ofcourse it works fine in FF, I mean why shouldn't it right? It seems Request.IsAjaxRequest() always evaluates to false in IE8. I understand that it is a result of a header X-Requested-With not being attached to a request in IE8. I don't have a lot of experience with web development -- is this a common issue and what is the (best) way to solve this?
UPDATE:
Yesterday I got it working normally in IE8, but when I tried it again this morning, the same problem was back. Now I don't think it has anything to do with the settings in IE8 anymore as I restored the settings to the default values. I tried examining the request with the fiddler tool. In order for me to be able to capture the traffic from localhost with fiddler, I added a period to the address: http://localhost.:3157/. So now the error occurs only when I use http://localhost.:3157/ (with period) and it works normally when I use http://localhost:3157/ (without period). I additionally tested the behavior in Chrome, Opera and Safari -- the ajax link works normally in these browsers. Note that I can get it working normally in IE8 when I attach a query parameter to the ajax link like so:
#Html.ActionLink("Index", "Index", new { controller = "Home", param = "param" }, new { id = "myLink" } )
I don't really want to do this. I'm running low on ideas here. I'm probably missing something that is blatantly obvious to a seasoned web developer =] Anybody recognize these symptoms?
You probably want to use the .live() method instead of .click():
$('#myLink').live('click', function () {
...
return false;
});
because you are replacing the DOM in the AJAX callback (the #main) which contains the link so you are killing the event handler you have assigned.
Also you have a typo in the jquery script inclusion in the <head>. You are missing a closing > after type="text/javascript":
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
So here's a complete working example:
_Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
</head>
<body>
<div id="header">header</div>
<div id="main">#RenderBody()</div>
</body>
</html>
HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
if (Request.IsAjaxRequest())
{
ViewBag.Message = "partial";
return PartialView();
}
else
{
ViewBag.Message = "full";
return View();
}
}
}
Index.cshtml:
<script type="text/javascript">
$(function () {
$('#myLink').click(function () {
$.post(this.href, function (result) {
$('#main').html(result);
});
return false;
});
});
</script>
HomeController index. #ViewBag.Message
#Html.ActionLink("Index", "Index", new { controller = "Home" }, new { id = "myLink" } )
add
jQuery.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
});
to make sure the correct header is attached.

Resources