showing each table data row as a Label - c#

I'm having following FinanceProductFeatures table , I want show each of this table record as label name for a form.
So I created model class like this
public class ProductFinanceFeatures
{
public IList<AB_FinanceProductFeatures> ListProductFinanceFields { get; set; }
}
public partial class AB_FinanceProductFeatures
{
public string ProductFinanceNameEn { get; set; }
public string ProductFinance_Value_EN { get; set; }
}
then Controller class like this
[HttpGet]
public ViewResult Financing_Product_Feature_Configuration()
{
var model = new ProductFinanceFeatures
{
ListProductFinanceFields = db.FinanceProductFeatures.ToList()
};
return View(model);
}
then Its viewpage like this
#model albaraka.Models.ProductFinanceFeatures
#{
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#for (int i = 0; i < Model.ListProductFinanceFields.Count; i++)
{
<div class="form-group">
#Html.LabelFor(model => model.ListProductFinanceFields[i].ProductFinanceNameEn, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(m => m.ListProductFinanceFields[i].ProductFinance_Value_EN, new { #row = 5 })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
but here I'm not getting expected result, cannot render the Label
showing like this

Just simply replace TextAreaFor with DisplayFor as below-
<div class="col-md-10">
#Html.DisplayFor(m => m.ListProductFinanceFields[i].ProductFinance_Value_EN, new { #row = 5 })
</div>
Or
<div class="col-md-10">
#Html.DisplayTextFor(m => m.ListProductFinanceFields[i].ProductFinance_Value_EN)
</div>
Hope this works for you..!

Related

How can I set a validationmessage for inputfield binded to entitymodel?

How can i set a validation message on all of these fields? Im not sure how to set it when I bind everything directly to my entitymodel Cancellation? I tried setting a validationmessage directly in my entityclass nut no luck.
This is my razorpage
#page
#model Index
#{
ViewBag.Title = "Index";
}
<div class="body-content">
<form id="avboka-form" method="post">
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-med-5">
<label asp-for="Cancellation.Elev"></label>
<input type="text" id="elev" asp-for="Cancellation.Elev" class="form-control">
<span asp-validation-for="Cancellation.Elev"></span>
</div>
</div>
<div class="form-group">
<div class="col-med-5">
<label asp-for="Cancellation.Dag"></label>
<input asp-for="Cancellation.Dag" type="datetime" id="datepicker" class="datepicker1 form-control">
<span asp-validation-for="Cancellation.Dag"></span>
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => Model.SelectedKommun, htmlAttributes: new { #class = "control-label col-med-2" })
<div class="col-med-5">
#Html.DropDownListFor(x => Model.Cancellation.KommunId, new SelectList(Model.Kommun, "Value", "Text"), htmlAttributes: new { #class = "form-control", id = "kommun" })
#Html.ValidationMessageFor(x => x.SelectedKommun, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => Model.SelectedFordon, htmlAttributes: new { #class = "control-label col-med-2" })
<div class="col-med-5">
#Html.DropDownListFor(x => Model.Cancellation.FordonId, new SelectList(Model.Fordon, "Value", "Text"), htmlAttributes: new { #class = "form-control", #id = "fordon" })
#Html.ValidationMessageFor(x => x.SelectedFordon, "", new { #class = "text-danger" })
</div>
</div>
<div class="col-med-5">
<label asp-for="Cancellation.Skola.Namn"></label>
<select id="skola" name="Cancellation.SkolaId" class="form-control">
#foreach (var schools in Model.School)
{
<option value="#schools.Id">#schools.Namn</option>
}
</select>
<span asp-validation-for="Cancellation.SkolaId"></span>
</div>
<input type="submit" name="save" value="Avboka skolskjuts" class="vt-btn" />
</form>
</div>
Here is part of my pagemodel where i bind my input-fields. The selects is collected from other tables and therefore is never empty.
[BindProperty]
public Avbokning Cancellation { get; set; }
public Index(SqlAvbokningData<Avbokning> avbokningRepo, SqlKommunData<Kommun> kommunRepo, SqlFordonData<Fordon> fordonRepo, SqlSkolaData<Skola> skolaRepo)
{
_avbokningRepo = avbokningRepo;
_kommunRepo = kommunRepo;
_fordonRepo = fordonRepo;
_skolaRepo = skolaRepo;
}
public async Task<IActionResult> OnGet()
{
Kommun = await _kommunRepo.GetKommuner();
Fordon = _fordonRepo.GetFordon();
Municipalities = await _kommunRepo.GetAll();
Vehicle = await _fordonRepo.GetAll();
School = await _skolaRepo.GetAll();
return Page();
}
[ValidateAntiForgeryToken]
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
//if (!Cancellation.Validate())
// return Redirect("/");
await _avbokningRepo.Add(Cancellation);
return Redirect("/Tack");
}
return RedirectToAction("OnGet");
}
Validation in MVC can be done with a viewmodel. You specify your model this way:
public class LogOnViewModel
{
[Required(ErrorMessage = "RequiredField")]
[Display(Name = "Username")]
public string Username { get; set; }
[Required(ErrorMessage = "RequiredField")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
}
Once you get to the web page itself, the ValidationMessageFor will then validate the fields based on the data annotations you have placed on your viewmodel, as you pass that on to the web page.
In the controller you can pass it on to the page by means like this:
var viewModel = new LogOnViewModel();
// do stuff
return View(viewModel);
It's not a perfect example, but this should give some idea of how you can use it.

Bind unknown number of Input elements to model in MVC5

I am fairly new to MVC5 and C# and I am trying to achieve something that I don't fully understand.
I have a Team Model such as this:
public class Team
{
[Key]
public Guid ID { get; set; }
public string TeamName { get; set; }
public string Coach { get; set; }
public string Conference { get; set; }
}
I also have a Player Model such as this:
public class Player
{
[Key]
public Guid Id { get; set; }
[ForeignKey("Teams")]
public Guid TeamId { get; set; }
public string Name { get; set; }
public virtual Team Teams { get; set; }
}
View Model is
public class TeamViewModel
{
public string TeamName { get; set; }
public string Coach { get; set; }
public string Conference { get; set; }
public List<Player> Players { get; set; }
}
With this structure, you are suppose to be able to add and infinite number of players to each team. As such I have a Teams table with few properties and a Player table that contains the player name as well as the player TeamId so that we know to what team they belong.
My problem comes when I am creating a team. I have Create Controller such as this:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(TeamViewModel model)
{
if (ModelState.IsValid)
{
var team = new Team { TeamName = model.TeamName, Coach = model.Coach, Conference = model.Conference, Player = model.Player };
db.Teams.Add(team);
var result = await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View();
}
And my View is as follows:
#model SoccerTeams.Models.ViewModels.TeamViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Team</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.TeamName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TeamName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TeamName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Coach, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Coach, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Coach, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Conference, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Conference, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Conference, "", new { #class = "text-danger" })
</div>
</div>
#if (#Model != null)
{
foreach (var p in Model.Player)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
}
else
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">Player</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
From my understanding, the View is suppose to be able to convert the input element to a list and pass it on to my ViewModel. However, my ViewModel is always coming up as null.
What am I missing and how would I make this work?
P.S. I understand that I can user Html.EditorFor, but I was not able to get it working, so I just printed it out as Html as I need to solve my other problem first.
Edit
I have altered my View to have the following code
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">Player</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"model.Players[0].Name\" type-\"text\"")
</div>
</div>
As a result, the model now properly populates the Players Array, however all other values have now become null. If I remove the input element, the values are populated but players array is null again as there are no form fields for it. Do you know what could be the culprit?
In the TeamViewModel I have also renamed Player to Players.
In order for MVC to bind your form data to the Action method's parameters
their names should match.
Supposing your ViewModel has property for List<Player> Players your code should be:
In your case:
foreach (var p in Model.Player)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
Should be:
for (int i = 0; i < Model.Player.Length; i++)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"model.Player[" + i + "].Name\" type-\"text\"")
</div>
</div>
}
Because this is the name of the parameter that you have provided:
Create(TeamViewModel model)
Also be careful because the indexes should not be broken, which means that they should be 0, 1, 2.. etc. without skipping a number.
The way that we read in the properties is by looking for
parameterName[index].PropertyName. The index must be zero-based and
unbroken.
NOTE You can read more about binding collections in Scott Hanselman's post - here
And last I suggest if you have a property that is list of something - in your case list of Player to use the plural form for the property name - Players.
EDIT
Try removing the "model." in front in the name. Make it like this "Players[0].Name". Since you only have one parameter in your Create Action method it should be fine.
I suggest you to use the helper #Html.EditorFor, so to do this you will create a partial view that will be used as template to inputs of the nested property. see the example:
Shared/EditorTemplates/Player.cshtml
#model Player
<div class="form-group">
#Html.HiddenFor(e => e.Id)
#Html.HiddenFor(e => e.TeamId)
<label class="control-label col-md-2" for="player">Player</label>
<div class="col-md-10">
#Html.TextBoxFor(e => e.Name, new { #class = "form-control text-box single-line", id = "player", name = "Player"})
</div>
</div>
Players form on Team view:
#Html.EditorFor(e => e.Player)
Instead of:
foreach (var p in Model.Player)
{
<div class="form-group">
#Html.Raw("<label class=\"control-label col-md-2\">" + p.ToString() + "</label>")
<div class="col-md-10">
#Html.Raw("<input class=\"form-control text-box single-line\" name=\"Player\" type-\"text\"")
</div>
</div>
}
See this article for more information about editor templates: Editor and display templates

