MVC 3 Rendering 2-Level Menu as Partial View - asp.net-mvc-3

I would like to implement a 2-level parent/child menu in my MVC 3 site such as
Company
- Background
- Contact
I have implemented a single, parent level menu as a PartialView like so ...
<div id="menu" class="block">
<ul id="menuItems">
foreach (var item in Model)
{
<li id="#item.Id">#Html.ActionLink(item.Name, item.Action,item.Controller)</li>
}
</ul>
</div>
and then included it on my MasterPage ...
#{Html.RenderAction("MainMenu", "Menu");}
The problem is that I would like to render a second child-menu based on the menu item selected at the parent level. This involves passing the Id of the parent into the controller action that returns the menu model. I'm not sure how I can pass this parent Id into the controller action. Can anyone provide any insights into this? I'm using MVC3 & Razor.

You may want to check out MvcSiteMapProvider which handles multilevel menu and sitemaps.

Looks like you're using Razor and while I'm not super familiar with that I'll take a shot at it. Basically you're going to pass a new object that has a single property of "id" to the MainMenu view. That will create another menu. Your MainMenu action should take an optional parameter of id.
public ActionResult MainMenu(int? id = null) {
...
}
Here is what your new list item would look like.
<li id="#item.Id">#Html.ActionLink(item.Name, item.Action,item.Controller)
#{Html.RenderAction("MainMenu", "Menu", new { id = item.Id });}
</li>

Related

Add and remove textbox at runtime in mvc3

In my page there is one textbox by default and one add button beside it. I need to add the another textbox when user click Add button. And there should be two buttons Add and Remove beside newly added text box. And same process goes on i.e., user can add Textbox using Add button and remove it using remove button.
I am new to mvc 3 so i am confused how to proceed. Is there any way like placeholder in asp.net so that we can add control at runtime.
Any suggestion and idea will be helpful to me
MVC is a very "hands-off" framework compared to Web Forms, so you're free to add the new textboxes how you like. Note that "controls" don't exist in MVC.
Here's how I'd do it:
Model:
class MyModel {
public Boolean AddNewTextBox { get; set; }
public List<String> MultipleTextBoxes { get; set; } // this stores the values of the textboxes.
}
View (I prefer the Web Forms view engine, I'm not a fan of Razor):
<% for(int i=0;i<Model.MultipleTextBoxes.Count;i++) { %>
<%= Html.TextBoxFor( m => m.MultipleTextBoxes[i] ) /* this might look like magic to you... */ %>
<% } %>
<button type="submit" name="AddNewTextbox" value="true">Add New Textbox</button>
<button type="submit">Submit form</button>
Controller:
[HttpPost]
public ActionResult MyAction(MyModel model) {
if( model.AddNewTextBox ) model.MultipleTextBoxes.Add("Yet another");
else if( ModelState.IsValid ) {
// your regular processing
}
}
You can also add more textboxes with Javascript and it work perfectly fine. All that matters is the HTML input elements. There's no cryptic viewstate. MVC is stateless.
Note that because I used <button type="submit"> my example will not work reliably in Internet Explorer 6-8 (sucks, I know), but you can replace them with <input type="submit"> with no ill-effects.
This requires some Javascript/JQuery... The following is a sketch only, but will hopefully be useful as a general approach.
The remove button
You want to render a button that can target its own container for removal. To do that, use some markup like this:
<div class="item-container">
<input type="button" onclick="removeItem(this)" />
</div>
And the Javascript for removeItem:
<script>
function removeItem(element) {
// get the parent element with class "item-container" and remove it from the DOM
$(element).find(".item-container").remove();
}
</script>
The add button
You could either use a partial view with Ajax, or use straight Javascript; which one is best likely depends on whether you need a round-trip to the server to create a new item. Let's say you need to go the the server to generate a new ID or something.
First, create a partial view and corresponding controller action; this should contain the remove button as above, as well as the text box and add button.
Now, create an Ajax form on your main page that gets invoked when you click Add:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("New", new AjaxOptions() { UpdateTargetId="ajaxTarget", HttpMethod = "GET" })) {
<input type='submit' value='Add New' />
}
<div id="ajaxTarget"></div>
This code fetches your partial view (from the action New in the current controller) and adds the result to the ajaxTarget element.
Note The Ajax form requires Unobtrusive Ajax, which you can install via Nuget: Install-Package JQuery.Ajax.Unobtrusive.

Showing list to the view

