Data annotations don't seem to work - asp.net-mvc-3

I have a model Contact with data annotation
[Required(ErrorMessage = "Please enter a Contact Name")]
public string ContactName
{ get; set; }
[Required(ErrorMessage = "Please enter a Region")]
public string Region
{ get; set; }
I am passing this model as a list in another model ClientModel
[Required(ErrorMessage = "Please enter a name")]
public string clientname
{get;set;}
Public List<Contact> contact
{get;set;}
Now in my view I am binding my ClientModel
like this
#model MyContact.Models.ClientModel
When I submit the corresponding view only clientname comes with a validation message. There are textboxes which are populated from List<Contact> but they do not validate. I have copied the required scripts in layout and also have added a validation summary. I cannot understand why the validation is not happening.
these are my textboxes
<table border="0" id="tbl2" cellspacing="10" cellpadding="0">
#for (int i = 0; i < Model.ContactList.Count; i++)
{
<tr>
<td>
#Html.CheckBox("chk1", true, new { #class = "BASESAccountTeamChkBoxItem" })
</td>
<td>
#Html.TextBoxFor(m => m.ContactList[i].ContactName, new { style = "width:170px;"})
#Html.ValidationMessageFor((m => m.ContactList[i].ContactName)
</td>
<td>
#Html.TextBoxFor(m => m.ContactList[i].Region, new { style = "width:170px;" })
#Html.ValidationMessageFor((m => m.ContactList[i].ContactName)
</td>
<td>
#Html.TextBoxFor(m => m.ContactList[i].Email, new { style = "width:170px;" })
#Html.ValidationMessageFor((m => m.ContactList[i].Email)
</td>
<td>
#Html.TextBoxFor(m => m.ContactList[i].Phone, style = "width:170px;" })
#Html.ValidationMessageFor((m => m.ContactList[i].Phone)
</td>
<td>
#Html.TextBoxFor(m => m.ContactList[i].Fax, new { style = "width:170px;" })
#Html.ValidationMessageFor((m => m.ContactList[i].Fax)
</td>
</tr>
}
</table>
This is the javascript that will add a new row
+Add New Contact
function addRow(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var colCount = table.rows[0].cells.length;
for (var i = 0; i < colCount; i++) {
var newcell = row.insertCell(i);
newcell.innerHTML = table.rows[0].cells[i].innerHTML;
//alert(newcell.childNodes);
if (table.rows[0].cells[i].innerHTML != "") {
switch (newcell.childNodes[0].type) {
case "text":
newcell.childNodes[0].value = "";
break;
case "checkbox":
newcell.childNodes[0].checked = false;
break;
case "select-one":
newcell.childNodes[0].selectedIndex = 0;
break;
}
}
}
}
When i add a new row the validation does not work.I cant know why that is happening
And i have kept my view in #Html.Beginform only. As my view is huge i am not posting the entire code. I also have the scripts in place .Please help

I had this problem a long time ago too, when I started learning ASP.Net MVC3. Here are some tips you can try.
We may be able to help better if you paste your view (or parts of your view) into here as well.
Is your form surrounded by a
#using(Html.BeginForm()){}
snippet?
If it's not, and you're doing the form by hand, you may get unexpected behavior with the MVC Javascript validator.
Are you including the
#Html.ValidationFor()
for each of your text boxes?
And not just a ValidationFor() the list?

Related

LINQ: .Select infinite loop

