A property of model becomes null while posting - asp.net-mvc-4

I'm new to MVC. Now I'm trying with a simple demo of MVC that to print Customer's information to screen and update it, send back to database.
I have no idea why the Customer's ID becomes null while the others are fine.
I want to display Customer's ID to the screen but I don't want user to edit it to post to my database. I've been researching this for some hours now..
my code :
Customer.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace PeopleManagement.Models
{
public class Customer
{
[Required]
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Customer()
{
}
public Customer(string id, string name, int age)
{
Id = id;
this.Name = name;
this.Age = age;
}
}
}
Index.cshtml
#using System.Web.UI.WebControls
#using PeopleManagement.Models
#model IList<Customer>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>First MVC Application</title>
<link href="#Url.Content("~/Content/css/customized-table.css")" rel="stylesheet" type="text/css" />
</head>
<body style="max-width:100%; max-height:100%">
<div id="pageTitle" style="text-align:center; color:red; font-size:24px; font-weight:bold;">Customer Management</div>
#using (#Html.BeginForm("Index", "Home", FormMethod.Post))
{
<div id="tablePanel" style="padding-top: 15px">
<table class="customized_table" border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
#{
for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(model => model[i].Name);
</td>
<td>
#Html.TextBoxFor(model => model[i].Name, new {#style = "min-width:100%; text-align:center", #disable = "true"})
</td>
<td>
#Html.TextBoxFor(model => model[i].Age)
</td>
</tr>
}
}
</table>
</div>
<div>
<p><input type="submit"/></p>
</div>
}
</body>
</html>
<script>
</script>
HomeController.cs
using System.Collections.Generic;
using System.Web.Mvc;
using PeopleManagement.Models;
namespace PeopleManagement.Controllers
{
public class HomeController : Controller
{
public List<Customer> CustomersList { get; private set; } = new List<Customer>(5);
[HttpGet]
public ActionResult Index()
{
CustomersList.Add(new Customer("ID_1", "Name_1", 1));
CustomersList.Add(new Customer("ID_2", "Name_2", 2));
CustomersList.Add(new Customer("ID_3", "Name_3", 3));
ModelState.Clear();
return View(CustomersList);
}
[HttpPost]
public ActionResult Index(List<Customer> postbackCustomers)
{
if (!ModelState.IsValid)
return View(CustomersList);
CustomersList = postbackCustomers;
return View(CustomersList);
}
}
}
Can anyone help ?

In MVC if you want to get some value back from view you have to have that value in the view first. It seems you have not inputted the Id in the view.
Change your view code like this,
for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(model => model[i].Id)
</td>
<td>
#Html.TextBoxFor(model => model[i].Name, new { #style = "min-width:100%; text-align:center", #disable = "true" })
</td>
<td>
#Html.TextBoxFor(model => model[i].Age)
</td>
</tr>
}
Hope this helps!!

Actually you are not showing the ID on the index.html view, The customer ID has value in your example. You should try to show it in read only mode in the for each loop.
#Html.DisplayFor(model => model[i].Id)

Related

Mvc 4 model binding not working dynamically added partial view

