Weird Razor nesting foreach (...) { <tr> #Html.... </tr> } - asp.net-mvc-3

I want to do this in my Razor view:
#foreach (Customer cust in Model.Customers)
{
<tr data-custid="#customer.GetIdAsText()">
#Html.RenderPartial("CustomerListTableRow", cust)
</tr>
}
As far as I understand, this should work. The foreach block contains a <tr>...</tr>. Inside that, it is in markup mode, so I need # to switch to C# mode. The problem is that apparently the variable cust loses its type info (and value?), so it complains that it cannot cast void to object, which RenderPartial expects.
I got it working like this:
#foreach (Customer cust in Model.Customers)
{
#:<tr data-custid="#customer.GetIdAsText()">
Html.RenderPartial("CustomerListTableRow", cust);
#:</tr>
}
But aside from looking puke ugly, if I let VS beautify the code, it mucks it up like this:
#foreach (Customer cust in Model.Customers)
{
#:<tr data-custid="#customer.GetIdAsText()">
Html.RenderPartial("CustomerListTableRow", cust); #:</tr> }
Nice, huh? :-)
So, why doesn't the first solution work? How should I write it?

Html.RenderPartial() is a void method and hence it must be enclosed it with a { } block:
#{Html.RenderPartial("CustomerListTableRow", cust);}
What you are definitely looking for is Html.Partial(), which returns an MvcHtmlString, and it can be used like this:
#Html.Partial("CustomerListTableRow", cust)

I think this should work,
#foreach (Customer cust in Model.Customers)
{
<tr data-custid="#customer.GetIdAsText()">
#Html.RenderPartial("CustomerListTableRow", cust);
</tr>
}
Depending on the version of MVC you are running.
Can you provide more details on the error?

Related

Can you use a #Helper inside an #Helper?

I am not sure this is possible.
I have a bunch of #Helper's inside a view AND in other views:
#helper ViewHelper1()
{
...
}
#helper ViewHelper2()
{
...
}
etc.
I have repetitive code that is used in the view AND in other views:
#if (!(Model.Entity == Model.Enum.One))
{
<td>
#ViewHelper1()
</td>
}
else
{
<td>
#ViewHelper1()
</td>
<td>
#ViewHelper1()
</td>
}
The actual #ViewHelper1 has more complex code, but that's not important (I think).
Well, since each view has a number of #Helper's (30+ views, 10-15 #Helper's each) and the <table> structure is the same, I was wondering how to go about creating a #Helper in App_Code that encapsulates the <td> structure and then would pass the view's #Helper.
Say:
#helper Table(...)
{
...
}
Or whether or not that's even possible and then call it in the view like:
#Table(HelperView1)
If it is I just needed help with the syntax.
As always, much appreciated.
The generated razor helpers are just functions with the return type HelperResult.
You can have delegates which returns HelperResult as parameters in your main helper and call them at the appropriate places.
A small sample to get you started:
#helper View1()
{
<h1>View1</h1>
}
#helper View2()
{
<h2>View2</h2>
}
#helper Table(Func<HelperResult> viewHelper)
{
<text>Reuslt of viewHelper</text>
#viewHelper()
}
#Table(View1)
#Table(View2)
The generated output:
Reuslt of viewHelper
<h1>View1</h1>
Reuslt of viewHelper
<h2>View2</h2>

if else statement in Razor is not functioning

I am using an if else in Razor view to check for null value like this:
#foreach (var item in Model)
{
<tr id="#(item.ShopListID)">
<td class="shoptablename">#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="shoptableamount">
#if (item.Amount == null)
{
Html.Display("--");
}
else
{
String.Format("{0:0.##}", item.Amount);
}
</td>
</tr>
}
However, no matter my model amount is null or having a value, the html rendered do not contain any value in the amount.
I wonder why this is happening. Any idea?
Thanks...
EDIT:
Decided to did it in controller:
// Function to return shop list food item amount
public string GetItemAmount(int fid)
{
string output = "";
// Select the item based on shoplistfoodid
var shopListFood = dbEntities.SHOPLISTFOODs.Single(s => s.ShopListFoodID == fid);
if (shopListFood.Amount == null)
{
output = "--";
}
else
{
output = String.Format("{0:0.##}", shopListFood.Amount);
}
return output;
}
and call at View like:
<td class="shoptableamount">
#Html.Action("GetItemAmount", "Shop", new { fid = item.ShopListFoodID })
</td>
You have to use the #()
#if (item.Amount == null)
{
#("--");
}
else
{
#String.Format("{0:0.##}", item.Amount)
}
As noted in the comments and other answers, the Html.Display is not for displaying strings, but for displaying data from the ViewData Dictionary or from a Model. Read http://msdn.microsoft.com/en-us/library/ee310174%28v=VS.98%29.aspx#Y0
I think you want to display "-----" if amount is null.
#foreach (var item in Model)
{
<tr id="#(item.ShopListID)">
<td class="shoptablename">#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="shoptableamount">
#if (item.Amount == null)
{
#Html.Raw("--")
}
else
{
String.Format("{0:0.##}", item.Amount);
}
</td>
</tr>
}
That's because you are using the Display() method incorrectly. The overload you are using is Display(HtmlHelper, String). If you are looking for "--" to be the text, you should use something like:
#Html.Label("--");
There are actually two other ways to display text from a code block in razor besides the suggested #(""), using a <text> tag and it's shorthand #:
#{
#("--")
<text>--</text>
#:--
}
The code above will display -- three times.

