I'm newby to MVC and I want to have different body class for each view.
My header is a partial view and #RenderSection does not work for it.
_Layout.cshtml:
#{
Html.RenderAction("GetHeader", "Main");
}
#RenderBody()
#{
Html.RenderAction("GetFooter", "Main");
}
_HeaderLayout.cshtml:
//...
<body class=" here must be specified class different for each view">
//...
MainController:
public class MainController : Controller
{
public ActionResult GetHeader()
{
return PartialView("~/Views/Shared/_HeaderLayout.cshtml");
}
public ActionResult GetFooter()
{
return PartialView("~/Views/Shared/_FooterLayout.cshtml");
}
}
Any idea please?
I would do it in two ways:
Create a base ViewModel class for all the view models used in your app and add a property for the BodyClass, then implement it in the Partial View.
Add a property in the ViewBag dictionary before returning the partial view.
Examples:
1. Base class
public class BaseViewModel
{
public string BodyClass {get; set;}
}
Usage:
Base Class:
in partial view:
#model BaseViewModel
///...
<body class="#Model.BodyClass">
in controller:
public ActionResult GetHeader()
{
var vm = new BaseViewModel { BodyClass= "test-class" };
return PartialView("~/Views/Shared/_HeaderLayout.cshtml", vm);
}
In ViewBag:
public ActionResult GetHeader()
{
ViewBag[SomeConstantStringValue] = "test-class";
return PartialView("~/Views/Shared/_HeaderLayout.cshtml");
}
in partial view:
<body class="#ViewBag[SomeConstantStringValue]">
Remember that you always have to specify that ViewBag value, otherwise you'll get an error.
Mihail Stancescu answer is probably best, but if you don't want a view model for each controller method, you could make use of a helper function instead. Either way though, your're going to probably have to make your own method that decides which class to return (see BodyClassForTabAndMethod() below).
Create a Helper class (if you don't have a suitable one already):
public static class Helper
{
public static string BodyClassForTabAndMethod()
{
string[] selectedTabAndMethod = GetSelectedTabAndMethod();
string bodyClass = "";
// Change the below switch statements based upon the controller/method name.
switch (selectedTabAndMethod[0])
{
case "home":
switch (selectedTabAndMethod[1])
{
case "index":
return "IndexClass";
case "about":
return "AboutClass";
case "contact":
return "ContactClass";
}
break;
case "account":
switch (selectedTabAndMethod[1])
{
case "login":
return "LoginClass";
case "verifycode":
return "VerifyCodeClass";
}
break;
}
return bodyClass;
}
public static string[] GetSelectedTabAndMethod()
{
string[] selectedTabAndMethod = new string[2]; // Create array and set default values.
selectedTabAndMethod[0] = "home";
selectedTabAndMethod[1] = "index";
if (HttpContext.Current.Request.Url.LocalPath.Length > 1)
{
// Get the selected tab and method (without the query string).
string tabAndMethod = HttpContext.Current.Request.Url.LocalPath.ToLower();
// Remove the leading/trailing "/" if found.
tabAndMethod = ((tabAndMethod.Substring(0, 1) == "/") ? tabAndMethod.Substring(1) : tabAndMethod);
tabAndMethod = ((Right(tabAndMethod, 1) == "/") ? tabAndMethod.Substring(0, tabAndMethod.Length - 1) : tabAndMethod);
// Convert into an array.
if (tabAndMethod.Count(s => s == '/') == 1)
{
string[] split = tabAndMethod.Split('/');
selectedTabAndMethod[0] = split[0];
selectedTabAndMethod[1] = split[1];
}
}
return selectedTabAndMethod;
}
public static string Right(string value, int length)
{
if (string.IsNullOrEmpty(value)) return string.Empty;
return ((value.Length <= length) ? value : value.Substring(value.Length - length));
}
}
And then in your view:
<body class="#Helper.BodyClassForTabAndMethod()">
I reached to a solution for my own question, very simply:
In Global.asax: //or any other class which loading at start
public static class WrrcGlobalVariables
{
//any other global variables...
public static string BodyClass { get; set; }
}
In any Controller and before returning view/partial view:
public ActionResult Index()
{
//some codes...
WrrcGlobalVariables.BodyClass = "HomePage";
return View();
}
and in _HeaderLayout.cshtml:
<body class="#WrrcGlobalVariables.BodyClass">
Both the approaches given by Mihail Stancescu are correct, however there is one more way to have a default value for it and custom value only when required. Also you should use RenderPartial as well for your case instead of RenderAction if all you're doing is rendering the partial without any extra logic which requires a child controller.
In _Layout.cshtml
#Html.Partial("_HeaderLayout")
#RenderBody()
#Html.Partial("_FooterLayout")
In _HeaderLayout.cshtml
<body class="#ViewBag[SomeConstantStringValue]">
In _ViewStart.cshtml
#{
ViewBag[SomeConstantStringValue] = ViewBag[SomeConstantStringValue] ?? "default-class";
}
Then anywhere in any view or controller set this ViewBag value, this way you'll ensure a guaranteed default value to prevent null reference exceptions
Related
MVC newbie question:
I'm picking up a URL of the form go/{mainnav}/{subnav}, which I've successfully routed to the GoController class, method:
public ActionResult Index(string mainnav, string subnav) {
return View();
}
So far, so good. But now I want the view to return different HTML, depending on the values of mainnav or subnav. Specifically, inside a javascript block, I want to include the line:
myobj.mainnav = [value of mainnav parameter];
and, only if subnav is not null or empty:
myobj.subnav = [value of subnav parameter];
How do you pass those parameters to an aspx page that doesn't have a codebehind?
You use a ViewModel class to transfer the data:
public class IndexViewModel
{
public string MainNav { get; set; }
public string SubNav { get; set; }
public IndexViewModel(string mainnav, string subnav)
{
this.MainNav = mainnav;
this.SubNav = subnav;
}
}
Your action method then comes out
public ActionResult Index(string mainnav, string subnav)
{
return View(new IndexViewModel(mainnav, subnav));
}
This means your view has to be strongly typed:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<YourNameSpace.IndexViewModel>" %>
In your view, you output the data like so:
myobj.mainnav = <%: Model.MainNav %>;
An alternative solution if you use MVC3, would be to use the dynamic ViewBag:
public ActionResult Index(string mainnav, string subnav)
{
ViewBag.MainNav = mainnav;
ViewBag.SubNav = subnav;
return View();
}
which would be accessed in the page as so:
myobj.mainnav = <%: ViewBag.MainNav %>;
However, I would recommend that you read up on unobtrusive javascript and see if you can improve your design to avoid this specific problem.
If you are using MVC3 I would suggest passing the values into the ViewBag.
ViewBag.MainNav = "xxxx";
ViewBag.SubNav = null;
then on your view page, where you define the JavaScript and add the value.
if you dont have MVC 3 if you use ViewData["MainNav"]), to store your value has the same effect.
Did you try accessing parameters from Request in your view?
i.e.
Request.Params["mainnav"]
or
Request.Params["subnav"]
Works in MVC
i'm using following approach:
ViewModel.class:
public class TitleBodyModel
{
public string Title { get; set; }
public string Body { get; set; }
public TitleBodyModel() { Title = Body = ""; }
public TitleBodyModel(string t, string b) { this.Title = t; this.Body = b; }
}
In the main View:
#Html.Partial("_TitleBody" , new XXX.Models.TitleBodyModel("title", "body" ))
Then in a partial view:
#model XXX.Models.TitleBodyModel
<div class="bl_item">
<div class="bl_title">#Model.Title</div>
<div class="bl_body">#Model.Body</div>
</div>
If i understand this can be a solution:
public ActionResult Index(string mainnav, string subnav)
{
return View(mainnav | subnav);
}
In the Html View you can use View
and after
<%=Model %>
I have a non-static class Institute, i cannot use static property DisplayPicturePath if the object is not passed into this view. However if i use Static class with static method then that is available in view. some suggestions if my approach is wrong?
[HttpGet]
public ActionResult Create() {
//if do not pass institute into view
//Institute institute = new Institute();
return View();
}
My razor view has this
<div class="ui segment">
<img id="DisplayPicture_img" alt="Institute Picture" class="ui fluid image" src="#Url.Content(Path.Combine(Institute.DisplayPicturePath ,"univeristy.jpg"))" />
</div>
and my class is this
public class Institute
{
public Institute()
{
DisplayPicture = "institute.png";
Scholarships = new List<Scholarship>();
ModifiedDate = DateTime.Now;
EntryDate = DateTime.Now;
}
[NotMapped]
public static string DisplayPicturePath
{
get
{
return #"\\"+ Path.Combine("Content", "images", "DisplayPictures");
}
}
[Key]
[DisplayName("Institute Id")]
public int InstituteId { get; set; }
[DisplayName("Institute Name")]
public string Name { get; set; }}
}
how ever i am using another static class to use this way
<div class="ui segment">
<img id="DisplayPicture_img" alt="intitute Picture" class="ui fluid image" src="#Url.Content(Path.Combine(UtilityMethods.GetDisplayPicturePath(PictureType.Institute),"univeristy.jpg"))" />
</div>
my static class is
public static class UtilityMethods
{
public static string GetDisplayPicturePath(PictureType type)
{
if (type.Equals(PictureType.Institute))
{
return #"\\" + Path.Combine("Content", "images", "DisplayPictures", "Institute");
}
else if(type.Equals(PictureType.User))
{
return #"\\" + Path.Combine("Content", "images", "DisplayPictures", "User");
}
else if (type.Equals(PictureType.Scholarship))
{
return #"\\" + Path.Combine("Content", "images", "DisplayPictures", "Scholarship");
}
else
{
return #"\\" + Path.Combine("Content", "images");
}
}
}
It was a Build Issue or Chrome browser cache clearance issue, Since Static property was available in my Controller but for some reason not available in view AT THE SAME TIME.
Just after a dinner break and good sleep. i rechecked it by creating tons of test scenarios and come to the point that original method was working after all.
Static properties are definitely available in view.
weather they are in Method form, Const string form or called from Non-Static class.
You can not access the property in view if it is not static unless you pass that in model
`[HttpGet]
public ActionResult Create() {
//if do not pass institute into view
Institute institute = new Institute();
institute.DisplayPicturePath=//Whatever value you wanna set here;
return View(institute);
}`
View:#model Institute
src="#Url.Content(Model.DisplayPicturePath)" />
I have this code :
0#Model.Work.Phone
When I use phone like 0#Model.Work.Phone, the # sign is not highlighted. And this looks like this in browser : 0#Model.Work.Phone . I mean the code is displayed instead of the phone number.
When I put a space like this :
0 #Model.Work.Phone
The # sign is higlighted but I want 0 and # to be next to each other. How can I achieve this? Thanks.
On Razor (at least on 2.0 or up) you can use an explicit expression:
0#(Model.Work.Phone)
As an alternative you can use the direct string.format call as offered by Gypsy Spellweaver
Another alternative is using an Razor delegate:
#{
Func<dynamic, object> phoneformat = (item) =>
{
// if we have a string
if (item is String && !String.IsNullOrEmpty(item))
{
// check if the first is not a 0
if (item[0] != '0')
{
// add it
item = String.Format("0{0}", item);
}
}
else if(item is Int32)
{
/// ints never have leading 0, so add it
item = String.Format("0{0}", item);
}
return item;
};
}
0#(Model.Work.Phone) <br/>
0#(Model.Work.PhoneInt)
#phoneformat(Model.Work.Phone) <br/>
#phoneformat(Model.Work.PhoneInt)
Here is the Model I used:
public class Work
{
public string Phone { get; set; }
public int PhoneInt { get; set; }
}
And the Controller that fills it:
public ActionResult Index()
{
var model = new MyModel();
model.Work = new Work {Phone = "612345678", PhoneInt = 612345678};
return View(model);
}
The rendered html content looks like this:
0612345678 <br/>
0612345678
0612345678 <br/>
0612345678
I'm trying to pass an array from my controller to my view using my Model. My method does not work for some reason. I've posted it below.
Controller:
public ActionResult Confirmation()
{
string[] Array = new string[2] {"Pending", "07/07/2013"};
ConfirmationModel Con = new ConfirmationModel
{
Status = Array[0],
AppDate = Array[1],
};
return View();
}
Model:
public class ConfirmationModel
{
public string Status { get; set; }
public string AppDate { get; set; }
}
View:
#model site.ConfirmationModel
#{
ViewBag.Title = "Confirmation";
}
#Html.DisplayFor(Mode => Model.Status)
#Html.DisplayFor(Mode => Model.AppDate)
You aren't passing your model to your view. Change the line below:
return View();
To this;
return View(Con);
You haven't actually included the model in the result. Do this:
return View(Con);
You should return populated model to your view. In your case:
return view(con)
Then use con in your view.
You're not passing any model to the view to be rendered.
The View() method has an overload to receive an object model to render in the view.
Try this: return View(Con);
The goal
Treat an offer as a category in controller.
The problem
I have a controller whose name is ProductsController. Inside it, I have an action called Category. When this method is requested, it responds with a view of products list that corresponds to the category passed as parameter. Follow the code:
[HttpGet]
public ActionResult Category(string categoryName = null)
{
if (Regex.Match(categoryName, #"\d+").Success)
{
int categoryId = Convert.ToInt32(Regex.Match(categoryName, #"\d+").Value);
string sluggedCategoryName = CommodityHelpers.UppercaseFirst(CommodityHelpers.GenerateSlug(Categories.GetDetails((sbyte)categoryId).Category_Name));
if (String.Format("{0}-{1}", categoryId, sluggedCategoryName) == categoryName)
{
ViewBag.Title = Categories.GetDetails((sbyte)categoryId).Category_Name;
ViewBag.CategoryProductsQuantity = Categories.GetDetails((sbyte)categoryId).Category_Products_Quantity;
ViewBag.CurrentCategory = sluggedCategoryName;
return View(Products.BuildListForHome(categoryId, null));
}
else
{
return View("404");
}
}
else
{
return View("404");
}
}
But I want to return other a specific view when "Offers" is passed as parameter.
How can I do this?
if (categoryName == "Offers")
return View("SomeView", Products.BuildListForHome(categoryId, null));
You can specify what view to return as a parameter like so:
return View("Offers", data);
Put an "if" "then" in the beginning of the method checking for Offers, and return your offers View if the conditions meet.