I am getting what appears to be an infinite loop in either LINQ or somehow JQuery. It keeps calling the Controller Method over and over.
Here's my controller method:
public ActionResult Index()
{
// TODO: decide what properties determine a need for User Action (the 'where(s)')
var viewModel = new PriorityTasksViewModel
{
BayOptions = _bayOptionRepository.GetBayOptions()
.Where(x => x.IsActive && !x.SiteVisibilityFlagsOverride).ToList()
.Select(x => new PriorityTasksBayOptionsViewModel()
{
BayGuid = x.BayGUID,
BayNumber = x.BayNumber,
PropertyId = x.PropertyId
})
.ToList(),
Properties = _propertyRepository.GetProperties()
.Where(x => !x.SiteVisibilityFlagsOverride).ToList()
.Select(x => new PriorityTasksPropertiesViewModel()
{
PropertyId = x.PropertyId,
PropertyName = x.Name
})
.ToList()
};
return View("_PriorityTasks", viewModel);
}
If I put a breakpoint in the view, I verify it's looping. What am I missing in my LINQ? I put .ToList() in there to force loading but...
View:
<h6>Properties</h6>
<table class="table">
<tr>
<th>
Name
</th>
</tr>
#foreach (var item in Model.Properties) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.PropertyName)
</td>
</tr>
}
</table>
And the JQuery at the bottom of the _Layout:(it has to show on teh menu of layout)
$(document).ready(function () {
$('#PriorityTasks').load('#Url.Action("Index", "PriorityTask")');
})
Maybe you need return a partial view instead
return PartialView("_PriorityTasks", viewModel);
I think if you want keep a layout you could use a partial view.
Controller:
public ActionResult Images(int? page)
{
int pageNumber = page ?? 1;
page = page ?? 1;
var images = db.image.AsQueryable().OrderBy(x => x.name);
var onePageOfImages = images.ToPagedList(pageNumber, pageSize);
ViewBag.onePageOfImages = onePageOfImages;
return (page == 0)
? PartialView()
: (ActionResult)PartialView("_ImageList");
}
Images.cshtml
#{
ViewBag.Title = "Image List";
}
#using PagedList;
#using PagedList.Mvc;
#Styles.Render("~/Content/PagedList.css")
<h2>Image List</h2>
#DateTime.Now.ToString()
<div id="unobtrusive">
#Html.Partial("_ImageList")
</div>
and _ImageList
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)

List HttpPostedFileBase with knockout

I have a create view with a form. It has an input text (enviroment), input file (logo) drop down list (platforms) and list of viewmodel (days).
This is working OK. Now I want to add a "dynamic field" to insert files. Typical Add File, Remove File. I´ve seen this is done with knockout. My problem is how to deal with HttpPostedFileBase and knockout, and worst, a list of HttpPostedFileBase and knockout.
I´ve done this, but it´s not working. Any help would be very appreciated.
CreateView:
#model HPRWT.ViewModels.ReportViewModel
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/knockout.namepathbinding.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/Files.js")" type="text/javascript"></script>
#using (Html.BeginForm("Create", "Service", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Report</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Enviroment)
#Html.EditorFor(model => model.Enviroment, new { data_bind = "value: enviroment" })
#Html.ValidationMessageFor(model => model.Enviroment)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Logo)
#Html.TextBoxFor(model => model.Logo, new { type = "file", data_bind = "value: logo" })
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PlatformID)
#Html.DropDownListFor(model => model.PlatformID, Model.Platforms.Select(f => new SelectListItem { Text = f.name, Value = f.ID.ToString() }))
</div>
<div class="editor-label">
#Html.LabelFor(model => model.InputFiles)
#for (int j = 0; j < Model.InputFiles.Count; j++)
{
#Html.TextBoxFor(model => model.InputFiles[j], new { type = "file", data_bind = "value: inputFile" })
}
<button data-bind="click: addFile">Add Log</button>
<button data-bind="click: removeFile">Remove Log</button>
</div>
<table id="hours">
#for (int i = 0; i < 7; i++)
{
<tr>
<td>#Model.Days[i].Label</td>
#for (int j = 0; j < 24; j++)
{
<td><div>#Html.CheckBoxFor(model => model.Days[i].Hours[j].Selected)#Html.LabelFor(model => model.Days[i].Hours[j].Selected, #" ")</div></td>
}
</tr>
}
</table>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Files.js
function createViewModel() {
var createFile = function () {
return {
inputFile: ko.observable()
};
};
var addFile = function () {
inputFiles.push(createFile());
};
var removeFile = function () {
inputFiles.pop();
};
var enviroment = ko.observable();
var logo = ko.observable();
var inputFiles = ko.observableArray();
return {
enviroment: enviroment,
logo: logo,
inputFiles: inputFiles,
addFile: addFile,
removeFile: removeFile
};
}
$(document).ready(function () {
var viewModel = createViewModel();
ko.applyBindings(viewModel);
});
ReportViewModel:
public class ReportViewModel
{
public int ID { get; set; }
public IEnumerable<Platform> Platforms { get; set; }
public int PlatformID { get; set; }
public string Enviroment { get; set; }
public HttpPostedFileBase Logo { get; set; }
public IList<HttpPostedFileBase> InputFiles { get; set; }
public IList<DayViewModel> Days { get; set; }
public ReportViewModel()
{
Days = Enumerable.Range(1, 7).Select(day => new DayViewModel { Value = day }).ToList();
InputFiles = new List<HttpPostedFileBase>();
}
}
DayViewModel:
public class DayViewModel
{
public int Value { get; set; }
public virtual IList<HourViewModel> Hours { get; set; }
public DayViewModel()
{
Hours = Enumerable.Range(0, 24).Select(hour => new HourViewModel { Value = hour }).ToList();
}
}
HourViewModel:
public class HourViewModel
{
public int Value { get; set; }
public bool Selected { get; set; }
}
Try by making InputFiles Array instead of IList
I am not sure about IList but when you take property as List, you have to keep html field name as fieldlist.propname.index (and Id will be fieldlist_propname_index) where you index will start from 0 for the default or first field and when you will add new control then its name should get increment like fieldlist.propname.0 (first one) then fieldlist.propname.1 and so on...
then only model binder will be able to bind.
Better try with Array if it works then I think you are good to go

