Conditionally add markup based on model value - asp.net-mvc

How can I test the value of a Model.IsCopy and render the Part Num textbox if false?
I tried using #Model.IsCopy but it's value is different than the value in #Html.HiddenFor(m=>m.IsCopy). Seems #Model is the empty class while m is the value passed into the Partial View.
#Html.HiddenFor(m => m.PartNum)
#Html.HiddenFor(m=> m.IsCopy)
<table>
<tr><td colspan="2" align="center"><h4 class="text-info"> Details</h4></td></tr>
<tr><td colspan="2" align="center"> <hr /></td></tr>
<tr>
<td width="30%">Part Num</td>
<td>
#{ if (#Model.IsCopy == false)
{
#Html.TextBoxFor(m => m.PartNum, new { ReadOnly = "true", Visibility = "true" })
}
}
</td>
</tr>
Inspecting in the browser shows the hidden field to be true but the Html.TextboxFor still renders.
<input name="IsCopy" id="IsCopy" type="hidden" value="true" data-val-required="The IsCopy field is required." data-val="true" data-bind="value:IsCopy">

Related

POST action returns the model in a valid state but returns Model.Count as 0 when using foreach or for loop

As shown in my post here the GET action method Test(..) works fine when using foreach loop in the corresponding Test.chtml view but the POST action method Test(...) returns null. But, as mentioned by many users, the foreach is not reliable for POST method. So, I decided to use the for loop as shown below. But that returned unexpected results in the view since, according to this post, in a foreachloop type casting is done automatically but in for loop you have to type cast the objects Model[i].BlogID etc to a proper class object type.
So, I decided to type cast the objects Model[i].BlogID etc to a BlogsWithRelatedPostsViewModel class object type as shown in the second version of Test.cshml view below; and this time the Test.cshtml view is displayng the correct records. But although the submit button in the view is sending a a valid model (ModelState.IsValid is true) the Model.Count is 0 that results in no update to database. Why Model.Count is 0 and how to correct it? As you can see below the html page source of the view is showing the name attributes of the tags matching the property values in the View Model.
Note: For complete code, please see this OP. I'm using ASP.NET Core with EF Core and Tag Helpers.
Test.cshtml view with for loop - without type casting the loop objects:
#model IList<ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel>
#using ASP_Core_Blogs.Models.BlogPostViewModels
#{ ViewData["Title"] = "Index"; }
<div class="row">
<div class="col-md-12">
<form asp-controller="Blogs" asp-action="Test" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post">
#{
IEnumerable<SelectListItem> yearsList = (IEnumerable<SelectListItem>)ViewBag.YearsList;
var currentlySelectedIndex = 0; // Currently selected index (usually will come from model)
}
<strong>Select a Post Year</strong>
<h6>Choose a year and a URL to begin:</h6>
<label>Year:</label><select asp-for="#currentlySelectedIndex" asp-items="yearsList"></select><input type="submit" class="btn btn-default" name="GO" value="GO" />
<table class="table">
<thead>
<tr>
<th></th>
<th></th>
<th>Url</th>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
#for (int i=0; i< Model.Count(); i++)
{
<tr>
<td><input type="hidden" asp-for="#Model[i].BlogID" /></td>
<td><input type="hidden" asp-for="#Model[i]).PostID" /></td>
<td>
<input type="text" asp-for="#Model[i].Url" style="border:0;" readonly />
</td>
<td>
<input asp-for="#Model[i].Title" />
</td>
<td>
<input asp-for="#Model[i].Content" />
</td>
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-default">Save</button>
</form>
</div>
</div>
Test.cshtml view with for loop objects being casted as BlogsWithRelatedPostsViewModel class objects:
#model IList<ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel>
#using ASP_Core_Blogs.Models.BlogPostViewModels
#{ ViewData["Title"] = "Index"; }
<div class="row">
<div class="col-md-12">
<form asp-controller="Blogs" asp-action="Test" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post">
#{
IEnumerable<SelectListItem> yearsList = (IEnumerable<SelectListItem>)ViewBag.YearsList;
var currentlySelectedIndex = 0; // Currently selected index (usually will come from model)
}
<strong>Select a Post Year</strong>
<h6>Choose a year and a URL to begin:</h6>
<label>Year:</label><select asp-for="#currentlySelectedIndex" asp-items="yearsList"></select><input type="submit" class="btn btn-default" name="GO" value="GO" />
<table class="table">
<thead>
<tr>
<th></th>
<th></th>
<th>Url</th>
<th>Title</th>
<th>Content</th>
</tr>
</thead>
<tbody>
#for (int i=0; i< Model.Count(); i++)
{
<tr>
<td><input type="hidden" asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).BlogID" /></td>
<td><input type="hidden" asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).PostID" /></td>
<td>
<input type="text" asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).Url" style="border:0;" readonly />
</td>
<td>
<input asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).Title" />
</td>
<td>
<input asp-for="((BlogsWithRelatedPostsViewModel)#Model[i]).Content" />
</td>
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-default">Save</button>
</form>
</div>
</div>
A Portion of html generated by View after Submit:
<tr>
<td><input type="hidden" data-val="true" data-val-required="The BlogID field is required." id="BlogID" name="BlogID" value="1" /></td>
<td><input type="hidden" data-val="true" data-val-required="The PostID field is required." id="PostID" name="PostID" value="1" /></td>
<td>
<input type="text" style="border:0;" readonly id="Url" name="Url" value="blog1#test.com" />
</td>
<td>
<input type="text" id="Title" name="Title" value="Title1" />
</td>
<td>
<input type="text" id="Content" name="Content" value="Content1" />
</td>
</tr>

