MVC 5 Razor view not binding bool to input - c#

I have a razor view (Framework 4.5, MVC 5) and an html input type=checkbox with the value equal to a model boolean value but instead of true or false it binds "value".
This is my code:
for (int index = 0; index < Model.Item1.Locations.Length; index++)
{
WSTupleOfInt32StringStringBoolean location = Model.Item1.Locations[index];
<div class="editor-field">
<input id="#string.Format("presentation.ServiceInfoes[{1}].Locations[{0}].Key", index, Model.Item2)" type="checkbox" value="#location.ThirdValue" name="#string.Format("presentation.ServiceInfoes[{1}].Locations[{0}].ThirdValue", index, Model.Item2)" />
</div>
<div class="editor-label">
<label for="#string.Format("presentation.ServiceInfoes[{1}].Locations[{0}].Key", index, Model.Item2)">#location.FirstValue</label>
#if (!string.IsNullOrEmpty(location.SecondValue))
{
<img alt="#location.SecondValue" src="#string.Format("//maps.google.com/maps/api/staticmap?center={0}&markers=color:blue|{0}&zoom=15&size=64x64&sensor=false", location.SecondValue)" />
}
</div><br />
}
The location.ThirdValue is the boolean property, debuging the property it's fine.. but in the HTML i get value="value" and not value="false".
What's happening?

See this Answer
Basically you want to use HTML.CheckBoxFor(model => model.booleanProperty)

Do this
<input id="#string.Format("presentation.ServiceInfoes[{1}].Locations[{0}].Key", index, Model.Item2)" type="checkbox" #(location.ThirdValue ? "checked" : "") name="#string.Format("presentation.ServiceInfoes[{1}].Locations[{0}].ThirdValue", index, Model.Item2)" />
The value is not setting checkbox to be checked or not, value has different function. For example if you set value to 'test' and check the checkbox, when you submit the form, you will see that instead of true value of submitted variable will be 'test';
you can do pretty cool stuff with it. For example you have 3 checkboxes on your form. all of them have the same name, but different values. when you submit the form, the result you get will be comma-separated string with values of checked checkboxes;

Related

asp-for in ASP NET Core send checkbox value and false even if checkbox is checked

I have a simple .cshtml page:
<form asp-controller="SomeController" asp-action="SomeAction">
#for(int i = 0; i < info.Length; i++)
{
<input type="checkbox" value="#info[i].Name" asp-for="Accepted[i]" checked /> <strong>#info[i].Name</strong>
<br />
}
<button type="submit">Some button</button>
</form>
And when I submit this form I would like to have FormData like it:
info[0]: some-data
info[1]: another-data
And I have it in my FormData, but some useless data is added to my FormData that looks like it:
info[0]: false
info[1]: false
What's more, its setted to false even if checkboxes are checked (when checkboxes are unchecked, they aren't contained in FormData and this useless data also isn't contained).
Why is this happening? Can I remove it while I want to use tag helpers?
In your code, You use index to bind value in Accepted, So even you don't bind any value in this index, It will also show default value. You can change type to string[] and use name='Accepted' to bind value directly.
public class ListModel
{
public List<string> info { get; set; } = new List<string>();
public string[] Accepted { get; set; }
}
<form method="post">
#for (int i = 0; i < Model.info.Count; i++)
{
<input type="checkbox" value="#Model.info[i]" name="Accepted" checked /> <strong>#Model.info[i]</strong>
<br />
}
<button type="submit">Some button</button>
</form>
Here you can see it will not bind false value.

List hidden value passes wrong value to controller

I have a list In my view. For each row, I view button and I am passing Id value as hidden. But when I click any button it is passing wrong hidden value to the controller. Always it passes the first-row hidden value to the controller.
View:
#foreach (var list in Model)
{
<div>
<div > #( ((int)1) + #Model.IndexOf(list)).</div>
<div >#list.details</div>
<div class="col-md-2 row-index">
<button class="btn btn-link" type="submit" name="action:view" id="view">View</button>
<input type="hidden" name="viewId" id="viewId" value="list.WId" />
</div>
</div>
}
Controller:
[HttpPost]
[MultipleButton(Name = "action", Argument = "view")]
public ActionResult ViewDetail(string viewId)
{
return RedirectToAction("ViewDetails");
}
To get all values you need to change the input value type in your controller to array of strings.
I hope that this solution can help you
[HttpPost]
[MultipleButton(Name = "action", Argument = "view")]
public ActionResult ViewDetail(string[] viewId)
{
return RedirectToAction("ViewDetails");
}
if you want to get the exact value you need to duplicate the form within your foreach
in this case you should write somthing like this :
#foreach (var list in Model)
{
<div>
<div > #( ((int)1) + #Model.IndexOf(list)).</div>
<div >#list.details</div>
<div class="col-md-2 row-index">
<form ... > // complete your form attributes
<button class="btn btn-link" type="submit" name="action:view" id="view">View</button>
<input type="hidden" name="viewId" id="viewId" value="list.WId" />
</form>
</div>
</div>
}
Note : You should delete the global form
You should have one form for each row. then you submit that row.
Otherwise as you state it passes first value.
You are setting each value to the same element ID (which is invalid anyway) and name. When you submit your form (which would be more helpful to fully answer your question) it is finding the first element that matches that criteria and submitting it.
There are multiple ways to resolve this such as the already mentioned form per entry but the other preference would be to modify you button to a div and add a click handler to pass the specific value to a js function which would then submit to the controller. Its a preference choice regarding how tightly coupled you want your front end. But the main problem is your element naming convention.