MVC3 Razor weakly typed view?

I know this sound somewhat off-piste but how would you create a weakly typed view where you pass in a collection of objects and iterate in razor accordingly and display in a table?
-- Controller View --
???
-- Razor View ---
#foreach (var item in Model)
{
<tr>
<td>
#item.attr1
</td>
<td>
#item.attr2
</td>
</tr>
}
Frist you know the data send
From Controller -------> view by two way
By weak type view
and by strong type view
there is no other way of passing data from controller to view ...(remember)
what is intelliscence ----> which show the related sub property of any model
like we write Model. --------> then all property show in
droupdown list after dot(.).
A.what is weak type view
This is used without using model i.e like using ViewBag and other.
There is no intellisence for this type of view and it is complicated, and when you write
any name which not exist then it give at runtime error.
Ex.
.............Controller
ViewBag.List = List<job>;
return View();
.............Razor View
#foreach(var item in ViewBag.List)
{
// when you write no intellisence and you want to write your own correct one...
#item.
}
B. What strongly type view
this is used model to send data from controller to view an vice-versa.
Model are strongly typed to view so, it show intellicence and when you write wrong
then there only error show at compile time..
Ex.
.................Controller
List<job> jobdata =new List<job>();
return View(jobdata);
................view
//Mention here datatype that you want to strongly type using **#model**
#model List<job>
#foreach(var item in Model)
//this **Model** represent the model that passed from controller
// default you not change
{
#item. //then intellisence is come and no need write own ....
}
that is weak and strong type view ......
So now you solve any problem with this basic.....
may I hope it help u....
But it is best to use Strongly Typed view so it become easy
to use and best compare to weak...
#model dynamic
Will do what you want, I believe.
If its going to be a collection, then maybe use
#model ICollection
It's not weakly typed. It's typed to a collection of some kind.
#model IEnumerable<MyClass>
OK, late to the party I know, but what you're after is a view stating "#model dynamic" as already stated.
Working Example: (in mvc3 at time of posting)
NB In my case below, the view is actually being passed a System.Collections.IEnumerable
As it's weakly typed, you will not get intelesense for the items such as #item.Category etc..
#model dynamic
#using (Html.BeginForm())
{
<table class="tableRowHover">
<thead>
<tr>
<th>Row</th>
<th>Category</th>
<th>Description</th>
<th>Sales Price</th>
</tr>
</thead>
#{int counter = 1;}
#foreach (var item in Model)
{
<tbody>
<tr>
<td>
#Html.Raw(counter.ToString())
</td>
<td>
#item.Category
</td>
<td>
#item.Description
</td>
<td>
#item.Price
</td>
</tr>
#{ counter = counter +1;}
</tbody>
}
</table>
}
Edit: removed some css

MVC3 Razor foreach problems

