I cannot seem to figure out how to access my Model from my View. I am confused.
Here is my Home controller. I have verified that "specimens" is being populated with data from the database:
public class HomeController : Controller
{
wildtropEntities wildlifeDB = new wildtropEntities();
public ActionResult Index()
{
ViewData["CurrentDate"] = System.DateTime.Now.ToString("MM/dd/yyyy");
var specimens = from s in wildlifeDB.specimen1
select s;
return View(specimens);
}
}
And here are couple snippets from my View:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<% foreach (WildlifeTropical.Models.specimen s in ??????)
{ %>
<div>s.Name</div>
<% } %>
I assumed I would be able to access "specimens" since I passed it to the View from the Controller (ie, return View(specimens))...but it isn't working.
You will have to make your view strongly typed to a collection of specimen which is what you are passing to it from your controller action (IEnumerable<specimen>):
<%# Page
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<WildlifeTropical.Models.specimen>>" %>
<% foreach (WildlifeTropical.Models.specimen s Model) { %>
<div><%= Html.Encode(s.Name) %></div>
<% } %>
Notice how the view inherits System.Web.Mvc.ViewPage<IEnumerable<WildlifeTropical.Models.specimen>> and it is now strongly typed to a collection of specimens that you will be able to loop through.
This being said, personally I don't like writing foreach loops in my views. They make them look ugly. In this case I would use a display template:
<%# Page
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<WildlifeTropical.Models.specimen>>" %>
<%= Html.DisplayForModel() %>
and then I would define a display template which will automatically be rendered for each element of the model collection (~/Views/Shared/DisplayTemplates/specimen.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<WildlifeTropical.Models.specimen>" %>
<div>
<%= Html.DisplayFor(x => x.Name) %>
</div>
See how the specimen.ascx user control is now strongly typed to System.Web.Mvc.ViewUserControl<WildlifeTropical.Models.specimen>. This is because it will be rendered for each specimen of the main view model.
I am not sure about MVC2. In MVC 3(with Razor View Engine), I can pass the Model / ViewModel to the View like this.
#model MyProject.ViewModel.UserViewModel
#{
ViewBag.Title = "Welcome To My Site";
}
<div class="divSubHead">
<h2>Hello #Model.FirstName</h2></div>
How about this? Note the Inherits for the Page.
<%# Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable(Of Specimen))" %>
<% foreach (WildlifeTropical.Models.specimen s in Model)
{ %>
<div>s.Name</div>
<% } %>
Related
I define a menu in navigation.vm file which working good in liferay project.
But I want to access this menu from my portlet.
Is there any way to access menu from portlet entry point or view.jsp????
import liferay-ui taglib:
<%# taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
then you can use
<liferay-ui:navigation displayStyle="from-level-0" >
</liferay-ui:navigation>
Note: setting displayStyle="from-level-0" to give you the normal behavior like on navigation.vm, you can play with attributes differently to get other behavior.
This link describes the way of getting menu items in a jsp directly.
The below code is reproduced directly from the above link with some improved formatting:
<%# taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# page import="java.util.List" %>
<%# page import="java.util.ArrayList" %>
<%# page import="com.liferay.portal.model.Layout"%>
<%# page import="com.liferay.portal.kernel.util.WebKeys"%>
<%# page import="com.liferay.portal.theme.NavItem" %>
<%# page import="com.liferay.portal.theme.RequestVars" %>
<%# page import="com.liferay.portal.theme.ThemeDisplay"%>
<portlet:defineObjects />
<liferay-theme:defineObjects />
<div style="width:100%">
<%
//ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
String title = themeDisplay.getLayout().getName(themeDisplay.getLocale());
List<NavItem> navItems = new ArrayList<NavItem>();
if (layout != null) {
RequestVars requestVars = new RequestVars(request, themeDisplay, layout.getAncestorPlid(), layout.getAncestorLayoutId());
navItems = NavItem.fromLayouts(requestVars, layouts);
}
for (NavItem navItem : navItems) {
if (navItem.getName().equalsIgnoreCase(title)) {
if (navItem.hasChildren()) {
for(NavItem navChild : navItem.getChildren()) {
%>
<div style="float:left;" class="newsMenuPortlet">
<a href="<%= navChild.getURL() %>" <%=navChild.getTarget() %>>
<%= navChild.getName() %>
</a>
</div>
<%
} // inner for-loop ends here
}
}
}// outer for-loop ends here
%>
</div>
I have following problem:
Some links that show up in the Menu (the children of "Portfolio") are links to custom controllers. Of course now the LinkingMode is not available for that Links. Thats a image of the Menu:
So the children of Portfolio (Website, Application, etc.) are actually Category-DataObjects, which do not have a SiteTree Representation. The Submenu of Portfolio is created via checking and looping for all found categories in the Database.
The menu creation looks like that:
<ul>
<% loop Menu(1) %>
<li class="$LinkingMode">
[$LinkingMode] $MenuTitle.XML
<% if Children %>
<ul class="secondary">
<% if ClassName == 'ProjectsPage' %>
<% loop $Top.Categories %> <!-- loop all found categories, every found item links to the custom category controller -->
<li class="$LinkingMode">$Name</li>
<% end_loop %>
<% else %>
<% loop Children %>
<li class="$LinkingMode"><span class="text">$MenuTitle.XML</span></li>
<% end_loop %>
<% end_if %>
</ul>
<% end_if %>
</li>
<% end_loop %>
</ul>
Every Category (Website, Mobile) in the Menu links to a custom controller, which looks basically like that:
class Category_Controller extends Page_Controller {
public function show($arguments) {
return $this; //there will be more code to display all projects of a category
}
}
I expect that I have to add some custom code for the Category_Controller which tells the Portfolio Page which linkingmode it has...
Many thx,
Florian
I´ve found good tips here:
http://www.ssbits.com/snippets/2009/extending-linkingmode-to-handle-controller-actions/
http://www.ssbits.com/tutorials/2010/dataobjects-as-pages-part-1-keeping-it-simple/
Thats the Category_Controller.php (a public var CategoryID is set there):
class Category_Controller extends Page_Controller {
public $CategoryID;
public function index($arguments) {
$slug = $arguments->param("Slug");
$category = Category::get()->filter(array('Slug' => $slug))->First();
$this->CategoryID = $category->ID;
}
}
DataObject Category (LinkingMode function checks if the current CategoryID set in the Controller equals the ID of the Category DateObject):
class Category extends DataObject {
public function LinkingMode(){
$categoryID = Controller::curr()->CategoryID;
return ($categoryID == $this->ID) ? 'current' : 'link';
}
}
In the template you can check then the linking mode as usual:
<% loop $Categories %>
<li class="$LinkingMode">$Name</li>
<% end_loop %>
Cheers,
Florian
I cannot make sense of this...
The simplified code below OUGHT to insert a new form field of the current time's second value.
Instead, even though the list manipulation happens correctly (as verifiable within the controller and in the debug output), the View does render an additional element, but seems to be just a copy of the final field's value (prior to submit). This can be verified by changing a field prior to submit - the values stick and the new element is a duplicate of the submitted final value.
The part that really cooks my noodle is that if I trivially change the operation from an Insert() to an Add(), the Add() works as expected!!
Using this example Model:
public class MyViewData
{
List<string> stringData = new List<string>();
public List<string> StringData { get { return stringData; } }
}
And this Controller:
public class TestController : Controller
{
public ActionResult Index()
{
return View(new MyViewData());
}
[HttpPost]
public ActionResult Index(MyViewData data)
{
data.StringData.Insert(0, DateTime.Now.Second.ToString());
return View(data);
}
}
And this View:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Forms.Controllers.MyViewData>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Test
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%
System.Diagnostics.Debug.WriteLine("---");
for (var i = 0; i < Model.StringData.Count; i++)
System.Diagnostics.Debug.WriteLine("{0}", Model.StringData[i]);
%>
<% using (Html.BeginForm()) { %>
<% for (var i = 0; i < Model.StringData.Count; i++) { %>
<%: Html.TextBoxFor(model => model.StringData[i])%></br>
<% } %>
<div><input type="submit" value="Do it" /></div>
<% } %>
</asp:Content>
This is the normal behavior of standard HTML helpers and is by design. When rendering the input field they will first look at the request POSTed values and only after in the ViewData and view model. This basically means that you cannot change POSted values in your controller action.
So if you have a form with an input field:
<%= Html.TextBoxFox(x => x.Id) %>
which is posted to the following action
[HttpPost]
public ActionResult Index(MyModel model)
{
model.Id = "some new value";
return View(model);
}
when rendering the view back the html helper will use the posted value. You could either write a custom html helper that does the job for you or handle it manually (absolutely not recommended but for the record):
<input type="text" name="StringData[<%= i %>]" value="<%= Model.StringData[i] %>" />
I have the code (snippet):
The Model is the IEnumerable object of the Person's class:
<% foreach (var item in Model)
{ %>
<tr>
<td><%= Html.DisplayFor(x=>item.Name) %></td>
</tr>
<% } %>
it renders only labels like that:
<td>Tommy</td>
According to the link it should be rendering a HTML markup something like:
but there is no the ID and the NAME property. Why ?
Your using the wrong template your should be using Html.EditorFor(x => x.Name)
Edit: I said you were using the wrong template because in your image it is a textbox displayed, not a label...
the default ouptut of Displayfor is
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.Encode(ViewData.TemplateInfo.FormattedModelValue) %>
according to Brad Wilson. You could easily build your own, look the other post of Brad Wilson for examples.
Or you could simply call Html.LabelFor(x => x.Name)
If you always want that, add a template, name String.ascx in your Views/Share/DisplayTemplate and just put the following in :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.Label("", ViewData.TemplateInfo.FormattedModelValue) %>
Is it possible that two different views use the same controller?
I have very complex controller that displays some data. Now I need to display this data (which is retrieved using ajax) in two partial views because I want to place them on different positions in layout.
the View() function can be passed arguments, for instance:
return View(); // The view with the same name as the action.
return View("MyView") // The view named "MyView"
There are a few more overloads too. Does this fit the bill?
If not, why not partial views, for instance, given this model:
public class BlogItem
{
public string Title { get; set; }
public int Id { get; set; }
}
And this action:
public ActionResult Index()
{
var items = new List<BlogItem>
{
new BlogItem { Title = "Test Blog Item", Id = 1 }
};
return View(items);
}
And this view:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<BlogItem>>" %>
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
<% Html.RenderPartial("List", Model); %>
<% Html.RenderPartial("Icon", Model); %>
</asp:Content>
I can have two partial views using the same model:
List:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<BlogItem>" %>
<ul>
<% foreach (var item in Model) { %>
<li><%= item.Title %></li>
<% } %>
</ul>
Icon:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<BlogItem>" %>
<div>
<% foreach (var item in Model) { %>
<div class="icon"><img src="..." /></div>
<div class="text"><%= item.Title %></div>
<% } %>
</div>
Would that work?
Based on my understanding so far, you want one controller action to return two views. I somehow think that this is not possible.
You have mentioned that the views are used to display identical data is different ways. My suggestion would to return a JsonResult from the controller action and build the view client side.