.net core 2 form input form tag helper for bool type not generating checkbox

I have a model which has a boolean property. In the edit view it displays as a text field of type text which I don't understand. In the documentation it states that a boolean input should display a checkbox for the type.
Model:
public class Person
{ ...
public bool? boolprop {get; set;}
}
Edit.cshtml:
{ ...
<div class="form-group">
<label asp-for="boolprop" class="control-label"></label>
<input asp-for="boolprop" class="form-control" />
<span asp-validation-for="boolprop" class="text-danger"></span>
</div>
}
Generated html:
<input class="form-control" type="text" id="boolprop" name="boolprop" value="True">
Any ideas how you can get a checkbox to display with the input tag helper?
You can get a tri-state list (not set, true, false) by doing this instead:
Html.InputFor(x=>x.boolprop)
A nullable boolean (bool?) and a boolean are not the same thing, of course. I agree the tag-helper output isn't especially intuitive, but Microsoft has said this is by design:
https://github.com/aspnet/Mvc/issues/5667#issuecomment-271394567
It's by design.
Imagine for example what it would mean for a bool? property to result in a checkbox . How could a user choose null when they submit a form?

Multiple forms created using for loops each with a submit button only first form data posts on submit [duplicate]

I have the following code, only the first form submits anything, the following submit null values, each model has data. If I change it to just one large form, everything submits. Why do the other individual forms post null values?
View
#model myModel[]
<ul>
#for (int i = 0; i < Model.Length; i++)
{
using (Html.BeginForm("controllerAction", "Controller", FormMethod.Post,
new { id="Form"+i }))
{
<li>
#Html.TextBoxFor(a => a[i].property1)
#Html.CheckBoxFor(a => a[i].property2)
#Html.HiddenFor(a => a[i].property3)
<input type="submit" />
</li>
}
}
</ul>
Controller
[HttpPost]
public ActionResult controllerAction(myModel[] models)
{
...do stuff...
}
The reason is that your creating form controls with indexers in your for loop, and your POST method parameter is myModel[] models.
By default, the DefaultModelBinder requires collection to be zero based and consecutive, so if you attempt to submit the second form, your posting back [1].property1: someValue etc. Because the indexer starts at 1, binding fails and the model is null.
You can solve this by adding a hidden input for an Index property used by the model binder to match up non consecutive indexers
<li>
#Html.TextBoxFor(a => a[i].property1)
#Html.CheckBoxFor(a => a[i].property2)
#Html.HiddenFor(a => a[i].property3)
<input type="hidden" name="Index" value="#i" /> // add this
<input type="submit" />
</li>

Trying to Dynamically Bind my "ng-true-value" in Angularjs

I am loading some values from a database and what I'm trying to do here is have a checkbox, load the description and then have 2 text boxes, the first is editable, and the second is readonly.
Both text boxes start with the values loaded from the database, then when the checkbox is checked, the value from the editable text box appears in the readonly text box, when it is unchecked, the readonly checkbox value is 0.
<div ng-if="condition.ConditionDesc == 'Other'">
<div class="col-sm-1 unpad" ><input type="checkbox" id=OtherCheckbox" ng-disabled="condition.Score_Potential.$invalid && condition.Score_Potential.$invalid" ng-model="condition.ConditionExists" ng-true-value="{{condition.Score_Potential}}" ng-false-value="0"/></div>
<div class="col-sm-2 unpad">{{ condition.ConditionDesc }} </div>
<div class="col-sm-5 unpad"><textarea id="OtherText" cols="30" placeholder="Please Specify." rows="1"></textarea></div>
<div class="col-sm-2"><input type="text" id="" name="" ng-model="condition.Score_Potential" class="form-control" format="number" required /></div>
<div class="col-sm-2"><input type="text" id="" name="" ng-model="condition.ConditionExists" class="form-control" readonly="readonly" format="number" required /></div>
</div>
Whenever I type a number in the editable textbox and then check my checkbox, it only puts the original value of the editable textbox into the readonly textbox. Any ideas of how to fix this?
You can solve this with some basic pre-processing and post-processing of model data:
Remove ng-true-value and ng-false-value, replace the model with a temporary model, and add a controller:
<input type="checkbox" id=OtherCheckbox"
ng-disabled="condition.Score_Potential.$invalid && condition.Score_Potential.$invalid"
ng-model="condition.conditionChecked"
ng-controller="CheckboxController" />
Controller that sets a temporary model value that is not affected by Score_Potential changes:
var cond = $scope.condition
yourApp.controller('CheckboxController', ['$scope', function($scope) {
$scope.$watch('condition.ConditionExists', function(conditionExistsValue) {
cond.conditionChecked = (conditionExistsValue === cond.Score_Potential);
}
}]);
When saving: conditionally set the value of ConditionExists to Score_Potential based on our temporary model value:
var cond = $scope.condition
cond.ConditionExists = cond.conditionChecked ? cond.Score_Potential : 0;

Categories