MVC3 Razor check box values are not coming through on submit

I have a form with serval check box items in a list.
I have a editor for this list. They display on the screen fine.
But when submitted the items checked are not submitted in the model...
Models:
public class ContactUsersModel : BaseModel
{
public IList<FilterCheckModel> PreviousVisitors { get; set; }
}
public class FilterCheckModel : BaseModel
{
public string Name { get; set; }
public string Value { get; set; }
public bool IsChecked { get; set; }
}
Controller:
IList<FilterCheckModel> prevVisitList = new List<FilterCheckModel>();
prevVisitList.Insert(0, new FilterCheckModel() { Name = "All previous visitors", Value = "0" });
prevVisitList.Insert(1, new FilterCheckModel() { Name = "Not visited in last month", Value = "1" });
prevVisitList.Insert(2, new FilterCheckModel() { Name = "Not visited for 1-3 months", Value = "2" });
prevVisitList.Insert(3, new FilterCheckModel() { Name = "Not visited for 3-6 months", Value = "3" });
prevVisitList.Insert(4, new FilterCheckModel() { Name = "Not visited for over 6 months", Value = "4" });
model.PreviousVisitors = prevVisitList;
html:
<table>
<tr>
<th>
Previous visitors:
</th>
</tr>
#for (int i = 1; i < Model.PreviousVisitors.Count; i++)
{
#Html.EditorFor(model => model.PreviousVisitors[i], "FilterCheck", new { Index = i + 1})
}
</table>
editor:
<tr>
<td>
#Model.Name
</td>
<td>
#Html.CheckBoxFor(x => x.IsChecked)
#Html.HiddenFor(x => x.Value)
</td>
</tr>
Found it!
the reason was that in my loop i was started i = 1.
this causes an issue for some reason.
The index need to start form 0...
#for (int i = 1; i < Model.PreviousVisitors.Count; i++)
so i changed this to
#for (int i = 0; i < Model.PreviousVisitors.Count; i++)
and it worked!

Model Binding a List MVC3 not reading vaules

