How to bind the value to input field to a control by using ternary operator check - asp.net-mvc-4

I have some input controls where I am trying to bind the value by checking for null which doesn't worked
<input id="LastKnownLatitudeDegree" name="VesselMissing.LastKnownLatitudeDegree" value="#Model.VesselMissing != null ? #Model.VesselMissing.LastKnownLatitudeDegree : ''" class="form-control" max="89" min="0" step="1" type="number" data-dec="0"><span>°</span>
If I am using a null check on top of the control it is not getting visible to the user to enter the data
#if (#Model.VesselMissing != null)
{
<input id="LastKnownLatitudeDegree" name="VesselMissing.LastKnownLatitudeDegree" value="#Model.VesselMissing.LastKnownLatitudeDegree" class="form-control" max="89" min="0" step="1" type="number" data-dec="0"><span>°</span>
}
I have some bunch of controls like this where I need to bind the value field. There is an other method which I tried out is working but I would like to know if there is a possibility to do as per the first statement
This works but I have some 20 controls so I am considering to make it work as per the first statemet
#{
string LastKnownLatitudeDegree = string.Empty;
if(Model.VesselMissing !=null)
{
LastKnownLatitudeDegree = Model.VesselMissing.LastKnownLatitudeDegree;
}
}
<input id="LastKnownLatitudeDegree" name="VesselMissing.LastKnownLatitudeDegree" value="#LastKnownLatitudeDegree class="form-control" max="89" min="0" step="1" type="number" data-dec="0"><span>°</span>

In both cases you have syntax error.
<input id="LastKnownLatitudeDegree" name="VesselMissing.LastKnownLatitudeDegree"
value="#(Model.VesselMissing != null ? Model.VesselMissing.LastKnownLatitudeDegree : "")" />
or
#if (Model.VesselMissing != null)
{
<input id="LastKnownLatitudeDegree" name="VesselMissing.LastKnownLatitudeDegree" value="#Model.VesselMissing.LastKnownLatitudeDegree" class="form-control" max="89" min="0" step="1" type="number" data-dec="0"><span>°</span>
}

Related

.NetCore - Model Binding with MultipleViews/BindPoperty

I'm trying to use Model Binding on two properties, both of them with BindProperty to an IList.
I will Have X Cells, then for each selected cell (a bool in Cell Object), I have 1 Reference. So in a pratical example I have 21 Cells, 3 of them are selected, so I must select 1 Reference for each of those selected Cells. All good until here, but when entering my Post Handler The ILists in which I'm storing are merging up, in other words, data is storing in the same IList. So, when SelectedCells and SelectedReferences(see below) should have 21 and 3 objects respectively, they have both 21 and the properties with the same name (e.g Id) get overwritten.
If the Views are associated to both the different view models, shouldn't the IList's be recognized as different?
[BindProperty]
public IList<CellViewModel> SelectedCells { get; set; }
//Was trying to play with ModelBinder type to force them to be treated as different types, unsuccessfully
//[ModelBinder(BinderType =(typeof(ReferenceViewModel)))]
[BindProperty]
public IList<ReferenceViewModel> SelectedReferences { get; set; }
Views
Cells
#model IList<NoPaper.ViewModels.CellViewModel>
<if include-if="Model.Count == 0">
<alert type="Warning">
Não existem células nesta unidade de produção
</alert>
</if>
<if include-if="Model.Count > 0">
<div class="list-group list-group-horizontal row">
#for (int i = 0; i < Model.Count(); i++)
{
<if include-if='Model[i].CellCategoryDescription == "Célula Robot" '>
<div class="list-group-item list-group-item-action text-center col-md-2" style="cursor:pointer;">
<input type="hidden" class="cell-value" asp-for="#Model[i].Id" />
<input type="hidden" class="cell" asp-for="#Model[i].IsSelected" />
#Model[i].Name<text style="font-weight:bold;">(R)</text>
</div>
</if>
<if include-if='Model[i].CellCategoryDescription == "Célula Manual" '>
<div class="list-group-item list-group-item-action text-center col-md-2" style="cursor:pointer;">
<input type="hidden" class="cell-value" asp-for="#Model[i].Id" />
<input type="hidden" class="cell" asp-for="#Model[i].IsSelected" />
#Model[i].Name<text style="font-weight:bold;">(M)</text>
</div>
</if>
}
</div>
</if>
References
#model IList<NoPaper.ViewModels.ReferenceViewModel>
<if include-if="Model.Count == 0">
<alert type="Warning">
Não existem referências nesta unidade de produção
</alert>
</if>
<if include-if="Model.Count > 0">
<div class="justify-content-center">
#for (int i = 0; i < Model.Count(); i++)
{
<div class="form-row">
<div class="form-group ">
<text>#Model[i].CellId</text>
<label asp-for="#Model[i].myId"></label>
<select asp-for="#Model[i].myId" asp-items="Model[i].ReferencesSL" class="custom-select">
<option value="">--</option>
</select>
<span asp-validation-for="#Model[i].myId" class="text-danger"></span>
</div>
</div>
}
</div>
</if>
You can try to add name attribute to your input,.net core bind data with name attribute.For example,if you want to bind SelectedCells:
<input type="hidden" class="cell-value" asp-for="#Model[i].Id" name="SelectedCells[#i].Id"/>
if you want to bind SelectedReferences:
<input type="hidden" class="cell-value" asp-for="#Model[i].Id" name="SelectedReferences[#i].Id"/>

