How to access model data in parent partial view - asp.net-mvc-3

I have one controller which will pass data to view Index.cshtml
public ActionResult Index()
{
var empId = #User.Identity.Name;
var empDetails = empRepository.GetEmployeeDetails(empId);
var emp = new UserViewModel {EmployeeDetail = empDetails};
return View(emp);
}
Layout of view Index.cshtml is Partialview _Layout.cshtml
#model HRM.Areas.EmployeeDetails.Models.UserViewModel
#{
ViewBag.Title = "Index";
Layout = "~/Areas/EmployeeDetails/Views/Shared/_Layout.cshtml";
}
<div>Hello</div>
I want to access the data which I passed from controller action to Index.cshtml in _Layout.cshtml.
Is there any way to do this ?

Your question is not clear on how you want to access the values so i'm making an assumption here:
If you want to include data from a view in a rendering from your layout page you can use the RenderSection method.
Layout Page:
#RenderSection("ViewSection", false)
View Page:
#section ViewSection {
<div>
<label>Emp Name:</label>
#model.EmpDetails.Name
</div>
}
When your Layout is rendered it'll look for a section in your view that matches and render it. Passing a false as the 2nd param tell the Layout that the section is not required.
For more info on this: http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx

Your question is not quite clear to me:/
My assumption ->
If you change your code to look like this:
public ActionResult Index()
{
var empId = #User.Identity.Name;
var empDetails = empRepository.GetEmployeeDetails(empId);
var emp = new UserViewModel { EmployeeDetail = empDetails };
ViewBag.UserViewModel = emp;
return View(emp);
}
on the Layout page you can access your data:
#if (ViewBag.UserViewModel != null)
{
//do sth with ViewBag.UserViewModel here
//for example:
#Html.Partial("_UserView",ViewBag.UserViewModel)
}
If you explain in details what you want to achive it will be easier for us to give you the right answer.

You can access the data in the model like this:
#Model.EmployeeDetail ...

Related

Render different partial views

I'm trying to render different partial views from the _Layout file depending on what function I'm in, controller-wise.
The partial view is in the right column of the website which is located in the _Layout like so:
<aside id="right">
#Html.Partial("RightPartial")
</aside>
What I want to do is render a different partial view depending on where I am.
If I'm in the Index view I might want to view news and in the About view I might want to view phone numbers or something.
Appreciate any help :)
#{
string currentAction = ViewContext.RouteData.GetRequiredString("action");
string currentController = ViewContext.RouteData.GetRequiredString("controller");
}
Now based on the values of those variables decide which partial to render. To avoid polluting the Layout I would write a custom HTML helper:
<aside id="right">
#Html.RightPartial()
</aside>
which might look like this:
public static class HtmlExtensions
{
public static IHtmlString RightPartial(this HtmlHelper html)
{
var routeData = html.ViewContext.RouteData;
string currentAction = routeData.GetRequiredString("action");
if (currentAction == "Index")
{
return html.Partial("IndexPartialView");
}
else if (currentAction == "About")
{
return html.Partial("AboutPartialView");
}
return html.Partial("SomeDefaultPartialView");
}
}

MVC3 Parent Child Views

