I updated a Enum Editor I found online to generate kendo radio controls instead of regular but the first radio button is generated with correct attributes and the remaining are wrong and at runtime, the whole set of radio buttons are not clickable
Here is the .cshtml for the editor:
#model Enum
#{
Func<Enum, string> getDescription = en =>
{
Type type = en.GetType();
System.Reflection.MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute), false);
if (attrs != null && attrs.Length > 0)
{
return ((System.ComponentModel.DataAnnotations.DisplayAttribute)attrs[0]).GetName();
}
}
return en.ToString();
};
var listItems = Enum.GetValues(Model.GetType()).OfType<Enum>().Select(e =>
new SelectListItem()
{
Text = getDescription(e),
Value = e.ToString(),
Selected = e.Equals(Model)
});
string prefix = ViewData.TemplateInfo.HtmlFieldPrefix;
int index = 0;
ViewData.TemplateInfo.HtmlFieldPrefix = string.Empty;
foreach (var li in listItems)
{
string fieldName = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}_{1}", prefix, index++);
<div >
#(Html.Kendo().RadioButton()
.Label(li.Text)
.Name(prefix)
.Value(li.Value)
.Checked(li.Selected)
.HtmlAttributes(new { #id = fieldName })
)
#*
This works properly
#Html.RadioButton(prefix, li.Value, li.Selected, new { #id = fieldName, #class = "k-radio" })
#Html.Label(fieldName, li.Text, new { #class = "k-radio-label" })
*#
</div>
}
ViewData.TemplateInfo.HtmlFieldPrefix = prefix;
}
Here is the first radio on the form:
<div>
<input name="StaffType" class="k-radio k-radio" id="StaffType_0" type="radio" checked="checked" value="DACStaff" data-val-required="The StaffTypeEnum field is required." data-val="true">
<label class="k-radio-label" for="StaffType_0_DACStaff">DAC Staff</label>
</div>
And here is the next one:
<div>
<input name="StaffType" class="k-radio k-radio" id="StaffType_1" type="radio" value="AirportStaff">
<label class="k-radio-label" for="StaffType_1_AirportStaff">Airport Staff</label>
</div>
I see that the class tag k-radio is applied twice and except the first element has the data-* attributes but second radio button and onwards, the generated code is missing attributes.
Can someone point out why the generated code is not functioning?
Usage:
<div class="form-group">
#Html.LabelFor(m => m.StaffType, new { #class = "col-sm-3 control-label" })
<div class="col-sm-6">
#Html.EditorFor(m => m.StaffType, "RadioButtonListEnum")
</div>
</div>
Related
I've a model that contains 3 tables in my view.
public class InExam
{
public AutoTests TheTest { get; set; }
public List<InTest> TheQuestions { get; set; }
public IEnumerable<Result> SingleQuee { get; set; }
}
First one made to get the detailed page, like "admin/AutoTests/id"
Second one made to get a list of questions linked to the page
Third one is to save radio button strings to post it back into the controller
my plan is to get (say) 20 questions that are linked with the detailed page, Adding 4 radio buttons for each question, and post back every selected button to the controller.
my view form :
#using (Html.BeginForm("Test", "Exams", new { id = Model.TheTest.id }, FormMethod.Post))
{
foreach (var item in Model.TheQuestions)
{
Kafo.Models.Result singleQuee = Model.SingleQuee.Where(x => x.Question == item.Question).FirstOrDefault();
<div class="container" style="padding-top:50px;direction:rtl;">
<h4 style="text-align:right;font-weight:bold;">#item.Question</h4>
<div class="container">
<div class="row" style="direction:rtl;">
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "1" })
<h5 style="padding-top:3px;padding-right:8px;">#item.RightAnswer</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "2" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer2</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "3" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer3</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "4" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer4</h5>
</div>
</div>
#Html.HiddenFor(m => singleQuee.Question)
</div>
</div>
</div>
}
<button class="btn botton" type="submit" onclick="return confirm('');">END</button>
}
i used this line "Kafo.Models.Result singleQuee = Model.SingleQuee.Where(x => x.Question == item.Question).FirstOrDefault();" in my view because i can't use tuple foreach ( C# ver. 5 )
This is my controller code :
[HttpGet]public ActionResult Test(int? id)
{
using (KafoEntities db = new KafoEntities())
{
InExam model = new InExam();
model.TheTest = db.AutoTests.Where(x => x.id == id).FirstOrDefault();
model.TheQuestions = db.InTest.Where(x => x.UserEmail == currentUser.Email && x.ExamId == model.TheTest.id).OrderByDescending(x => x.id).Take(Convert.ToInt32(model.TheTest.QuestionsNumber)).ToList();
model.SingleQuee = db.Result.ToList();
return View(model);
}
}
[HttpPost]
public ActionResult Test(int? id, List<Result> singleQuee)
{
using (KafoEntities db = new KafoEntities())
{
int result = 0;
foreach (Result item in singleQuee)
{
Result sets = db.Result.Where(x => x.id == item.id).FirstOrDefault();
sets.Question = item.Question;
db.SaveChanges();
var check = db.InTest.Where(x => x.Question == item.Question).FirstOrDefault();
if (check != null)
{
if (item.Question == "1")
{
result++;
}
}
}
return RedirectToAction("Results", "Exams", new { Controller = "Exams", Action = "Results", id = done.id });
}
}
I first save the new string that came from the radio button value into the result record, then i call it back in the if condition to check it's value
The problem here is i get a
Object reference not set to an instance of an object.
when i post the test, it means that the list is empty, so i need to know what makes the radio buttons not working,
Thanks.
If you want to bind a List of object in Mvc, you should name the controller like "ModelName[indx].PropertyName". In your case it should be "singleQuee[0].Question".
Code Sample
var Indx = 0;
foreach (var item in Model.TheQuestions)
{
.....
var radioName = $"singleQuee[{Indx}].Question";
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
<input type="radio" name="#radioName" value="1" />
<h5 style="padding-top:3px;padding-right:8px;">#item.RightAnswer</h5>
</div>
</div>
.....
}
Action Method
I have a model which have properties.And, i want to check that if any model item has some value or not.Also,no property is set to mandatory or optional using data-annotations.If no property is assigned and any value then i should set some model error e.g "Please specify some search criteria."
#using (Html.BeginForm("GetAdvanceSearchData", "Home", FormMethod.Post)){
<div class="rTableCell" style="border:none !important">
#Html.TextBoxFor(m => m.MessageStatus, new { placeholder = Html.DisplayNameFor(n => n.MessageStatus), #class = "fieldtextbox", #style = "height: 25px !important" })
#Html.ValidationMessageFor(m => m.MessageStatus)
</div>
<div class="rTableCell" style="border:none !important">
#Html.TextBoxFor(m => m.RequestType, new { placeholder = Html.DisplayNameFor(n => n.RequestType), #class = "fieldtextbox", #style = "height: 25px !important" })
#Html.ValidationMessageFor(m => m.RequestType)
</div>
<div class="rTableCell" style="border:none !important">
</div>
<div class="rTableCell" style="border:none !important">
<p class="submit">
<button type="submit" name="submit">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
</p>
</div>
}
These are only few properties for the model.
In action method GetAdvanceSearchData you can do your own validity checks, in addition to validation attributes, or instead of them.
If you add an entry to ModelState then ModelState.IsValid will become false, and the added entry will show in the output of Html.ValidationMessageFor(...) or Html.ValidationSummary().
Example:
[HttpPost]
public ActionResult GetAdvanceSearchData(YourModel vm)
{
if (vm == null || (string.IsNullOrEmpty(vm.MessageStatus) && string.IsNullOrEmpty(vm.RequestType)))
{
ModelState.AddModelError("", "Please specify some search criteria")
// Using "" as Key will only show when you use #Html.ValidationSummary().
// Using "myErr" as Key will show when you use #Html.ValidationMessage("myErr").
// Using a property name as Key will show it next to the property if you use #Html.ValidationMessageFor(m => m.property).
}
if (ModelState.IsValid)
{
var results = ...
return View("ResultsView", results);
}
else
{
return View(vm);
}
}
I am using ASP.NET MVC in VB. This is the "CreateStuffViewModel", which is a view model for my "Stuff" class:
Public Property Name() As String
Public Property Description() As String
Public Property ItemNames() As List(Of String)
In the View for creating a Stuff, the model being used is the above view model. I have a dropdown combobox containing the names of all of the user's Items, which is created in the controller in the Get. The user can select an item in the combobox, then hit an "Add" button, which adds that text to a list box. When the user hits the "Create" button, the text items in the list box are supposed to be in the ItemNames list.
This is the Get function:
' GET: Stuff/Create
Function Create() As ActionResult
Dim selectItem As New List(Of SelectListItem)
Dim curUserID = User.Identity.GetUserId()
Dim listOfItems = db.Items.Where(Function(x) x.MyUser.Id = curUserID)
For Each item In listOfItems
selectItem.Add(New SelectListItem() With {.Value = item.ID, .Text = item.Name})
Next
ViewData("selectItem") = selectItem
Dim newStuff As CreateStuffViewModel = New CreateStuffViewModel
newStuff.ItemNames = New List(Of String)
Return View(newStuff)
End Function
Then this is the view:
#ModelType CreateStuffViewModel
#Code
ViewData("Title") = "Create"
'This is the list of items that was created in the controller
Dim selectItem As New List(Of SelectListItem)
selectItem = ViewData("selectItem")
Dim selItems As New List(Of SelectListItem)
End Code
<h2>Create</h2>
#Using (Html.BeginForm())
#Html.AntiForgeryToken()
#<div class="form-horizontal">
<br />
<br />
<h4>Create a new Stuff</h4>
<hr />
#Html.ValidationSummary(True, "", New With { .class = "text-danger" })
<div class="form-group">
#Html.LabelFor(Function(model) model.Name, htmlAttributes:= New With { .class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(Function(model) model.Name, New With { .htmlAttributes = New With { .class = "form-control" } })
#Html.ValidationMessageFor(Function(model) model.Name, "", New With { .class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(Function(model) model.Description, htmlAttributes:= New With { .class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(Function(model) model.Description, New With { .htmlAttributes = New With { .class = "form-control" } })
#Html.ValidationMessageFor(Function(model) model.Description, "", New With { .class = "text-danger" })
</div>
</div>
#*This is the dropdown list containing the strings of item names*#
<div class="form-group">
<div class="control-label col-md-2" style="font-weight: bold">Select an existing Item</div>
<div class="col-md-10" id="ItemsList">
#Html.DropDownList("AvailItems", selectItem)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Add Item" class="btn btn-default" id="AddItem"/>
</div>
</div>
#*This is the list box to which the Add button adds the item text*#
<div class="form-group">
<div class="control-label col-md-2" style="font-weight: bold">Items in Stuff</div>
<div class="col-md-10">
#Html.ListBoxFor(Function(model) model.ItemNames, New SelectList(selItems), htmlAttributes:=New With {.name = "ItemNames"})
<div class="btn-group-vertical">
<div class="btn-link">Move Up</div>
<div class="btn-link">Move Down</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Remove Selected Item" class="btn btn-default" id="RemoveItem"/>
</div>
</div>
<br />
<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>
End Using
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#Section Scripts
#Scripts.Render("~/bundles/jqueryval")
#*Script for adding selected item from drop down to the list*#
<script>
$('#AddItem').click(function () {
var selection = $('#ItemsList :selected').text();
selection.trim();
var x = document.getElementsByName("ItemNames");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].type == "select-multiple") { //listbox
x[i].options.add(new Option(selection, selection));
}
}
});
</script>
#*Script for removing selected item from list*#
<script>
$('#RemoveItem').click(function () {
var x = document.getElementsByName("ItemNames");
var listBox;
var i;
for (i = 0; i < x.length; i++) {
if (x[i].type == "select-multiple") { //listbox
listBox = x[i];
}
}
if (listBox.selectedIndex >= 0) {
var sel = listBox.options[listBox.selectedIndex];
listBox.options.remove(sel);
}
});
</script>
End Section
And this is the Post function:
' POST: Stuff/Create
'To protect from overposting attacks, please enable the specific properties you want to bind to, for
'more details see http://go.microsoft.com/fwlink/?LinkId=317598.
<HttpPost()>
<ValidateAntiForgeryToken()>
Async Function Create(ByVal model As CreateStuffViewModel) As Task(Of ActionResult)
If ModelState.IsValid Then
Dim newStuff = New Stuff() With {
.Name = model.Name,
.Description = model.Description
}
Dim curUserID = User.Identity.GetUserId()
Dim thisUser As AppUser = db.Users.Where(Function(x) x.Id = curUserID).FirstOrDefault()
newStuff.MyUser = thisUser
'model.ItemNames is Nothing:
Dim thisList As List(Of String) = model.ItemNames
If thisList IsNot Nothing Then
Dim thisItem As Item
For Each item In thisList
thisItem = (From thing In db.Items Select thing Where thing.MyUser.Id = curUserID AndAlso thing.Name = item)
newStuff.Items.Add(thisItem)
Next
End If
db.Stuffs.Add(newStuff)
Await db.SaveChangesAsync()
Return RedirectToAction("Index")
End If
Return View(model)
End Function
So the view works fine - the Add button adds the text to the list box as expected. But when I hit the "Create" button, in the controller, the ItemNames list is NOTHING, and I do not know why.
Any help is greatly appreciated!
I am learning MVC and am stuck at this. I was trying to create a filter for name, category, type, Min Value, Max value but when redirected to another view it only shows three parameters but without other values.
Controller (DetailController)
public ActionResult FilteredResult(string searchedLocation, string Type, string PCName, string MinValue, string MaxValue)
{
var A = searchedLocation;
var B = Type;
var C = PCName;
var D = MinValue;
var E = MaxValue;
return View();
}
View
#using (Html.BeginForm("FilteredResult", "Detail", FormMethod.Get))
{
<form>
<h4 style="color: #ed145b;">Find the right property for you</h4>
<ul class="form-style-1">
<li>
#Html.TextBox("Location", ViewBag.Location as string , new { #class = "field-long" })
</li>
<li>
#Html.DropDownList("Type", (SelectList)ViewBag.TypeList, "Select" , new { #class = "field-select" })
</li>
<li>
#Html.DropDownList("Category", (SelectList)ViewBag.CategoryList, "Select" ,new { #class = "field-select" })
</li>
<li>
<label for="amount">Price range:</label>
<input type="text" id="amount" class="field-long" readonly style="border:0; color:#ee2265; font-weight:bold;">
</li>
<li class="clearfix"> #Html.TextBox("MinValue", ViewBag.MinValue as string, new { #class = "Minprice field-long", disabled = "true" })
#Html.TextBox("MaxValue", ViewBag.MaxValue as string, new { #class = "Maxprice field-long", disabled = "true" })
</li>
<li>
<div id="slider-range"></div>
</li>
<li>
<input type="submit" value="Search" class="btn-primary" />
</li>
</ul>
</form>
}
After clicking on search it shows like this. Only the data from dropdown is shown and other parameter like Minvalue and max value is not shown in the url. Location is showing
Can anyone help me on how I can successfully get data in the required field in the controller?
It's because your MinValue and MaxValue textboxes have disabled="true" attribute. Disabled inputs won't be submitted
#Html.TextBox("MinValue", ViewBag.MinValue as string, new { #class = "Minprice field-long", disabled = "true" })
#Html.TextBox("MaxValue", ViewBag.MaxValue as string, new { #class = "Maxprice field-long", disabled = "true" })
You should remove the disabled attribute
#Html.TextBox("MinValue", ViewBag.MinValue as string, new { #class = "Minprice field-long" })
#Html.TextBox("MaxValue", ViewBag.MaxValue as string, new { #class = "Maxprice field-long" })
If you want to make those textboxes non editable, use readonly attribute instead
#Html.TextBox("MinValue", ViewBag.MinValue as string, new { #class = "Minprice field-long", #readonly = "readonly" })
#Html.TextBox("MaxValue", ViewBag.MaxValue as string, new { #class = "Maxprice field-long", #readonly = "readonly" })
because you are using disabled attribute true that means it fetches data from database but will not show on View so either make disabled = "false" or remove this attribute.
This is very weird and i know that this worked in the past. I must have broken it with something else but I really don't know what.
I'm a .NET programmer with very little MVC knowledge and it seems that I'm missing some key things here , that mvc does in the background.
Let met explain it as best as I can.
I have a view, which contains this :
<tbody>
#foreach (var experienceViewModel in this.ViewData.Model)
{
var id = "GetExperienceDetail" + experienceViewModel.Id;
<tr>
<td>#experienceViewModel.Assessment</td>
<td>#experienceViewModel.CompanyName</td>
<td>#experienceViewModel.Description</td>
<td>#experienceViewModel.StartDate</td>
<td>#experienceViewModel.EndDate</td>
<td width="20"><i class="glyphicon glyphicon-pencil"></i></td>
<td width="20"><a id="#Html.Raw(id + "delete")" class="confirm-delete" data-keyname="experienceId" data-textfield="#string.Concat(experienceViewModel.Assessment, " | ", experienceViewModel.Description)" data-link="#Html.Raw(id + "delete")" data-key="#experienceViewModel.Id" data-controller="Experience" data-action="ExperienceDelete" href="#" title="Verwijder"><i class="glyphicon glyphicon-remove"></i></a></td>
</tr>
}
Its not the last tr but the one before that. The one with openDetail. This function will be called from the js web.js which I'm gonna paste below:
function openDetail(link) {
var $link = $('#' + link);
debugger;
var controller = $link.attr('data-controller');
var action = $link.attr('data-action');
var id = $link.attr('data-key');
var form = $link.attr('data-form');
var modelName = $link.attr('data-model');
//default person
if (modelName == null)
modelName = "person";
modelName = modelName.toLowerCase();
var valueModel = $link.attr('data-' + modelName);
var json = "{\"id\" : " + id + ", \"" + modelName + "\"" + " : " + valueModel + "}";
var url = '/' + controller + '/' + action;
$.ajax({
url: '/' + controller + '/' + action,
type: 'POST', // not sending json over url
data: json,
contentType: "application/json; charset=utf-8",
success: function (data) {
$('#partialoveview').html(data);
if (typeof form !== 'undefined' && form !== false) {
$.validator.unobtrusive.parse($('#' + form));
$("span.field-validation-valid").hide();
$('.label-error').hide();
}
loadForm();
},
error: function (data) {
}
});
This function does the job, the only thing that is going wrong is that dropdownlist, and specifically THAT one cause there is another one, below it , and this has the correct behavior of selecting the value that it has ...
This will go to the Person controller with the action ExperienceDetail(int id, int person)
[HttpPost, OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
public PartialViewResult ExperienceDetail(int id, int person)
{
var experienceViewModel = new ExperienceViewModel { AssessmentList = this.AssessmentList(), CompanyList = this.CompanyList(), PersonId = person };
if (id > 0)
{
Data.Model.Experience experience = this._experienceRepository.GetExperienceDetail(id);
experienceViewModel = new ExperienceViewModel(experience) { AssessmentList = this.AssessmentList(), CompanyList = this.CompanyList()};
}
return this.PartialView("_ExperienceDetailPartial", experienceViewModel);
}
this.CompanyList gets a select list from the basecontroller
When this view is returned , i cant see that this select list has a selectedvalue. But then again, the ddl which is working has also a null at the selectedvalue so this isn't responsable for setting the correct value after edit I guess?
Then the detail screen , which is put into a div from the js:
I only put in the beginning with first the company drop down ( NOT WORKING ) and then the assessment ddl ( WORKING )
#model Emenka.HumanResources.Application.Models.ExperienceViewModel
#using (Html.BeginForm("UpdateExperienceDetail", "Person", FormMethod.Post, new { #id = "ExperienceDetail", #role = "form", data_action = "ExperienceOverview", data_controller = "Person" }))
{
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.PersonId)
<fieldset>
<legend>Ervaring</legend>
<div class="row">
<div class="col-md-5">
<div class="form-group">
#Html.LabelFor(m => m.CompanyId, new { #class = "control-label" })
<div class="input-group col-xs-9">
#Html.DropDownListFor(m => m.CompanyId, ViewData.Model.CompanyList, string.Empty, new { #class = "no-focus form-control" })
#* #Html.ValidationMessageFor(m => m.CompanyId, " ")*#
...
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.AssessmentId, new { #class = "control-label" })
#Html.DropDownListFor(m => m.AssessmentId, ViewData.Model.AssessmentList, string.Empty, new { #class = "no-focus control-sm-7 form-control" })
#* #Html.ValidationMessageFor(m => m.AssessmentId, " ")*#
</div>
<div class="form-group">
#Html.LabelFor(x => x.StartDate, new { #class = "control-label" })
<div class="input-group col-xs-7">
#Html.TextBoxFor(x => x.StartDate, new { #class = "form-control date-picker", #readonly = "readonly" })
<label for="StartDate" class="input-group-addon glyphicon glyphicon-calendar add-on" />
</div>
</div>
I've searched and searched and i just have no clue what to search for . Can you guys give me tips plz ?
PS : dont mind the spaces at the data attrib, i was trying to get rid of the error when submitting this form at stackoverflow ( code 4 spaces ) .
i know the third parameter from the drop down is to select the default value, but this is string.Empty with the dropdownlist of assessment and this gets the correct value when clicking edit, and so not an empty string like the company dropdown... so logically this cannot be the problem
i found the problem !
Setting the viewdata property of the corresponding companyId which was linked to the dropdown, solved all my problems. I dont know why this worked at the other pages, maybe i just missed it .