I've got a model that is returning a IEnumerable of football picks for a variable number of users. Due to this, I'm dynamically building an html table with a variable number of columns. Basically, my picks will come back like this. However, each game is going to be repeated for each User, so I'm only adding the first 3 columns of each table row once, and then adding only a single tag until the gameID changes. I know there are probably better ways to do this, but it's just a side project that I need to get done quickly. And, I just want to figure out why it's not working.
GameID
GameDateTimeDisplay
GameTeamDisplay
WinningTeamDisplay
PickedTeamAbbr
OK, so here is the insanity that doesn't work. I can get my table headers created successfully, but then the tbody isn't working, but it's erroring in an odd place.
I had to put all the #Html.Raw(...) stuff in there because it was having trouble finding the end tags for the foreach and if statements without them.
Anyway, here is my code. The line that is causing the exception is this:
#gameID = #pick.Game.GameID;
The exception is --> Compiler Error Message: CS1525: Invalid expression term '='
The intellisense shows #gameID as a variable and the #pick.Game.GameID seems to be correct as well.
<table>
<thead>
<tr>
<th>Game</th>
<th>Game Date/Time</th>
<th>Winner</th>
#foreach(var name in #Model.UserNames) {
<th>#name</th>
}
</tr>
</thead>
<tbody>
#{
int lastGameID = 0;
int gameID = 0;
bool firstGame = true;
}
#foreach(var pick in #Model.Picks) {
#gameID = #pick.Game.GameID;
if(#gameID != #lastGameID) {
if(!#firstGame){
<text>#Html.Raw("</tr>")</text>
}
#Html.Raw(
<tr>
<td>#pick.GameTeamDisplay</td>
<td>#pick.GameDateTimeDisplay</td>
<td>#pick.Game.WinningTeam.TeamAbbr</td>
<td>#pick.PickedTeamAbbr</td>
)
}
else {
#Html.Raw(<td>#pick.PickedTeamAbbr</td>)
}
}
#Html.Raw(</tr>)
</tbody>
</table>
UPDATE:
I've removed the #Html.Raw, , etc... Also wrapped the gameID assignment in a #{}. It's now giving me an error on this line,
#{gameID = #pick.Game.GameID;}
Compilation Error: CS1501: No overload for method 'Write' takes 0 arguments
Here is the updated Code:
#foreach(var pick in #Model.Picks) {
#{gameID = #pick.Game.GameID;}
if(#gameID != #lastGameID) {
if(!#firstGame){
#:</tr>
}
#:<tr>
<td>#pick.GameTeamDisplay</td>
<td>#pick.GameDateTimeDisplay</td>
<td>#pick.Game.WinningTeam.TeamAbbr</td>
<td>#pick.PickedTeamAbbr</td>
}
else {
<td>#pick.PickedTeamAbbr</td>
}
}
</tr>
You need to surround it with { } to make it a codeblock
#{gameID = pick.Game.GameID;}
Also, you don't need the # inside the foreach/if statements because they're code blocks.
e.g. you could just write:
foreach(var name in Model.UserNames) {
Just write
#foreach(var pick in Model.Picks) {
<tr>
<td>#pick.GameTeamDisplay</td>
<td>#pick.GameDateTimeDisplay</td>
<td>#pick.Game.WinningTeam.TeamAbbr</td>
<td>#pick.PickedTeamAbbr</td>
</tr>
}
You don't need # inside code block. You can use #: instead of <text>, Html.Raw
You can see here Razor syntax reference
I determined that my Razor view code was simply too complex. The real problem was that I was trying to force a view to work with a Model that I had created for another view. I ended up creating a few more models specifically for this view. Code is much cleaner and best of all it works! Here is the code I ended up with.
<table>
<thead>
<tr>
<th>Game</th>
<th>Game Date/Time</th>
<th>Winner</th>
#foreach(var name in #Model.UserNames) {
<th>#name</th>
}
</tr>
</thead>
<tbody>
#foreach(var game in #Model.Games) {
<tr>
<td>#game.GameDescription</td>
<td>#game.GameDisplayDateTime</td>
<td>#game.GameWinner</td>
#foreach(var pick in game.GamePicks){
<td>#pick.PlayerPick</td>
}
</tr>
}
</tbody>
</table>

How can I reference MVC item/model in HTMLAttributes?

I'm trying to list two radio buttons in each row of a table, but I haven't been able to assign unique IDs to each radio button. I'd like to assign the IDs based on the #item.myID as follows:
#foreach (var item in Model)
{
<tr>
<td>
#Html.RadioButton("Yes", #item.myID, #item.IsCool, new { id = "#item.myID", autopostback = "true" })
#Html.RadioButton("No", #item.myID, !#item.IsCool, new { id = "#item.myID", autopostback = "true" })
</td>
</tr>
}
However, the IDs keep rendering literally as "#item.myID". In other words, it's not treating the # sign as a special character. I've also tried using parenthesis, like this: "#(item.myID)".
You need to remove the quotes from around the id assignment, like so;
#foreach (var item in Model)
{
<tr>
<td>
#Html.RadioButton("Yes", item.myID, item.IsCool, new { id = item.myID, autopostback = "true" })
#Html.RadioButton("No", item.myID, !item.IsCool, new { id = item.myID, autopostback = "true" })
</td>
</tr>
}
Also, note that you don't need the additional "#" symbol when you are already in the context of another Razor code block - the Razor View Engine is pretty clever :)

Resources