I want to create a layout like the User page on Stack Overflow where there is a view (the parent view) at the top of the page and then content in tabs, each with it's own view (child views).
When I hover over each of the tabs on the User page in SO it looks like they are pointed at the user controller and are being sent the tab name in the query string to render the appropriate tab content.
I believe I can achieve this using a layout with a section defined in the parent view. The section would be the child view, but I don't know how I would tell the section which view or partial view to show.
I have not been able to find anything useful on the web. Can someone tell me how to do this or at least point me in the right direction?
Thanks in advance!
Edit: Thanks to #Mystere's help I was able to come up with the solution below in case anyone else is trying to do the same thing.
HTH
Final Solution:
Controller Actions
public ActionResult Details(int id, string tab = null)
{
ViewBag.Jobid = id;
ViewBag.Tab = tab ?? "Services";
var viewModel = getJobRecordDetails(id);
return View(viewModel);
}
public ActionResult JobInfo(int id, string tab)
{
ViewBag.Jobid = id;
ViewBag.Tab = tab;
if (tab == "Services")
{
var viewModel = getServices(id);
return View("Services", viewModel);
}
if (tab == "Equipment")
{
var viewModel = getEquipment(id);
return View("Equipment", viewModel);
}
if (tab == "Personnel")
{
var viewModel = getPersonnel(id);
return View("Personnel", viewModel);
}
return View("Error");
}
Parent View
#model MyApplication.Models.JobViewModel
#{
ViewBag.Title = "Details";
}
<h2>Job Details</h2>
...
#* Child View Action *#
#Html.Action("JobInfo", new { id = ViewBag.Jobid, tab = ViewBag.Tab })
Child View
#model MyApplication.Models.ServicesViewModel[]
#{
ViewBag.Title = "Services";
Layout = null;
}
#* Submenu Navigation *#
#{
Html.RenderPartial("SubMenu");
}
<h2>Services</h2>
Services here...
Subnavigation Partial View
<div id="submenucontainer">
<ul id="submenu">
<li class="#Html.ActiveTab("Job","JobInfo","Services")">Services </li>
<li class="#Html.ActiveTab("Job","JobInfo","Equipment")">Equipment</li>
<li class="#Html.ActiveTab("Job","JobInfo","Personnel")">Personnel</li>
</ul>
ActiveTab Helper
public static string ActiveTab(this HtmlHelper helper, string controller, string action, string tab)
{
var classValue = "";
var currentController =
helper.ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
var currentAction =
helper.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
var currentTab = helper.ViewContext.Controller.ValueProvider.GetValue("tab").RawValue.ToString();
if (currentController == controller && currentAction == action && currentTab == tab)
classValue = "selected";
return classValue;
}
It is unlikely they are using a section for that. sections are used primarily in layout pages (the equivelent of master pages).
More than likely, they just have multiple views, and they pass whichever view is appropriate to the View() method. They might use partial views, or MVC templates to render the tab areas, so that common code is factored out.
Edit:
As requested, code sample:
In action method:
public ActionResult Dashboard(string tab) {
if (tab == "summary")
ViewBag.Tab = "~/Views/Dashboard/Summary.cshtml";
if (tab == "activity")
ViewBag.Tab = "~/Views/Dashboard/Activity.cshtml";
return View()
}
in Dashboard.cshmtl
... your parent view
#Html.Partial(ViewBag.Tab)
... your footer
It's not rocket science. There are so many ways to do this it doesn't take much thought to come up with one of them.

How do I insert a partial view in a View at a certain place in the view with MVC3?

