Asp.net MVC View Textbox Returns Default Value - asp.net-mvc

I can send lat,lon, neighbors and neighborslimit variables to View.Yet, I want change neighborlimit from view. When I post View, MapViewModel's variables are 0, I have tried to ModelState.Clear() but there is no difference, Could you help me about it ? Thanks
MODEL:
public class MapViewModel
{
public double lat;
public double lon;
public List<Point> neighbors;
public Polygon polygon;
public int neighborlimit;
public double[][] polyTable;
}
CONTROLLER:
[HttpGet]
public ActionResult Map()
{
UserAccount user = (UserAccount)UserManager.FindByName(User.Identity.Name);
MapViewModel model = new MapViewModel() { lat = (double)user.address.latitude, lon = (double)user.address.longitude, neighbors = user.getNeighbors(), neighborlimit= (int)user.neighborsLimit };
return View(model);
}
[HttpPost]
public ActionResult Map(MapViewModel model)
{
UserAccount user = (UserAccount)UserManager.FindByName(User.Identity.Name);
user.neighborsLimit = model.neighborlimit;
UserManager.Update(user);
return View(model);
}
VIEW:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-md-10">
#Html.TextBoxFor(h => h.neighborlimit, new { #class = "form-control" })
</div>
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
}

You don't have a property for neighborlimit (just a field). Change it to
public int neighborlimit { get; set; }
which will allow the DefaultModelBinder to set the property when you submit the form

The problem is that you don't have the values in the form that's why when the form is posted the values doesn't exists and the ModelBinder set default values. If the security is not a problem but hidden fields for all values that you want to persist.
Something like this
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(h => h.lat)
/* Now enter hidden fields for all of the properties that you want */
<div class="form-group">
<div class="col-md-10">
#Html.TextBoxFor(h => h.neighborlimit, new { #class = "form-control" })
</div>
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
}
UPDATE
As Stephen Muecke said make sure that you use properties not fields

Related

How to validate the HTML controls with data annotations in MVC?