I am trying to create a form where in user can add controls. I have main view
#model MVCDynamicFormGenerator.Models.FormViewModel
#{
ViewBag.Title = "Create";
}
#using (#Html.BeginForm())
{
<fieldset>
#Html.HiddenFor(form => form.Form.Uid)
#Html.Hidden("ListFields", ViewData["ListFields"])
<p>
#Html.LabelFor(form => form.Form.FormName)
#Html.TextBoxFor(form => form.Form.FormName)
</p>
<div id="FormFieldList">
#foreach (var formfield in Model.FormFields)
{
switch (formfield.ControlType)
{
case ("Textbox"):
Html.RenderPartial("Textbox", formfield);
break;
}
}
</div>
<h4>
[+] Add a Field
</h4>
<div id="FieldType">
<table>
<tr>
<th>
Select a Field Type
</th>
</tr>
<tr>
<td>
#Html.DropDownList("FieldTypes", new SelectList(Model.FormFields[0].FormFieldTypes, "Value", "Text"), new { id = "SelectedFieldUid" })
#Html.ActionLink("Add Field", "NewFormField", new { formId = ViewContext.FormContext.FormId, selectedFieldType = "SelectedFieldUid" }, new { id = "newFormField" })
#Html.ValidationMessageFor(model => model.FormFields)
</td>
</tr>
</table>
</div>
<p>
<input type="submit" value="Create" />
<input type="button" value="Cancel" '#Url.Action("List")');" />
</p>
</fieldset>
}
On dropdown change I am loading a partial view which is working(User can add n number of times)
#model MVCDynamicFormGenerator.Models.FormFieldViewModel
<div class="FormField">
#using (#Html.BeginForm())
{
<table>
<tr>
<th>
Form Field
</th>
<th>
Field Type
</th>
</tr>
<tr>
<td style="width: 45%;">
#Html.TextBoxFor(formfield => formfield.FormFieldName)
#Html.ValidationMessageFor(formfield => formfield.FormFieldName)
</td>
<td style="width: 25%;">
#Html.DropDownListFor(formfield => formfield.SelectedFormFieldType,
new SelectList(Model.FormFieldTypes, "Value", "Text",
Model.SelectedFormFieldType),
new { disabled = "disabled" })
#Html.HiddenFor(formfield => formfield.SelectedFormFieldType)
#Html.ValidationMessageFor(formfield => formfield.SelectedFormFieldType)
</td>
</tr>
</table>
}
</div>
/// form models
public class FormViewModel
{
//Properties
public Form Form { get; set; }
public List<FormFieldViewModel> FormFields { get; set; }
//Constructor
public FormViewModel()
{
Form = new Form();
FormFields = new List<FormFieldViewModel>();
}
}
public class FormFieldViewModel
{
public string FormFieldName { get; set; }
public string SelectedFormFieldType { get; set; }
}
controller methods
[HttpPost]
public ActionResult Create(FormViewModel viewModel)
{
return View();
}
All the field information related to main view gets available but FormFieldViewModel list gives zero count
Any help or suggestion to fix this

Modelmetadata additional values always empty MVC4

I have the below property in my model:
[Required]
[UIHint("DropDownList")]
[AdditionalMetadata("Source", "Party.Organization.Caption")]
public int PartyId { get; set; }
I am trying to get the additional metadata value in view as follows:
object s = ViewData.ModelMetadata.AdditionalValues["Source"];
but it is always returning count 0.
not sure, why, can somebody advise pls?
complete view:
#model IEnumerable<object>
#using System.Reflection;
#using r2d2Web.Extensions;
#using d2Utils.Extensions.d2Type;
#using d2Utils.Reflection;
#using System.Collections;
#{
Type mdlType = Model.First().GetType();
PropertyInfo keyProp = mdlType.GetKeyProperty();
IEnumerable<PropertyInfo> props = mdlType.EditorProps();
Hashtable parties = (Hashtable)ViewData["Parties"];
Hashtable partyroles = (Hashtable)ViewData["Partyroles"];
}
<div class="grid">
<table>
<thead>
<tr>
#foreach (var prop in props)
{
<th>#prop.Name</th>
}
<th></th>
</tr>
</thead>
<tbody>
#foreach (var obj in Model)
{
<tr>
#foreach (var prop in props)
{
if (prop.Name == "PartyId")
{
object s = ViewData.ModelMetadata.AdditionalValues["Source"];
<td>#(obj.GetValForProp<string>(s.ToString()))</td>
}
else if (prop.Name == "PartyRoleTypeId")
{
<td>#partyroles[obj.GetValForProp<int>(prop.Name)]</td>
}
else
{
<td>#(obj.GetValForProp<string>(prop.Name))</td>
}
}
<td>
#Html.ActionLink("Edit", "Edit", new { id = obj.GetValForProp<int>(keyProp.Name) }) |
</td>
</tr>
}
</tbody>
</table>
</div>
<div id="my-dialog"></div>
You are not specifying field for getting additional metadata. Try to do it like this:
#ViewData.ModelMetadata.Properties.FirstOrDefault(n => n.PropertyName == "PartyId").AdditionalValues["Source"]
If you had strongly typed view model with type that contains PartyId better option would be to use
#ModelMetadata.FromLambdaExpression(x => x.PartyId, ViewData).AdditionalValues["Source"]