Save all data of MVC4 html grid

Can anyone give me an example of saving all html grid data in one time. I have a view like this.
#model IList<SURVEY.Models.Question>
#using (Html.BeginForm("Index", "Survey", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-3" }))
{
#foreach(var item in Model)
{
<tr>
<td>#item.Ans1</td>
<td align="center">
<label>
<input type="radio" name="optionAS_#item.QuestionId" value="1" id="optionAS_1" onclick="disableAs(this,#item.QuestionId,1)"/>
</label>
</td>
<td align="center">
<label>
<input type="radio" name="optionAS_#item.QuestionId" value="2" id="optionAS_1" onclick="disableAs(this,#item.QuestionId,2)"/>
</label>
</td>
</tr>
}
}
I am getting null value for these controls in controller post.
[HttpPost]
public ActionResult Index(IList<Question> ques)
{
return View();
}
I am getting ques is null here. Can anyone tell me how can I resolve this?
You should use html helpers to bind properties of your model, your code might be as follows:
#for(var i = 0; i < Model.Count; i++)
{
<tr>
<td>#Html.HiddenFor(_ => Model[i].Id)
Model[i].Ans1
</td>
<td align="center">
<label>
#Html.RadioButtonFor(_ => Model[i].Name)
</label>
</td>
...
</tr>
}
and so for. HiddenFor helper is needed to create hidden input to send Id value to server to give you ability to identify you object. Take a look into Html Helpers in MVC and you will have your model back to server when form is submitted.

How to retrieve struts2 checkboxlist values