I have an MVC3 application that I am implementing pjax into . Everything is working well except what to do on the server side when an address gets loaded that doesn't already have the main view on the client side. My Controller code looks like
public virtual ActionResult Details(Guid id)
{
var partDetail = new PartDetail(id);
var partialView = PartialView("Details", partDetail);
if(Request.Headers["X-PJAX"]!= null)
{
return partialView;
}
var mainView = View("Index");
// Stick Partial View into main view at #update_panel?
return mainView;
}
How can I stick the partial View into the main view so it inserts the partial view in the #update_panel?
Ok, without a major refactor, you could do the following.
(this assumes that you are able to set the #model on index.cshtml to PartDetail()).
in your controller action above, change:
var mainView = View("Index");
to:
var mainView = View("Index", partDetail);
then, inside your index.cshtml, add the following:
<div id="update_panel">#RenderPartial("Details", Model)</div>
As i said, this will ONLY work if the index #model is set to PartDetail(), otherwise, a little refactoring on the model in the index view will be required to include this PartDetail() model. this viewmodel might well look like the following:
public class IndexViewModel
{
ModelForIndex Index{get; set;}
PartDetail Details{get; set;}
}
this refactored viewmodel would be added to the index.cshtml as #model IndexViewModel and consumed by the partial as:
<div id="update_panel">#RenderPartial("Details", Model.Details)</div>
hope this makes sense.

MVC3 Helper DisplayFor Model

I've got a view that displays a list of items. Rather than display items in a grid, I'd like to display 4 items per page, each with an image and multiple properties, displayed in a unique layout.
So, I'd like a foreach to iterate through the items, and each item to get displayed in a div. I could put all the code in the loop, but I'd like to have a custom html helper extension to do this.
I came up with this,
public static MvcHtmlString DisplayViewerFor(this HtmlHelper helper, TestModel model, bool rightAligned = true) {
if (model == null) {
model = new TestModel();
}
var outterDiv = new TagBuilder("div");
outterDiv.AddCssClass(rightAligned ? "item-display-right" : "item-display");
var image = new TagBuilder("image");
image.Attributes.Add("src", "Item/GetImage/" + model.ItemName);
image.Attributes.Add("height", "150");
var editorLabel = new TagBuilder("div");
editorLabel.AddCssClass("editor-label");
//LOOKING TO ADD CODE LIKE THIS HERE
var labelContent= html.LabelFor({my model property here})
editorLabel.InnerHtml += labelContent;
//END OF ADD
return new MvcHtmlString(outterDiv.ToString(TagRenderMode.EndTag));
}
In my method above, I need to display a few more values, and I would like to use the Html.LabelFor and Html.DisplayFor helpers, but the methods aren't available and I'm not sure what to pass to them if they were.
I'm not sure if this is possible or not, but I thought I would ask.
EDIT
I'm trying to use the html.LabelFor. See my code where I have updated it above, adding to it these two lines.
var labelContent= html.LabelFor({my model property here})
editorLabel.InnerHtml += labelContent;
You can see the code above.
EDIT 2
Here is the planned use for this Helper with dummied down view.
#model TestItemDisplayList
#{
ViewBag.Title = "Items";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#foreach(var item in #model.Items){
#Html.DisplayViewerFor(item)
}
You can use the Html.DisplayFor method to render a DisplayTemplate. One of the over loads for the method is to specify a template to use. You can modify your page code to read:
Page:
#model TestItemDisplayList
#{ ViewBag.Title = "Items"; Layout = "~/Views/Shared/_Layout.cshtml"; }
#Html.DisplayFor(model => Model,"TestItemDisplayList")
Display Template for TestItemDisplayList
#model TestItemDisplayList
#* You could limit this loop to the first 4 items *#
#foreach(var item in model.Items){ #Html.DisplayFor(item => item) }
Display Template for TestModel
#model TestModel
<div class="item-display">
<img src="#Url.Action("GetImage", "Image", new { id = Model.ItemName})" height="150"/>
<div class="editor-label">#Html.LabelFor(model => model.PropertyHere)</div>
</div>
I assume that your URL for the image used the default route of {controller}/{action}/{id} so I used the Url.Action and specified your ID.
You could also get away witout using a DisplayTemplate for "TestItemDisplayList" and moving that code in to your page but I wasn't clear if you wanted to add logic in that to limit the number of pages.

dropdownlist set selected value in MVC3 Razor