My list will be empty when POST the form

I have some problem with the MVC, I'll try to describe. I have 2 class in my model.
public class ApplicationPermissionVM
{
public ApplicationPermission Permission { get; set; }
public bool IsSelected { get; set; }
}
public class RoleAndPermissonsModel
{
//Constructor skipped
public ApplicationRole ApplicationRole { get; set; }
public IEnumerable<ApplicationPermissionVM> Permissions { get; set; }
}
The second model is the main model, and I initialize the model in controller. The ApplicationRole is null and I have got 19 element in the list. When I POST the form the ApplicationRole member will be created, but the Permissions list will be empty so will lost all selection. If anyone knows what is the problem please write to me.
Controller:
[HttpGet]
public ActionResult NewRole()
{
_model = new RoleAndPermissonsModel();
return View(_model);
}
[HttpPost]
public ActionResult NewRole(RoleAndPermissonsModel newRole)
{
if (ModelState.IsValid)
{
var id = _applicationRoleService.AddNewRole(newRole.ApplicationRole);
_applicationRoleService.AssignPermissionsToRole(newRole.SelectedItems, id);
}
return RedirectToAction("Index");
}
View:
#model EO.Core.WebUI.Models.RoleAndPermissonsModel
#using (Html.BeginForm("NewRole", "PermissionRole", FormMethod.Post, new { id = "frmNewRole" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ApplicationRole</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ApplicationRole.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ApplicationRole.Name)
#Html.ValidationMessageFor(model => model.ApplicationRole.Name)
</div>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.IsSelected)
</th>
<th></th>
</tr>
#foreach (var item in Model.Permissions)
{
<tr>
<td>
#Html.EditorFor(modelItem => item.IsSelected)
</td>
<td>
#Html.DisplayFor(modelItem => item.Permission.Name);
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
you need manually to loop through the list and output it like
<input type="text"
id="Permissions[0].IsSelected"
name="Permissions[0].IsSelected" value="" />
so, change your code to:
#for(int i = 0; i < Model.Permissions.Count; i++)
{
<tr>
<td><input type="checkbox"
id="Permissions[#(i)].IsSelected"
name="Permissions[#(i)].IsSelected" /></td>
<td><input type="text"
id="Permissions[#(i)].Permission.Name"
name="Permissions[#(i)].Permission.Name" /></td>
</tr>
}
because you have an object inside your type Permissions remember to initialiate it or you will get a null reference.
public class RoleAndPermissonsModel
{
public RoleAndPermissonsModel() {
this.Permissions = new List<ApplicationPermissionVM>();
}
public ApplicationRole ApplicationRole { get; set; }
public IEnumerable<ApplicationPermissionVM> Permissions { get; set; }
}
or you can easily create a ViewModel instead and use that to interlink your Model to your View.
Note: I do wonder, if your list is always null (as you are passing an empty/null list) why are you looping through Model.Permissions ?
In order to do the "EDIT" view, the loop code should be:
#for(int i = 0; i < Model.Permissions.Count; i++)
{
<tr>
<td><input type="checkbox"
#(Permissions[i].IsSelected ? "checked='checked'" : "")
id="Permissions[#(i)].IsSelected"
name="Permissions[#(i)].IsSelected" /></td>
<td><input type="text"
id="Permissions[#(i)].Permission.Name"
name="Permissions[#(i)].Permission.Name"
value="#(Permissions[i].Permission.Name)" /></td>
</tr>
}
all you need to add is checked to the checkbox if it's selected and fill the permission name to the other input.

Postback checkboxes from table rows on MVC Razor Strongly Typed View

I have strongly typed view showing data from
ViewModel
public class GoldSetnUsers
{
bool Public { get; set; }
public List<GSUsers> gsUsers { get; set; }
public GoldSetnUsers()
{
UsersContext _dbm = new UsersContext();
this.gsUsers = _dbm.UserProfiles.Select(n => new GSUsers { UserName = n.UserName, isEditor = false, isReviewer = false }).ToList();
}
public class GSUsers
{
public string UserName { get; set; }
public bool isEditor { get; set; }
public bool isReviewer { get; set; }
}
}
Controller Httpget method display this view
Problem is, post-back model returns all rows check boxes as false. The check-box outside table, Public, returns correct post-back value though.
Controller Postback code
[HttpPost]
public ActionResult Create(GoldSetnUsers newGS)
{
if (ModelState.IsValid)
{ // newGS gets me value
}
}
View
#model mvc2db.Models.GoldSetnUsers
#using BootstrapSupport;
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
#Html.BeginControlGroupFor(model=>model.Public)
#Html.LabelFor(model => model.Public,new {#class="control-label"})
<div class="controls">
#Html.EditorFor(model => model.Public,new {#class="input-xlarge"})
#Html.ValidationMessageFor(model => model.Public,null,new{#class="help-inline"})
</div>
<div class="controls">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Reviewer</th>
<th>Editor</th>
</thead>
<tbody>
#foreach (var item in Model.gsUsers) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
#Html.EditorFor(modelItem => item.isEditor)
</td>
<td>
#Html.EditorFor(modelItem => item.isReviewer)
</td>
</tr>
}
</tbody>
</table></div>
#Html.EndControlGroup()
<div class="form-actions">
<button type="submit" class="btn btn-primary">Save changes</button>
<button class="btn">Cancel</button>
</div>
</fieldset>
}
I guess since you are generating the checkboxes using a foreach loop all the checkboxes will have the same id. Hence there will be an ambiguity so as to which is checked and which is not.
You can try giving the username as the id of the checkbox.