ASP.NET MVC 5 Edit Option for Complex List Child

I have an object called Job and one of the properties is a List of Steps:
public class Job
{
[Display(Name = "Id")]
public int? JobId { get; set; }
[Required]
public string Name { get; set; }
public List<Step> Steps { get; set; }
public Job()
{
Steps = new List<Step>();
}
}
public class Step
{
public int? StepId { get; set; }
public int JobId { get; set; }
[Required]
public string Name { get; set; }
}
I have a JobController with the following action to perform the update:
// PUT: /Job/Edit/5
[HttpPut]
public ActionResult Edit(Job model)
{
// Logic to update model here
}
Based on a the answer to this question I updated my UI (using the Bootstrap template that comes with MVC5) to:
#using (Html.BeginForm())
{
#Html.HttpMethodOverride(HttpVerbs.Put)
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.JobId)
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<h3>Steps</h3>
<div>
#foreach (var item in Model.Steps)
{
<div class="form-group">
#Html.Hidden("Steps[" + stepIndex + "].StepId", item.StepId)
#Html.LabelFor(modelItem => item.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true" data-val-required="The Name field is required."
id="#String.Format("Steps_{0}__Name", stepIndex)" name="#String.Format("Steps[{0}].Name", stepIndex)" type="text" value="#item.Name" />
#Html.ValidationMessageFor(modelItem => item.Name, "", new { #class = "text-danger" })
</div>
</div>
stepIndex += 1;
<hr />
}
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
As you can see I have to manually build the input tag opposed to using Html.EditorFor. The reason is that I need to control name of the id so that it passes the Index into the id and name. I would assume there is a better approach that would allow MVC to render the correct values using labelFor, EditorFor and ValidationMessageFor.
The questions I have are:
Is there a set of controls I can use with MVC5 that allows me to render complex child objects without going through these extra steps?
If no on 1, then is there a better approach than manually create input tag?
Option 1: Replace the foreach loop with for:
#for (int i = 0; i < Model.Steps.Count; i++)
{
<div class="form-group">
#Html.HiddenFor(m => m.Steps[i].StepId)
#Html.TextBoxFor(m => m.Steps[i].Name, new { #class = "form-control text-box single-line" })
...
</div>
}
Option 2: Create an editor template called Step.chtml for the Step class and use EditorFor:
Step.chtml
#model Step
<div class="form-group">
#Html.HiddenFor(m => m.StepId)
#Html.TextBoxFor(m => m.Name, new { #class = "form-control text-box single-line" })
...
</div>
Main View
<h3>Steps</h3>
<div>
#Html.EditorFor(m => m.Steps)
<div>
In both these ways the framework will give the inputs correct names and ids.
Looks like complicated the things, try the below.
1. Create a new editor template (which is a view) named 'Step.cshtml' under the EditorTemplates folder with the model Step.
2. In that do the below code, Step.cshtml
#model Step
<div class="form-group">
#Html.HiddenFor(model => model.StepId)
#Html.LabelFor(modelItem => modelItem.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Name, htmlAttributes: new { #class = "form-control text-box single-line" })
#Html.ValidationMessageFor(modelItem => modelItem.Name, "", new { #class = "text-danger" })
</div>
3. Remove the foreach statement from your view, and instead call the editor template as,
#Html.EditorFor(model => model.Steps)