I will create a list with checkboxlist. For those I use following code:
<s:form action="accept" namespace="/manager/course">
<s:checkboxlist list="courseRequests" name="acceptList" listValue="studentNickname" listKey="studentId" theme="checkbox-fix"/>
<s:url action="accept" namespace="/manager/course" var="accList" />
<s:a href="%{accList}"><s:text name="Accept"/> </s:a>
</s:form>
It work fine a create a check box list, that you can see its pic in the following:
and this is html code generated by above code:
<form id="accept" name="accept" action="/ESA/manager/course/accept.action" method="post">
<table class="wwFormTable">
<table class="gradienttable">
<tr>
<th class="row"><p>Row</p></th>
<th style="width: 240px;"><p>Student</p></th>
<th ><p>Accept</p></th>
</tr>
<tr>
<td id="row"><p><label>1</label></p></td>
<td style="width:250px;"><p>
<label for="acceptList-1" class="checkboxLabel">Mansour Barzegar</label>
</p></td>
<td style="text-align:center;"><p>
<input type="checkbox" name="acceptList" value="5" id="acceptList-1" </p></td>
</tr>
<tr>
<td id="row"><p><label>2</label></p></td>
<td style="width:250px;"><p>
<label for="acceptList-2" class="checkboxLabel">Ali Mahmoudi</label>
</p></td>
<td style="text-align:center;"><p>
<input type="checkbox" name="acceptList" value="6" id="acceptList-2" </p></td>
</tr>
<tr>
<td id="row"><p><label>3</label></p></td>
<td style="width:250px;"><p>
<label for="acceptList-3" class="checkboxLabel">Masih Zare</label>
</p></td>
<td style="text-align:center;"><p>
<input type="checkbox" name="acceptList" value="7" id="acceptList-3" </p></td>
</tr>
</table>
Accept
</table>
</form>
In the Action Class I tried to retrive seleced checkbox value by following code:
private int[] acceptList;
public void setAcceptList(int[] acceptList){
this.acceptList=acceptList;
}
and several other code but I all states I get null.
Do I use wrong code?
in your markup, do this:
<input type="checkbox" name="thename" id="checkbox_id1" value="value1" />
<input type="checkbox" name="thename" id="checkbox_id2" value="value2" />
in your action (or object) do this:
// action/object code...
Set<String> cbox = new HashSet();
public void setThename(String[] thenames) {
for (String thename : thenames) {
cbox.add(thename);
}
}
// action/object code...
notice the checkbox name matches the setter name, e.g. element name == someName and method == setSomeName
Same would apply for Set<Integer>, but you use int[] thenames as the argument. You could also use Integer[] thenames for the argument.
to test output:
if (cbox != null) {
for (String s : cbox) {
log.info(s);
}
}
http://struts.apache.org/release/2.2.x/docs/using-checkboxes.html

Trying to figure out Ajax.BeginForm

I have a view in 2 sections.
The top section I input fields and submit to save them.
In the second section I have an autocomplete textbox. I select an item in autocomplete, and when I click submit I want to add that item to a datatable.
So for the first part when I click submit I save the details via a HttpPost method on the controller.
For the second part I intend to save it via an Ajax call for the controller and then bring back a partial view with the results. I have not coded the partial view yet, that is next.
Now I am new to Ajax.BeginForm and I am struggling with it.
I was hoping that the submit button inside the Ajax.BeginForm would only apply to that part of the form.
But in fact it calls the HttpPost method for the whole form.
So how do I fix this?
My view looks like;
#using ITOF.HtmlHelpers
#model ITOF.Models.OngoingContractViewModel
#{
ViewBag.Title = "EditOngoingContractDetails";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("EditOngoingContractDetails", "Contract", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Contract.ContractId)
<h1>Edit Ongoing Contract Details</h1>
<fieldset>
<legend>#Model.Contract.Heading</legend>
<p>Where you see <span class="error">*</span> you must enter data.</p>
<table>
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.EndDate)
</td>
<td>
#Html.EditorFor(model => model.Contract.EndDate)
</td>
</tr>
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.Organogramme)
</td>
<td>
<input type="file" id="PDF" name="file" />
#Html.HiddenFor(model => model.Contract.Organogramme)
</td>
</tr>
#if (!string.IsNullOrWhiteSpace(Model.Contract.Organogramme))
{
<tr>
<td></td>
<td>
The current organogramme is <span class="HighlightTextRed">#Model.GetOrganogrammeName()</span>
for the contract <span class="HighlightTextRed">#Model.Contract.ContractName</span><br/>
Click here to see the last saved organogramme
</td>
</tr>
}
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.AssistantRLOManagerId)
</td>
<td>
#Html.DropDownListFor(model => model.Contract.AssistantRLOManagerId, Model.AssistantRloManagerSelectList, "--N/A--")
</td>
</tr>
#if (this.TempData["SuccessMessage"] != null)
{
<tr>
<td colspan="2" class="success">#this.TempData["SuccessMessage"].ToString()</td>
</tr>
}
<tr>
<td colspan="2" style="padding-top: 20px; text-align: center;"><input type="submit" value="Save" /></td>
</tr>
</table>
</fieldset>
<fieldset>
<legend>Add an existing Site to this contract: </legend>
#using (Ajax.BeginForm("AddExistingSite", new AjaxOptions { UpdateTargetId = "siteRows" }))
{
<input type="text" name="q" style="width: 800px"
data-autocomplete="#Url.Action("SiteSearch", "DataService", new { contractId = #Model.Contract.ContractId })" />
<input type="submit" value="Add site to contract" />
}
#if (Model.SiteList.Count > 0)
{
<table id="siteDataTable" class="display">
<thead>
<tr>
<th>Main Site?</th>
<th>Type</th>
<th>Address</th>
<th>Map</th>
<th>Telephone</th>
<th>Email</th>
</tr>
</thead>
<tbody id="siteRows">
#foreach (var item in Model.SiteList)
{
<tr id="#item.SiteContract.SiteContractId">
<td>#item.SiteContract.MainSiteFlag</td>
<td>#item.Site.SiteType</td>
<td>#item.Site.Address</td>
<td>#item.Site.MapUrl</td>
<td>#item.Site.Telephone</td>
<td>#item.Site.Email</td>
</tr>
}
</tbody>
</table>
<div class="add_delete_toolbar" />
}
#Html.ListLink("Back to List")
</fieldset>
}
Oh no, you just cannot nest HTML forms. That's not supported. You will have to rethink your design. This really has absolutely nothing to do with ASP.NET MVC and things like Html.BeginForm or Ajax.BeginForm. The HTML specification simply tells you that the <form> tag cannot be nested and if you nest it you will get undefined behavior that could vary between browsers.
For example you could implement the autocomplete functionality using jquery UI autocomplete plugin and get rid of the Ajax.BeginForm.