my view dont Bind the viewModel MVC4

Sorry if I am not seeing anything wrong, but my View don't bind my ViewModel. I debugged many times, and there's no Data in the model when the breakpoint is on the action line.
Other views of the project works fine.
Action:
[HttpPost]
public ActionResult Index_Funcionario(FuncionariosViewModel viewModel)
{
...
View
#model ZebraStudio.Models.FuncionariosViewModel
#{
ViewBag.Title = "Index_Funcionario";
}
<div class="main-field">
<div class="linha-cabecalho">
<div class="aba">Consulta</div>
<div class="area">Funcionários > Consultar</div>
</div>
<div class="sub-field">
<div class="search-field">
#using (Html.BeginForm())
{
<div class="floatleft">
#Html.RadioButton("TipoFiltro", "1", new { #class = "radioFloat" })
<div >Código: #Html.TextBoxFor(model => model.cod_Usuario, new { #class = "customeditor"})</div>
</div>
<div class="floatleft">
<div class="radioFloat">#Html.RadioButton("TipoFiltro", "2", new { #class = "radioFloat" })</div>
<div>Nome: #Html.TextBoxFor(model => model.nome, new { #class = "customeditor"})</div>
</div>
<div class="floatleft">
#Html.RadioButton("TipoFiltro", "3", true, new { #class = "radioFloat" })
<div class="inline">Listar Todos.</div>
</div>
<br />
<input type="submit" value="Buscar" class="searchbutton"/>
}
</div>
<table class="search-result">
<tr>
<th>Código</th>
<th>Nome</th>
<th>Email</th>
<th>Tipo de Usuário</th>
<th>Ações</th>
</tr>
#foreach (var usuario in Model.usuarios)
{
<td>#usuario.UserId</td>
<td>#usuario.Nome</td>
<td>#User.Identity.Name</td>
<td>#foreach (var role in Roles.GetRolesForUser())
{
#role
}
</td>
<td></td>
}
</table>
</div>
ViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace ZebraStudio.Models
{
public class FuncionariosViewModel
{
public IEnumerable<Usuario> usuarios;
public Usuario usuario;
public string nome;
[DataType(DataType.EmailAddress)]
public string Email;
public string password;
public int opcao_Selecionada;
public int cod_Usuario;
}
}
Anything Wrong? Please Help-me.
ASP.Net MVC model binding does not support fields.
You need to change those to properties.
You can use auto-implemented properties:
public string Email { get; set; }