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!
Related
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
i have a radiobutton list in my create view.It is generated along with checkbox when selecting a dropdown.
#model IEnumerable<Admin.Models.viewmodel>
#foreach (var item in Model)
{
<label>
#Html.CheckBox("User", item.Selected, new { #id = "User" + item.Value, #value = item.Value })
#item.Text
</label>
<label>
#Html.RadioButton("rdnUser" + item.Value.TrimStart(), 1, item.IsSelected,new { #id = "rdnUser"})Primary
</label>
<label>
#Html.RadioButton("rdnUser" + item.Value.TrimStart(), 2,item.IsSelected, new { #id = "rdnUser"})Secondary
</label>
}
Iam saving the value of radiobutton to a field UserType in table UserMapping.
When I click on Edit link,I want to get the radiobutton selected according to database value..
Created a viewmodel to take values in checkbox and radiobutton.viewpartial viewmodel is:-
public class viewpartial : System.Web.Mvc.SelectListItem
{
public int Values { get; set; }
public bool IsSelected { get; set; }
}
The query is:-
var query = (from u in UserMapping
where u.UserID == id && u.Active == 1
join f in Financial on u.FinancialID equals f.FinancialID
into c
from d in c.DefaultIfEmpty()
select new viewpartialIFC
{
Text = d.FiName,
Value = SqlFunctions.StringConvert((double)d.FinancialID),
Selected = d.FinancialID == u.FinancialID ? true : false,
Values = u.UserType,
//IsSelected=???
}).Distinct().ToList();
what changes should i make in the query to get radiobutton selected..
This is a way that you can create a list of users and have the option to selected them (checkbox) and selected a particular role (radiobuttons):
ViewModel:
public class AdminViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool isSelected { get; set; }
public int RadioValue { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var data = GenerateViews();
return View(data);
}
[HttpPost]
public ActionResult Index(IList<AdminViewModel> data)
{
var selectedViews = data.Where(d => d.isSelected == true);
foreach (var selected in selectedViews)
{
//selected.Id;
//selected.RadioValue;
}
System.Diagnostics.Debugger.Break();
return View(data);
}
private IList<AdminViewModel> GenerateViews()
{
var output = new List<AdminViewModel>();
var rand = new Random();
for (var count = 1; count <= 10; ++count)
{
var newView = new AdminViewModel();
newView.Id = count;
newView.Name = "Name " + count.ToString();
newView.isSelected = false;
newView.RadioValue = rand.Next(1, 3);
output.Add(newView);
}
return output;
}
}
View:
#model IList<WebMVC3.Controllers.AdminViewModel>
<h2>Index</h2>
#using (Html.BeginForm())
{
//foreach (var item in Model)
for(var index = 0; index < Model.Count; ++index)
{
<div>
#Html.HiddenFor(m => Model[index].Id)
<label>
#Html.CheckBoxFor(m => Model[index].isSelected, Model[index].isSelected)
#Model[index].Name
</label>
<label>
#Html.RadioButtonFor(m => Model[index].RadioValue, 1)
Primary
</label>
<label>
#Html.RadioButtonFor(m => Model[index].RadioValue, 2)
Secondary
</label>
</div>
}
<input type="submit" value="Save" />
}
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.
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.
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?