MVC 4 object with List of objects not returning list of objects

I have a viewmodel that contains a list of another viewmodel. As demonstrated here:
public class PrizeViewModel
{
public Guid PrizeId { get; set; }
public string Description { get; set; }
public List<CategoryViewModel> Categories { get; set; }
}
CategoryViewModel is defined as such:
[Serializable]
public class CategoryViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
The Prize view looks like this:
#model PrizeViewModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Prize</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Categories, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
Create New Category
#Html.EditorFor(model => model.Categories, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
I then have a CategoryEditorTemplate:
#model CategoryViewModel
<div>
<span><input id="#Model.Id" name="#Model.Id" type="checkbox" checked="#(Model.Selected)" value="#Model.Name" /></span>
<label for="#Model.Id">#Model.Name</label>
</div>
The Create method in the controller takes a PrizeViewModel, problem that I am having is that when I get the PrizeViewModel back, Categories is null. Any suggestions?
First, I don't understand how your Category template is supposed to work. You're mixing up your Boolean and id and somehow expecting them to bind... Here's how I think you want it to work.
Change your category editor template to this (it should be called CategoryViewModel.cshtml) The key is that you need to hidden values in order to post them back to the server. And, like Stephen mentions, you were overriding the Editor Template automatic collection naming by not using a helper for your input fields.
#model CategoryViewModel
<div>
#Html.HiddenFor(x => x.Id)
#Html.HiddenFor(x => x.Name)
<Label>#Html.CheckBoxFor(x => x.Selected) #Model.Name</label>
</div>
Your prize view should be fine exactly as you posted it.
Do not. I repeat, do NOT use any form of foreach or for statement with an editor template and collections.
If you loop through categories with for loop when posting to actionresult it will be able to bind model to list here is post about binding model to list
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
here is example of how to make it:
#for(int i = 0; i < Model.Categories.Count(); i++)
{
#Html.EditorFor(model => Model.Categories[i])
}
In your CategoryEditorTemplate, you are overriding the default naming required for correct binding when you do ...name="#Model.Id"...
The html for your categories should look like
<input type="text" name=Categories[0].Name ...
<input type="checkbox" name=Categories[0].Selected...
<input type="text" name=Categories[1].Name ...
....
Either use helpers in your Template, for example
#Html.TextBoxFor(m => m.Name)
#Html.CheckBoxFor(m => m.Selected)
or delete the template and use a for loop to generate the html
#for(int i = 0; i < Model.Categories.Count; i++)
{
#Html.TextBoxFor(m => m.Categories[i].Name)
#Html.CheckBoxFor(m => m.Categories[i].Selected)
}

