MVC Razor View loses Variable scope inside for loop - c#

I have a razor view that loses the variable scope once inside the forloop. It works fine until I added the table tags. So all my calls to the different parts of the ViewModel no longer work. Please let me know if there is anything else that would help to know.
#model Auditor_Evaluations_MVC.ViewModels.EvaluationViewModel
#using (Html.BeginForm())
{
<div>
<table class="table table-condensed" style="width:825px;">
for(int i = 0; i < Model.QuestionGroup.Count; i++)
{
var questionGroup = Model.QuestionGroup[i];
#Html.HiddenFor(m => Model.QuestionGroup[i].GroupName)
#Html.HiddenFor(m => Model.QuestionGroup[i].GroupId)
<thead>
<tr>
<th class="text-left">#Html.Label(questionGroup.GroupName) </th>
<th class="text-center">Excellent</th>
<th class="text-center">Good</th>
<th class="text-center">Fair</th>
<th class="text-center">Poor</th>
<th class="text-center">N/A</th>
</tr>
</thead>
var questions = questionGroup.Questions;
for(int j = 0; j < questions.Count; j++)
{
#Html.HiddenFor(m => Model.QuestionGroup[i].Questions[j].QuestionName)
<tr>
<td class="text-left">#Html.Label(questions[j].QuestionName) </td>
var questionResponse = questions[j].QuestionResponses;
#for(int k = 0; k < questionResponse.Count; k++)
{
<td class="text-center" style="width:75px">
#Html.RadioButtonFor(m => Model.QuestionGroup[i].Questions[j].SelectedAnswer,questionResponse[k].QuestionValue)
</td>
}
</tr>
}
}
<tr>
<td colspan="6"> </td>
</tr>
<tr>
<td colspan="6"><strong>#Model.GeneralQuestion1Text</strong></td>
</tr>
<tr>
<td colspan="6">#Html.TextAreaFor(m => m.GeneralQuestion1Value)</td>
</tr>
<tr>
<td colspan="6"><strong>2. Additional Comments:</strong></td>
</tr>
<tr>
<td colspan="6">#Html.TextAreaFor(m => m.GeneralQuestion2Value)</td>
</tr>
<tr>
<td colspan="6"><strong>3. Would you like the appropriate audit manager to contact you regarding any or all of the information relayed through this questionnaire? If yes, please include your name and telephone number.</strong></td>
</tr>
<tr>
<td colspan="6">#Html.TextAreaFor(m => m.GeneralQuestion3Value)</td>
</tr>
<tr>
<td colspan="6"><input type="submit" value="Submit"/></td>
</tr>
</table>
</div>
}

I'm not 100% sure on exactly what your problem is, the question is a little confusiing, but all the places where you do something like this:
#Html.HiddenFor(m => Model.QuestionGroup[i].GroupName)
Should probably be replaced with
#Html.HiddenFor(m => m.QuestionGroup[i].GroupName)
i.e. use the m variable to represent your model in the lambda expression, rather than referencing the Model property.
Also, on this line:
<table class="table table-condensed" style="width:825px;">
for(int i = 0; i < Model.QuestionGroup.Count; i++)
You need to add an # in front of the for keyword.

Try using a foreach in that Razor block
foreach(var question in Model.QuestionGroup) {
#Html.HiddenFor(m => m.question.GroupName)
#Html.HiddenFor(m => m.question.GroupId)
...
etc.
update: you may need to look into the EditorFor and EditorForModel HTML helpers if your model is not mapping to the correct ViewModel when send it

Related

How to use a razor declared variable outside of razor?

I have a foreach displaying product descriptions and product prices. i want to be able to sum all of the prices and display them in a data cell. How can i do this?
<table class="table table-striped">
<tr>
<th>Description</th>
<th>Price</th>
</tr>
#foreach (var product in Model)
{
<tr>
<td>#product.Description</td>
<td>#product.Price</td>
</tr>
}
#foreach (var product in Model)
{
var sum = product.Price++;
}
<tr>
<td colspan="2">Total Price: </td>
</tr>
</table>
i want to be able to show the value of sum outside the foreach
You can declare a variable inside a code block and use it in the foreach like so:
<table class="table table-striped">
<tr>
<th>Description</th>
<th>Price</th>
</tr>
#foreach (var product in Model)
{
<tr>
<td>#product.Description</td>
<td>#product.Price</td>
</tr>
}
#{
var sum = 0;
foreach (var product in Model)
{
sum += product.Price;
}
}
<tr>
<td colspan="2">Total Price: #sum</td>
</tr>
</table>
An alternative could be using System.Linq.
<tr>
<td colspan="2">Total Price: #Model.Sum(product => product.Price)</td>
</tr>