In .Net MVC. I have a html control. Inorder to bind it with the model property I am using name attribute. How do we get the validations(using data annotation) provided in the model class property into the html control?
In Cshtml
#using (Html.BeginForm("ClaimWarranty", "WarrentyClaim", FormMethod.Post, new{ enctype = "multipart/form-data" }))
{
<div class="form-group row">
<label for="" class="col-md-2 col-form-label input-label">Email Address:</label>
<div class="col-md-8">
<input type="text" name="Emailaddress" class="form-control input-style" placeholder="example#company.com">
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" onclick="ValidateFileSize()" class="btn btn-default" />
</div>
</div>
}
//The model class is below;
public class ClaimWarranty
{
[Required(ErrorMessage = "Email ID is Required")]
[DataType(DataType.EmailAddress)]
[MaxLength(50)]
[RegularExpression(#"[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}", ErrorMessage = "Incorrect Email Format")]
public string Emailaddress { get; set; }
}
I am using the name property to bind the text box to the model property .
<input type="text" name="Emailaddress" class="form-control input-style" placeholder="example#company.com">
How do I get the validations in the html control ,provided in the model class (using the data annotations) as shown above without using jquery validations or razor code?
In View
#model Demo.Models.Student
#using (Html.BeginForm("SaveStudent", "Student", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<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>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btnbtn-primary" />
</div>
</div>
}
In Model
public class Student
{
[Required(ErrorMessage = "Please enter name"), MaxLength(30)]
public string Name { get; set; }
}
By default, ASP.Net MVC framework executes validation logic during model binding. In Controller side, we need to check
if (ModelState.IsValid)
{
}
OR We can also check Individual validation, as shown below:
if (ModelState.IsValidField("LastName") == false)
if(!ModelState.IsValid)
{
// you can get the error information from model state, convert it into list
var validationErrors = ModelState.Values.Where(E => E.Errors.Count > 0)
.SelectMany(E => E.Errors)
.Select(E => E.ErrorMessage)
.ToList();
// now you have got the list of errors, you will need to pass it to view
// you can use view model, viewbag etc
ViewBag.ErrorList = validationErrors;
return View();
}
else
{
// perform your business operation, save the data to database
return View();
}
On View Page -
you have to add check for validation error list
if(ViewBag.ErrorList != null)
{
foreach(var errorMessage in ViewBag.ErrorList)
{
// here you can display the error message and format in html
}
}
Way you can display error on view page
1. #Html.ValidationSummary() - It will display summary of the validation errors
2. #Html.ValidationMessageFor(x => x.Emailaddress) - It will display error message
for specific property
3. you have to manually retrieve the error information from model state and then store it in list and pass to the view page.

How Can I Get ViewData in PartialView in Razor Pages

I'm Using Razor Pages For my App, in one part of my app I've used a partial view here is my codes;
public class Permission
{
[Key]
public int PermissionId { get; set; }
public string PermissionTitle { get; set; }
public int? ParentID { get; set; }
}
public class IndexModel : PageModel
{
public PartialViewResult OnGetCreateRole()
{
var ListPermission = permissionService.AllPermission();
return new PartialViewResult()
{
ViewName = "_PCreateRole", // partial's name
ViewData = new ViewDataDictionary<List<Permission>>(ViewData,
ListPermission)
};
}
}
ViewData is a List of Permission class and i've sent ViewData to partial but i dont know how to get ViewData, also my partial use another model, below is my partial:
#model ToMVC.DataLayer.Entities.User.Role
<div class="row">
<div class="col-md-12">
<form asp-page="CreateRole" method="post">
<div class="form-group">
<label class="control-label">Title</label>
<input asp-for="RoleTitle" class="form-control"/>
<p><span class="text-danger" asp-validation-for="RoleTitle"></span></p>
</div>
<div class="form-group">
<input type="submit" value="submit" class="btn btn-primary" />
</div>
//this part needs ViewData
#foreach (var item in ViewData)
{
}
</form>
</div>
</div>
I want to use ViewData in Foreach loop.
A better solution than ViewData would be to simply make a new ViewModel class containing all the information you need for a view.
public class UserRoleAndPermissions{
public UserRoleAndPermissions(){
Permissions = new List<Permissions>();
}
public List<Permission> Permissions {get;set;}
public ToMVC.DataLayer.Entities.User.Role Role {get;set;}
}
And your view
//check your namespace here - this is just an example
#model ToMVC.DataLayer.UserRoleAndPermissions
<div class="row">
<div class="col-md-12">
<form asp-page="CreateRole" method="post">
<div class="form-group">
<label class="control-label">Title</label>
<input asp-for="RoleTitle" class="form-control"/>
<p><span class="text-danger" asp-validation-for="RoleTitle"></span></p>
</div>
<div class="form-group">
<input type="submit" value="submit" class="btn btn-primary" />
</div>
#foreach (var item in Model.Permissions)
{
}
</form>
</div>
</div>

Why is the view model passed to my action method null?

I can't seem to pass the form values using a model. I do not want to resort to using individual parameter/FormCollection/Request and then instantiate the model class with the values.
My model
//JcSpaceAccount.cs
namespace JcSpaceEntities
{
public class JcSpaceAccount
{
public string FirstName;
public string LastName;
public string Email;
public DateTime DateOfBirth;
}
}
My View
//Registration.cshtml
#model JcSpaceEntities.JcSpaceAccount
<!DOCTYPE html>
<div class="form-horizontal">
<h4>JcSpaceAccount</h4>
<hr />
#using (Html.BeginForm("Registration", "Registration", FormMethod.Post))
{
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.LabelFor(m => m.FirstName)
</div>
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(m => m.FirstName)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.LabelFor(m => m.LastName)
</div>
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.LastName)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.LabelFor(m => m.Email)
</div>
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.Email)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.LabelFor(m => m.DateOfBirth)
</div>
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.DateOfBirth)
</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>
My controller
namespace JcSpace.Areas.Registration.Controllers
{
public class RegistrationController : Controller
{
// GET: Registration/Registration
[HttpGet]
public ActionResult Registration()
{
return View();
}
[HttpPost]
public ActionResult Registration(JcSpaceAccount entity)
{
return View();
}
}
}
You should change your model to:
public class JcSpaceAccount
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public DateTime DateOfBirth { get; set; }
}
Problem is default MVC ModelBinder works with properties and you have fields in your model now. So default model binder just can't fill them.
Change your JcSpaceAccount fields to properties and you get your data on post.
And in your Post contoller method you should set your model as #haim770 said:
[HttpPost]
public ActionResult Registration(JcSpaceAccount entity)
{
ViewData.Model = entity; //This line
return View();
}
On your Registration() method decorated with HttpGet.
[HttpGet]
public ActionResult Registration()
{
return View(new JcSpaceAccount());
}