ASP .Net MVC Core binds wrong value in model list

I have a model with the following
- ModelData: List<ModelData>
With ModelData has the following:
- Name (string)
- LanguageId: Guid
And ViewBag has the following:
- Languages: IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem>
And the view has the following:
#for (int i = 0; i < Model.ModelData.Count; i++)
{
<div class="row">
<div class="form-group">
<label asp-for="ModelData[i].LanguageId" class="control-label"></label>
<select asp-for="ModelData[i].LanguageId" asp-items="#ViewBag.Languages" class="form-control">
</select>
<span asp-validation-for="ModelData[i].LanguageId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ModelData[i].Name" class="control-label"></label>
<input asp-for="ModelData[i].Name" class="form-control" />
<span asp-validation-for="ModelData[i].Name" class="text-danger"></span>
</div>
#if (i > 0)
{
<div class="col-md-4">
<div class="form-group">
<button name="RemoveDataItem" value="#i.ToString()" class="btn btn-primary">Remove</button>
</div>
</div>
}
</div>
}
<input type="submit" name="AddDataItem" value="Add Item" class="btn btn-primary" />
<input type="submit" value="Create" class="btn btn-primary" />
And the controller as the following:
public async Task<IActionResult> CreateAsync(CreateModel model, string addDataItem, string removeDataItem)
{
if (addDataItem != null)
{
await FillViewBag();
model.ModelData.Add(new ModelData());
return View(model);
}
else if (removeDataItem != null)
{
await FillViewBag();
int itemIndex = int.Parse(removeDataItem);
model.ModelData.RemoveAt(itemIndex);
return View(model);
}
if (!ModelState.IsValid)
{
await FillViewBag();
return View(model);
}
// Save
}
And it works great, however I have a problem as the following:
Let's say i pressed the add button two times so now I have three records on ModelData and I entered a value in all textboxes and selected values in all select list, then I pressed remove next to the second row, so it goes to the controller action, the method removes the data of the correct index, and returns to the view, so Now I should find two rows, first with the data that was entered in the first row, and second with the data that was entered in the third row (because the second row is removed), however, what actually happens is that I end up with the data of the first two rows not the first and the third.
Any help is appreciated considering I did the following:
I validated that the item that is removed is the corect one (the second item), but the value is not bound correctly.
I added this attribute to the textbox value="#Model.ModelData[i].Name", and it worked correctly but I think this is not the correct way to solve this issue, also I did not find a similar attribute for the select tag.
Edit:
I also managed to add static Id for the input fields of each row, but it didn't help
Edit:
The problem is that the index is changed after the second row is removed, so the index of the third row (originally was 2) became 1 after removing the second row, and thus it now has the previous name attribute of second row "ModelData[1].Name" and not "ModelData[2].Name" and I think this is the problem which makes the browser keeps the previous value of the second row
For anyone who is concerned, I found the solution to this issue which is to add the following line before returning the view:
ModelState.Clear();
add index value to each item:
<input type="hidden" name="ModelData.index" value="#i">
update your view code like this:
#for (int i = 0; i < Model.ModelData.Count; i++)
{
<div class="row">
<input type="hidden" name="ModelData.index" value="#i">
<div class="form-group">
<label asp-for="ModelData[i].LanguageId" class="control-label"></label>
<select asp-for="ModelData[i].LanguageId" asp-items="#ViewBag.Languages" class="form-control">
</select>
<span asp-validation-for="ModelData[i].LanguageId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ModelData[i].Name" class="control-label"></label>
<input asp-for="ModelData[i].Name" class="form-control" />
<span asp-validation-for="ModelData[i].Name" class="text-danger"></span>
</div>
#if (i > 0)
{
<div class="col-md-4">
<div class="form-group">
<button name="RemoveDataItem" value="#i.ToString()" class="btn btn-primary">Remove</button>
</div>
</div>
}
</div>
}
Where's your source data? What you have done is just change the model parmeter.
Also, I can reproduce your problem, when I directly return View after remove the specify record. It can be fixed by using RedirectToAction
I made a demo based on your codes, you can refer to the below codes:
Controller:
public static CreateModel createModel = new CreateModel
{
ModelDatas = new List<ModelData>
{
new ModelData{ LanguageId = 1, Name = "a"},
new ModelData{ LanguageId = 2, Name = "b"},
new ModelData{ LanguageId = 3, Name = "c"}
}
};
public IActionResult Create()
{
FillViewBag();
return View(createModel);
}
[HttpPost]
public IActionResult Create(CreateModel model, string addDataItem, string removeDataItem)
{
if (addDataItem != null)
{
FillViewBag();
createModel.ModelDatas.Add(new ModelData());
return RedirectToAction("Create");
}
else if (removeDataItem != null)
{
FillViewBag();
int itemIndex = int.Parse(removeDataItem);
createModel.ModelDatas.RemoveAt(itemIndex);
return RedirectToAction("Create");
}
if (!ModelState.IsValid)
{
FillViewBag();
return RedirectToAction("Create");
}
return View();
}
View:
#model CreateModel
<form asp-action="Create" asp-controller="Test" method="post">
#for (int i = 0; i < Model.ModelDatas.Count; i++)
{
<div class="row">
<div class="form-group">
<label asp-for="ModelDatas[i].LanguageId" class="control-label"></label>
<select asp-for="ModelDatas[i].LanguageId" asp-items="#ViewBag.Languages" class="form-control">
</select>
<span asp-validation-for="ModelDatas[i].LanguageId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ModelDatas[i].Name" class="control-label"></label>
<input asp-for="ModelDatas[i].Name" class="form-control" />
<span asp-validation-for="ModelDatas[i].Name" class="text-danger"></span>
</div>
#if (i >= 0)
{
<div class="col-md-4">
<div class="form-group">
<button name="RemoveDataItem" value="#i.ToString()" class="btn btn-primary">Remove</button>
</div>
</div>
}
</div>
}
<input type="submit" name="AddDataItem" value="Add Item" class="btn btn-primary" />
<input type="submit" value="Create" class="btn btn-primary" />
</form>
Result:

ASP.NET Core Razor: Conditional attribute without value

I want to conditionally render a readonly attribute in an <input>. In the ASP.NET Core dialect of Razor the interpretation of attributes is a little different opposed to System.Web.Mvc.
In System.Web.Mvc I used to do:
<input name="Name" class="form-control" #(Model.MyCondition ? "readonly" : "") />
In ASP.NET Core, the same does not work: no error, but the attribute isn't rendered either.
<input asp-for="Name" class="form-control" #(Model.MyCondition ? "readonly" : "" ) />
Once the attribute is present in the HTML it is enforced, so I cannot do something with the value of the attribute. This snippet would cause the input to always be read-only:
<input asp-for="Name" class="form-control" readonly="#(Model.MyCondition ? "readonly" : "" )" />
Now, I can work around by creating a tag helper that would respond to the is-readonly tag, but that seems very convoluted for something so simple.
How do I conditionally render a no-value attribute without resorting to a custom tag helper?
If you set the value to null when your condition isn't matched (instead of an empty string) then the attribute will not be rendered, as follows:
<input asp-for="Name" class="form-control" readonly="#(Model.MyCondition ? "readonly" : null )" />
#{
var htmlAttributes = (MyModel.MyCondition == true) ? (object)new
{
##readonly = "readonly"
} : null;
}
#Html.TextBoxFor(m => m.Nom, htmlAttributes)
What I do is create an #if statement. I find it more transparent.
#if (Model.MyCondition)
{
<input asp-for="Name" class="form-control" readonly="readonly" />
}
else
{
<input asp-for="Name" class="form-control" />
}

how to control input value be integer in reactive form

<input
#valueRef
tabindex="1"
type="number"
step="1"
name="value"
id="value"
placeholder="Enter value"
class="form-control"
formControlName="value"
[ngClass]="{ 'is-invalid': submitted && adjForm.controls['value'].errors && !this.data.isAdjAccount }"
/>
I set input step as 1, but it still supports to input decimal, what I want to show is: when you open this from, and enter value in this input box, it forbids user to enter decimals, only integer is valid.
Try this
<input type="text" class="form-control" placeholder="Enter value" id="txtvalueRef" name="valueRef" #valueRef="ngModel" pattern="[0-9]*">
<div [hidden]="valueRef.valid || valueRef.pristine" class="alert alert-danger">
<div [hidden]="!valueRef.hasError('pattern')">Items should be only numbers</div>
</div>

Based on If condition I want make the field as required in angular2

<div *ngFor="let proc of procInputList" >
<label >{{proc.key_ | Capitalize}}</label>
<input id="{{proc.key_}}" name="inputparams" type ="text" class="form-control" required = "proc.r_q == Y ? required :none" />
</div>
But unfortunately its not working for me..and I don't want to use forms there.
To condition an attibute you can:
<input class="form-control" [required] = "proc.r_q == 'Y'" />