Submit form with table - how to pass the selected row number on submit

Here is the Model:
public class TestModel
{
public string Data { get; set; }
public List<string> Datas { get; set; }
}
Here is the view:
#model InventoryWeb.Models.TestModel
#using (Html.BeginForm())
{
#Html.DisplayFor(modelItem => Model.Data)
#Html.HiddenFor(m => m.Data)
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
#Html.Hidden("Datas["+ i + "]", Model.Datas[i])
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<input type="submit" value="Submit" formaction="SubmitTest" formmethod="post"/>
</td>
</tr>
}
</table>
}
How to pass the selected row number (the number of row on which user pressed the "Submit" button) to controller? TempData/Viewbag/whatever it is possible to use to pass this info to Controller site when Submitting.
The way you wrote it, it will send all the data back to server for any row.
You can insert a form in each row:
#model InventoryWeb.Models.TestModel
#Html.DisplayFor(modelItem => Model.Data)
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
#using (Html.BeginForm())
{
#Html.Hidden("rowNumber", i)
<input type="submit" value="Submit" formaction="SubmitTest" formmethod="post"/>
}
</td>
</tr>
}
</table>
But I prefer using javascript in this situations.
Edit
With JavaScript:
#using (Html.BeginForm("SubmitTest"))
{
#Html.DisplayFor(modelItem => Model.Data)
#Html.HiddenFor(m => m.Data)
<input type="hidden" id="rowNumber" name="rowNumber" />
<table class="table">
<tr>
<th>
Data
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Datas.Count; i++)
{
#Html.Hidden("Datas["+ i + "]", Model.Datas[i])
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<input type="button" value="Submit" onclick="SubmitForm(#i, this);"/>
</td>
</tr>
}
</table>
}
<script>
function SubmitForm(i, btn){
$("#rowNumber").val(i);
var form = $(btn).closest("form");
form.submit();
}
</script>
use <button> to replace the <input type="submit" ..>, and set the row number in the value of the <button>
#for (int i = 0; i < Model.Datas.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.Datas[i])
</td>
<td>
<button name="rowNumber" value="#i">Submit</button>
</td>
</tr>
}
And if the target post Controller/Action is different the current one, instead of setting formaction and formmethod in every submit button, set it in the Html.BeginForm() like
#using(Html.BeginForm("ActionName", "ControllerName"))
{
...
}

Creating a table programmatically

I have been searching for quite some time to create the following table through code-behind using C#. I am finding difficulty in adding a <tr> to <thead> and <tr> to <tbody>. This is how the table should look like:
<table id="mytable" border="1" cellpadding="10" cellspacing="0" >
<caption>myCaption</caption>
<thead>
<tr>
<td> </td>
<th scope="col">myHeader1</th>
<th scope="col">myHeader2</th>
<th scope="col">myHeader3</th>
</tr>
</thead>
<tbody>
<tr>
<td>2</td>
<td>3</td>
<td>1</td>
</tr>
</tbody>
</table>
Any help is appreciated.
Create a strongly typed view with a list of whatever you're binding, and use the #foreach loop:
#model List<MyClass>
<table id="mytable" border="1" cellpadding="10" cellspacing="0" >
<caption>myCaption</caption>
<thead>
<tr>
<td> </td>
<th scope="col">myHeader1</th>
<th scope="col">myHeader2</th>
<th scope="col">myHeader3</th>
</tr>
</thead>
<tbody>
#foreach(var m in Model)
{
<tr>
<td>#m.MyProp1</td>
<td>#m.MyProp2</td>
<td>#m.MyProp3</td>
</tr>
}
</tbody>
I have done similar thing using C# MVC. Here is a sample code. Hope this will help to get an idea.
#{int count = Model.HeadingsList.Count;}
<table>
<thead>
<tr>
#foreach (string heading in Model.HeadingsList)
{
<th>#heading</th>
}
</tr>
</thead>
<tbody>
#foreach (string row in Model.rowsList)
{
string[] cellValues = Array.ConvertAll(row.Split(','), p => p.Trim());
if (count != cellValues.Count()) { return; }
<tr>
#for (int i = 0; i < #count; i++)
{
<td>#cellValues[i]</td>
}
</tr>
}
</tbody>
</table>
I had a list of rows like below.
Array[0]['cell1','cell2','cell3'...]
Array[1]['cell1','cell2','cell3'...]