MVC 4 Model binding a nested model that is used in partial views

I got the following problem, when trying to bind a model in my controller method, the nested model is not bound (input name's do not match, because it's used in a partial view).
Let me illustrate the problem with code samples:
Controller:
public class TestController : Controller
{
public ActionResult Create()
{
var model = new Test2();
model.Basisgegevens.Name = "Test";
model.Basisgegevens.Omschrijving = "Omschrijving";
return View(model);
}
[HttpPost]
public ActionResult Create(Test2 model)
{
return View(model);
}
}
Model:
public class Test
{
public string Name { get; set; }
public string Omschrijving { get; set; }
}
public class Test2
{
public Test2()
{
this.Basisgegevens = new Test();
}
public int PeriodeVanId { get; set; }
public int PeriodeTotId { get; set; }
public Test Basisgegevens { get; set; }
}
View:
#model WebApplication4.Models.Test2
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Test2</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.PeriodeVanId, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PeriodeVanId)
#Html.ValidationMessageFor(model => model.PeriodeVanId)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PeriodeTotId, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PeriodeTotId)
#Html.ValidationMessageFor(model => model.PeriodeTotId)
</div>
</div>
#Html.Partial("~/Views/Test/Partials/Naam.cshtml", Model.Basisgegevens)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Partial view:
#model WebApplication4.Models.Test
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Omschrijving, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Omschrijving)
#Html.ValidationMessageFor(model => model.Omschrijving)
</div>
</div>
The model 'Test' used in the partial view is used by another controller, therefore i cannot changed the input field names (to allow binding).
This is sent to the server:
PeriodeVanId:0
PeriodeTotId:0
Name:Test
Omschrijving:Omschrijving
I want the bottom 2 properties (from the nested model), to be renamed in the model binding at controller level to:
Basisgegevens.Name
Basisgegevens.Omschrijving
That would allow for the binding, and then the model validation to kick in properly.
Does anyone know a solution for this simple model binding problem?
You need to render the partial as an editor. use the following
#Html.EditorFor(model => model.Basisgegevens, "~/Views/Test/Partials/Naam.cshtml")
This will name the inputs correctly so they should bind. Basically it tells razor that the partial is part of the form not unrelated content
For me it works when I use Html.EditorFor and I move partial view under folder EditorTemplates.
There are 2 options where you need to create folder EditorTemplates:
under particular view
or in share folder.
Tested on MVC 5 app.

Categories

Resources