MVC multiple select List not showing default values

Been working on this issue for a few hours now, maybe I'm missing something simple here, but no matter what I try I can't get the default selected items to work.
The controller function:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Room room = db.Rooms.Find(id);
if (room == null)
{
return HttpNotFound();
}
List<int> allowedMods = new List<int> {1, 2};
List<keyval> allMods = new List<keyval>
{
new keyval(1,"A"),
new keyval(2,"B"),
new keyval(3,"C")
};
MultiSelectList multiList = new MultiSelectList(allMods, "ID", "Name", allowedMods);
ViewBag.mods = multiList;
return View(room);
}
Simple helper class keyval:
public class keyval
{
public int ID { get; set; }
public string Name { get; set; }
public keyval() { }
public keyval(int ID, string Name)
{
this.ID = ID;
this.Name = Name;
}
}
The view:
#model X.Models.Room
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Room</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.Label("Moderators Allowed", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBox("mods", ViewBag.mods as MultiSelectList, new { #class = "form-control" })
</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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Relevant generated Html:
<div class="col-md-10">
<select class="form-control" id="mods" multiple="multiple" name="mods">
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>
</div>
I've tried so many different variations and when I submit the form I do get the new list of selected items, However the default values is not working for me.
I would really appreciate help on this issue.
The name of your listbox is the same as the name of your ViewBag property that holds the list, there is a strange bug with ViewBag that causes things to not render properly if this is the case. Try changing ViewBag.mods to ViewBag.moderators or something other than ViewBag.mods.
Tested using your code and that corrects the problem for me.

IValidatableObject.Validate does not fire if DataAnnoations add ValidationResult

With a standard ASP.NET MVC controller and view and a model that both implements IValidatableObject and has DataAnnotations, the Validate method never fires if the DataAnnotations generate an exception.
Here's the model...
public class ModelStaticDA : IValidatableObject {
public long Id { get; set; }
[EmailAddress]
public string EmailAddress { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
yield return new ValidationResult("MODEL NOT VALID!")
}
}
Here's the view (client validation is disabled for this demo)...
#model BindingAndValidation.Models.ModelStaticDA
#{
ViewBag.Title = "Create";
HtmlHelper.ClientValidationEnabled = false;
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ModelStaticDA</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.EmailAddress, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.EmailAddress)
#Html.ValidationMessageFor(model => model.EmailAddress)
</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")
}
If you post something like "invalid" to EmailAddress, only the DataAnnotation message displays. If you post a valid e-mail address, the message from Validate displays.
Is this the correct behavior? If so, why? If not, what am I doing wrong?
You are doing everything right, that's the behavior. My guess it was designed this way to avoid having to validate again while working with the properties inside the Validate method, you know that when it's called you are working with valid data, and you can do things that require valid data.

Resources