MVC Partial View not rendering

Partial view is not rendering while passing ViewModel.. Its rendering without ViewModel.
I mean if I keep #Html.Partial("PartialClientIndex") then its rendering and when I pass ViewModel it directly going to Dispose without rendering partial view.
I'm missing something here.. could you please help in this.
Main View:
<div id="PartialClient">
#Html.Partial("PartialClientIndex", viewModelList)
</div>
Action:
[HttpPost]
public ActionResult PartialClientIndex(int? SelectedGroupId)
{
int SkipRec = 0;
int NextRec = 25;
VMClient vmclient = new VMClient();
vmclient.IEClients = db.client.Where(cl => cl.Groups.id == SelectedGroupId).OrderBy(c => c.id).Skip(SkipRec).Take(NextRec).ToList();
return PartialView("PartialClientIndex", vmclient);
}
Partial View:
#model IEnumerable<HostingManager.Models.VMClient>
<table>
<thead>
<tr>
<th style="width:25px; padding:10px;">
Group
</th>
<th class="tbContent-Name">
Client Name
</th>
<th class="tbContent-Name">
Contact Person
</th>
<th class="tbContent-Name">
Contact Email
</th >
<th></th>
</tr>
</thead>
<tbody>
#if(Model != null)
{
var x = Model.Select(c=>c.IEClients).ToList();
var y = x[0].ToList();
// var y = x[0]["item1"];
foreach (var item in y) {
<tr>
<td class="tbContent-Name">
#Html.DisplayFor(modelItem => item.Groups.name)
</td>
<td class="tbContent-Name">
#Html.DisplayFor(modelItem => item.contactPerson)
</td>
<td class="tbContent-Name">
#Html.DisplayFor(modelItem => item.contactPerson)
</td>
<td class="tbContent-Name">
#Html.DisplayFor(modelItem => item.contactEmail)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.id }, new { onclick = "return confirm('Are you sure you wish to delete this ?');" })
</td>
</tr>
}
}
</tbody>
It seems that the variable vmclient that you are passing as model into your partial view is of type VMClient. Though your partial view is expecting the IEnumerable<VMClient> type.
You basically have to change the model type in your partial view to the following
#model HostingManager.Models.VMClient
and adjust the way you are assigning the y variable
var y = Model.IEClients;

Adding rows to the final page of a pagedlist

<div>
<table ​>
<tr>
<th>Customer ID</th>
<th>Name</th>
<th>Type</th>
</tr>
#foreach (var a in Model.Attachments)
{
<tr>
<td>
#a.CId
</td>
<td>
#a.CName
</td>
<td>
#a.CType
</td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model.Attachments, page => Url.Action("Index", new { page }))
</div>
Currently I am displaying 25 items per page. If the final page does not have 25 items, I want to append rows to the end of the table, to keep the Page selector at the same level from page to page.
This seems like it would work, I just don't know where to put it:
#for (int i = 25; i > Model.Attachments.Count() % 25; i--)
{
<tr>
<td></td>
</tr>
}
You have for sure a loop thrown the attachments list.
Put this loop right after the loop where you write your TRs.
Just take into account that if your data makes your TRs higher, this will break your solution. Other thing you may try is adding a HTML space in your dummy rows:
<div>
<table ​>
<tr>
<th>Customer ID</th>
<th>Name</th>
<th>Type</th>
</tr>
#foreach (var a in Model.Attachments)
{
<tr>
<td>
#a.CId
</td>
<td>
#a.CName
</td>
<td>
#a.CType
</td>
</tr>
}
#for (int i = 25; i > Model.Attachments.Count() % 25; i--)
{
<tr>
<td></td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model.Attachments, page => Url.Action("Index", new { page }))
</div>

Categories

Resources