I have read some posts, but I still find it difficult to solve this. My problem is that my action only reads some of the values from the binded list. This is how I send the list to the view:
public ActionResult RegisterSurvey()
{
RegisterSurveyModel model = new RegisterSurveyModel();
var questions = new List<QuestionModel>();
var survey = EFSurvey.Survey.FirstOrDefault();
survey.QuestionSurvey
.Where(x => x.AuditingDeleted == false)
.Where(x => x.Active == true).ToList().ForEach((item) =>
{
var questionModel = new QuestionModel();
ModelCopier.CopyModel(item, questionModel);
questionModel.Answer = string.Empty;
questions.Add(questionModel);
});
model.Questions = questions;
return View(model);
}
This is my model:
public class RegisterSurveyModel
{
public List<QuestionModel> Questions { get; set; }
}
public class QuestionModel
{
public int QuestionSurveyID { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
public bool Suggestion { get; set; }
}
This is my view:
<div class="SiteSurveyContainer">
#using (Html.BeginForm())
{
<div class="SurveyUp">
#for (int i = 0; i < Model.Questions.Count(); i++)
{
if (!Model.Questions[i].Suggestion)
{
<p>#Model.Questions[i].Question</p>
#Html.HiddenFor(x => Model.Questions[i].QuestionSurveyID);
#Html.TextBoxFor(x => Model.Questions[i].Answer, new { #class = "surveyBox" });
}
}
</div>
<div class="SurveyBottom">
<div class="line">
</div>
<p>
Suggestions</p>
#for (int i = 0; i < Model.Questions.Where(x => x.Suggestion == true).Count(); i++)
{
#Html.HiddenFor(x => Model.Questions[i].QuestionSurveyID);
#Html.TextAreaFor(x => Model.Questions[i].Answer, new { #class = "surveyTextArea" })
}
</div>
<div class="surveyBottomButton">
<input type="submit" value="Submit Results" />
</div>
}
So far so good. Anyway, when I answer all of the survey questions, I only get the first 4 answers... Weird. Anyone knows why is that happening?
You have multiple input controls with within the same form with the same name.
Suggested questions are a sub set of all questions, so they are being repeated twice on the same form. That will throw off the ModelBinder, so your receiving action is probably only seeing the questions that have not been repeated.

Validation Issues on Hidden DropDownListFor's ASP.NET MVC3

FINAL EDIT: The problem was that ViewBag.PropName == Model.PropName;
FIX: ViewBag.PropName ===> ViewBag.PropName2
This is my first time posting; I'm new and think I messed up the layout... so sorry!
I encountered some issues with client-side validation for hidden dropdownlistfor's.
I am working with ASP.NET MVC3 and have a lot of hidden ddl on this page.
The validation however, doesn't work for some ddl's.
Has anyone ever had a problem with this before?
These are 2 properties; 1 working, 1 failing
//VALIDATION FAILS
[Required]
[Range(0, 4)]
public int TiresBack { get; set; }
//VALIDATION WORKS
[Required]
[Range(0, 4)]
public int TechnicalState { get; set; }
This is a piece the razor:
<tr>//THIS DOESN'T WORK
<td style="width: 38%;">
#txtFor("tiresBack")
</td>
//This is JQuery Star-Rating.
<td align="center" id="starsTiresBack">
</td>
<td>
#Html.DropDownListFor(model => model.TiresBack, ViewBag.TiresBack as IEnumerable<SelectListItem>, new { style = "display:none;" })
<input class="blueButton" type="button" id="btnBrandRearTires" value="#txtFor("brandTiresBack")" />
<span>#Html.ValidationMessageFor(model => model.TiresBack)</span> <span>#Html.ValidationMessageFor(model => model.BrandRearTires)</span>
</td>
</tr>
//THIS WORKS
<tr>
<td style="width: 38%;">
#txtFor("technicalState")
</td>
<td id="starsTechnicalState" align="center">
</td>
<td>
#Html.DropDownListFor(model => model.TechnicalState, ViewBag.TechState as IEnumerable<SelectListItem>, new { style = "display:none;" })
<input class="blueButton" type="button" id="btnTechnicalStateDescription" value="#txtFor("technicalStateDescriptionButton")" style="display:none;"/>
<span>#Html.ValidationMessageFor(model => model.TechnicalState)</span> <span>#Html.ValidationMessageFor(model => model.TechnicalStateDescription)</span>
</td>
</tr>
EDIT1: Initialised in the controller using this method:
public static List<SelectListItem> CreateDefaultStateList(int? selected = -1)
{
List<SelectListItem> sl = new List<SelectListItem>();
for (int i = -1; i < 5; i++)
{
SelectListItem sli = new SelectListItem();
if (i == 0 || i == -1)
sli.Text = "";
else
sli.Text = i.ToString();
sli.Value = i.ToString();
if (i == selected)
sli.Selected = true;
sl.Add(sli);
}
return sl;
}
EDIT2: The create controller. defaultstatelist is what got returned from the method posted above.
List<SelectListItem> defaultStateList = CreateDefaultStateList();
[Authorize]
public ActionResult Create()
{
FillViewBag();
ViewBag.PropX = defaultStateList;
ViewBag.TiresFront = defaultStateList;
ViewBag.TechState = defaultStateList;
ViewBag.PropY= defaultStateList;
ViewBag.PropZ= defaultStateList;
ViewBag.PropA= defaultStateList;
ViewBag.PropB= defaultStateList;
ViewBag.PropC= defaultStateList;
ViewBag.PropD= defaultStateList;
return View();
}
Typing this I notice the the default value in the method. That could be it...
==> Tried it, wasn't it. Updated code to '-1' as default value now.
The problem was that ViewBag.PropName == Model.PropName;
FIX: Rename ViewBag.PropName to something else like ViewBag.PropName2.

Resources