I have retrieved a list of products from the database, from model to controller. Now, I want to display it in the view when the button is clicked. I don't know which HTML element to use to show the list and how do I pass it to the view?
In your controller, you can pass the Model to the View by returning your model like:
return View(model);
Then in your View specify your model at the top of your file:
#model [Model here]
Then you could loop through your objects to display them on the page like so:
<ul>
#foreach(var product from Model.Products){
<li>#product.Name</li>
}
</ul>

MVC3 Ajax.BeginForm with PartialView and persistent routedata issue

I have a main view and the URL for this view has a Action/Controller/Area and id value, something like:
http://localhost:56513/Incident/IncidentHome/Index/8c02a647-a883-4d69-91be-7ac5f7b28ab7
I have a partialview in this main view, one that calls methods in the controller via Ajax. This partial view needs to know the ID value of the url for the parent page. I found how to do this is through 'ParentActionViewContent'. Something like:
using (Ajax.BeginForm("UpdatePersonalStatusPanel", "Status", new { area = "Tools" , id = ViewContext.ParentActionViewContext.RouteData.Values["id"].ToString() }, new AjaxOptions { UpdateTargetId = "divPersStatus" }))
{
<p style="text-align: center;">
<span class="editor-label">#Html.LabelFor(m => m.StatusText)</span> <span class="editor-field">#Html.EditorFor(m => m.StatusText)</span>
<input type="submit" value="Change Current Status" />
</p>
}
Now, this works fantastic for calling the controller method. The ID is passed correctly so that the controller can then see it in the routedata. I use the id to perform a database call, and then return the partialview again. The problem is on the return. I get a 'Object reference not set to an instance of an object' on the ViewContext.ParentActionViewContext.RouteData.Values["id"].ToString() bit in the ajax.beginform , and my targetid doesn't refresh.
Clearly I must be doing something wrong. Does someone else have a better way to see the parent view's routedata through Ajax?
If I'm understanding you correctly, this partial view calls itself. So ParentActionViewContext works the first time because the first time your main view calls an action using this partial view. However, later an ajax call directly returns this partial view. When the partial view is invoked directly there is no Parent View action hence the null reference on ParentActionViewContext.
Rather than deal with with route data I recommend including the id in the model of your partial view.
new { area = "Tools" , id = Model.Id }

To call a page on click of an ActionLink in the same View

i am developing an application in MVC3..
I have several links on the leftside and on click of the link the page should be displayed on the right side
I have made a table.
in the First Column the links are displayed like this:
<ul>
#foreach (var item in Model)
{
<li>#Html.ActionLink(item.HobbyName, "Hobbies")</li>
}
and in the second column i need to display information about the links when it is clicked but i am not understanding hw shud i do that..
Like What shud i write in the Controller to fetch those views in this column.
Please Help me
Use Ajax.ActionLink instead of Html.Actionlink and set update target id in Ajax Options to the div you want to update. Example
<ul>
#foreach(var item in Model)
{
<li>
#Ajax.ActionLink(item.HobbyName, "Hobbies",
new AjaxOptions { UpdateTargetId = "divHobyList" })
</li>
}
</ul>
<div id="divHobyList">
here will load hobbies
</div>

MVC 3 Changing Model in Views with RenderPage

I'm having problems when trying to change the model of my view in MVC 3.
First view (index.cshtml) :
#model IEnumerable<MyProgram.MyFrogCollection>
<h1>Welcome to my frog collection</h1>
#foreach(MyProgram.Frog frog in Model)
{
<div class="frogDetails">
#RenderPage("ShowFrogDetails.cshtml", frog);
</div>
}
Second view (ShowFrogDetails.cshtml), that I would like to use all over the site :
#model MyProgram.Frog
<h3>Name:</h3><div class="detail">#Model.Name</div>
<h3>Colour:</h3><div class="detail">#Model.Colour</div>
However when I try to run the page index.cshtml after passing in a list of frog objects I get the following error when getting to the #RenderPage line :
Server Error in '/' Application. The model item passed into the
dictionary is of type
'System.Collections.Generic.List`1[MyProgram.Frog]', but this
dictionary requires a model item of type 'MyProgram.Frog'.
If I were to remove the code from ShowFrogDetails.cshtml and place it in-line within the foreach loop of index.cshtml the results are what I would expect. However this doesn't reuse existing code.
Is there anyway I can change the model to a single Frog object for use in the RenderPage ?
Cheers!
Try like this:
<div class="frogDetails">
#Html.Partial("ShowFrogDetails", frog)
</div>

Resources