MVC Model with multiple HttpPostedFileBase properties

I'm using the following model with my get/post actions.
Public Class AuthorEditQuestionViewModel
<Required()>
<Display(Name:="Question Title")>
Public Property Title As String
<Display(Name:="Start Ledger")>
Public Property StartLedger As HttpPostedFileBase
Public Property StartLedgerUrl As String
<Display(Name:="End Ledger")>
Public Property EndLedger As HttpPostedFileBase
Public Property EndLedgerUrl As String
<Required()>
<Display(Name:="Introduction/Instructions")>
Public Property IntroductionHtml As String
End Class
The html for the ledger fields is as follows.
<input type="file" id="StartLedger" name="StartLedger" />
<input type="file" id="EndLedger" name="EndLedger" />
However, in the post action, it seems that both the StartLedger and EndLedger properties seem to be populated with the same value (the first file).
Does anyone have any examples of handling multiple named file upload fields with MVC3? It really feels like supporting file uploads well has been a shortcoming in ASP.Net MVC since version 1.
---- EDIT (.vbhtml below)
#Using Html.BeginForm("EditQuestion", "Author", Nothing, FormMethod.Post, New With {.enctype = "multipart/form-data"})
#Html.ValidationSummary("Please correct the following issues.")
#<table class="form">
<tr>
<td class="label">#Html.LabelFor(Function(m) m.Title)</td>
<td class="input">
#Html.TextBoxFor(Function(m) m.Title)
</td>
</tr>
<tr>
<td class="label">#Html.LabelFor(Function(m) m.StartLedger)</td>
<td class="input">
<input type="file" id="StartLedger" name="StartLedger" />
#If Not String.IsNullOrWhiteSpace(Model.StartLedgerUrl) Then
#Download
End If
</td>
</tr>
<tr>
<td class="label">#Html.LabelFor(Function(m) m.EndLedger)</td>
<td class="input">
<input type="file" id="EndLedger" name="EndLedger" />
#If Not String.IsNullOrWhiteSpace(Model.EndLedgerUrl) Then
#Download
End If
</td>
</tr>
<tr>
<td class="label" colspan="2">#Html.LabelFor(Function(m) m.IntroductionHtml)</td>
</tr>
<tr>
<td class="input" colspan="2">#Html.TextAreaFor(Function(m) m.IntroductionHtml, 10, 80, Nothing)</td>
</tr>
<tr>
<td class="buttons" colspan="2">
<button class="action" data-action="#Url.Action("Index")">Cancel</button>
<button>Save</button>
</td>
</tr>
</table>
End Using
The signature for the action is as follows...
Function EditQuestion(id As Guid?, model As AuthorEditQuestionViewModel) As ActionResult

Categories

Resources