Here is my model:
public class NewsCategoriesModel {
public int NewsCategoriesID { get; set; }
public string NewsCategoriesName { get; set; }
}
My controller:
public ActionResult NewsEdit(int ID, dms_New dsn) {
dsn = (from a in dc.dms_News where a.NewsID == ID select a).FirstOrDefault();
var categories = (from b in dc.dms_NewsCategories select b).ToList();
var selectedValue = dsn.NewsCategoriesID;
SelectList ListCategories = new SelectList(categories, "NewsCategoriesID", "NewsCategoriesName",selectedValue);
// ViewBag.NewsCategoriesID = new SelectList(categories as IEnumerable<dms_NewsCategory>, "NewsCategoriesID", "NewsCategoriesName", dsn.NewsCategoriesID);
ViewBag.NewsCategoriesID = ListCategories;
return View(dsn);
}
And then my view:
#Html.DropDownList("NewsCategoriesID", (SelectList)ViewBag.NewsCategoriesID)
When i run, the DropDownList does not select the value I set.. It is always selecting the first option.
You should use view models and forget about ViewBag Think of it as if it didn't exist. You will see how easier things will become. So define a view model:
public class MyViewModel
{
public int SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
and then populate this view model from the controller:
public ActionResult NewsEdit(int ID, dms_New dsn)
{
var dsn = (from a in dc.dms_News where a.NewsID == ID select a).FirstOrDefault();
var categories = (from b in dc.dms_NewsCategories select b).ToList();
var model = new MyViewModel
{
SelectedCategoryId = dsn.NewsCategoriesID,
Categories = categories.Select(x => new SelectListItem
{
Value = x.NewsCategoriesID.ToString(),
Text = x.NewsCategoriesName
})
};
return View(model);
}
and finally in your view use the strongly typed DropDownListFor helper:
#model MyViewModel
#Html.DropDownListFor(
x => x.SelectedCategoryId,
Model.Categories
)
just in case someone comes with this question, this is how I do it, please forget about the repository object, I'm using the Repository Pattern, you can use your object context to retrieve the entities. And also don't pay attention to my entity names, my entity type Action has nothing to do with an MVC Action.
Controller:
ViewBag.ActionStatusId = new SelectList(repository.GetAll<ActionStatus>(), "ActionStatusId", "Name", myAction.ActionStatusId);
Pay attention that the last variable of the SelectList constructor is the selected value (object selectedValue)
Then this is my view to render it:
<div class="editor-label">
#Html.LabelFor(model => model.ActionStatusId, "ActionStatus")
</div>
<div class="editor-field">
#Html.DropDownList("ActionStatusId")
#Html.ValidationMessageFor(model => model.ActionStatusId)
</div>
I think it is pretty simple, I hope this helps! :)
I drilled down the formation of the drop down list instead of using #Html.DropDownList(). This is useful if you have to set the value of the dropdown list at runtime in razor instead of controller:
<select id="NewsCategoriesID" name="NewsCategoriesID">
#foreach (SelectListItem option in ViewBag.NewsCategoriesID)
{
<option value="#option.Value" #(option.Value == ViewBag.ValueToSet ? "selected='selected'" : "")>#option.Text</option>
}
</select>
Well its very simple in controller you have somthing like this:
-- Controller
ViewBag.Profile_Id = new SelectList(db.Profiles, "Id", "Name", model.Profile_Id);
--View (Option A)
#Html.DropDownList("Profile_Id")
--View (Option B) --> Send a null value to the list
#Html.DropDownList("Profile_Id", null, "-- Choose --", new { #class = "input-large" })
Replace below line with new updated working code:
#Html.DropDownList("NewsCategoriesID", (SelectList)ViewBag.NewsCategoriesID)
Now Implement new updated working code:
#Html.DropDownListFor(model => model.NewsCategoriesID, ViewBag.NewsCategoriesID as List<SelectListItem>, new {name = "NewsCategoriesID", id = "NewsCategoriesID" })
I want to put the correct answer in here, just in case others are having this problem like I was. If you hate the ViewBag, fine don't use it, but the real problem with the code in the question is that the same name is being used for both the model property and the selectlist as was pointed out by #RickAndMSFT
Simply changing the name of the DropDownList control should resolve the issue, like so:
#Html.DropDownList("NewsCategoriesSelection", (SelectList)ViewBag.NewsCategoriesID)
It doesn't really have anything to do with using the ViewBag or not using the ViewBag as you can have a name collision with the control regardless.
I prefer the lambda form of the DropDownList helper - see MVC 3 Layout Page, Razor Template, and DropdownList
If you want to use the SelectList, then I think this bug report might assist - http://aspnet.codeplex.com/workitem/4932
code bellow, get from, goes
Controller:
int DefaultId = 1;
ViewBag.Person = db.XXXX
.ToList()
.Select(x => new SelectListItem {
Value = x.Id.ToString(),
Text = x.Name,
Selected = (x.Id == DefaultId)
});
View:
#Html.DropDownList("Person")
Note:
ViewBag.Person and #Html.DropDownList("Person") name should be as in view model
To have the IT department selected, when the departments are loaded from tblDepartment table, use the following overloaded constructor of SelectList class. Notice that we are passing a value of 1 for selectedValue parameter.
ViewBag.Departments = new SelectList(db.Departments, "Id", "Name", "1");
For anyone that dont want to or dont make sense to use dropdownlistfor, here is how I did it in jQuery with .NET MVC set up.
Front end Javascript -> getting data from model:
var settings = #Html.Raw(Json.Encode(Model.GlobalSetting.NotificationFrequencySettings));
SelectNotificationSettings(settings);
function SelectNotificationSettings(settings) {
$.each(settings, function (i, value) {
$("#" + value.NotificationItemTypeId + " option[value=" + value.NotificationFrequencyTypeId + "]").prop("selected", true);
});
}
In razor html, you going to have few dropdownlist
#Html.DropDownList(NotificationItemTypeEnum.GenerateSubscriptionNotification.ToString,
notificationFrequencyOptions, optionLabel:=DbRes.T("Default", "CommonLabels"),
htmlAttributes:=New With {.class = "form-control notification-item-type", .id = Convert.ToInt32(NotificationItemTypeEnum.GenerateSubscriptionNotification)})
And when page load, you js function is going to set the selected option based on value that's stored in #model.
Cheers.

Resources