I am not an expert MVC programmer but have to make a small change in the code. Any help?
I have a field CallerType which had [required] attribute. However, I do not want to be mandatory anymore so I am removing [required] attribute but still get the same input required error.
public virtual CallType CallType { get; set; }
[Display(Name = "Type of Calls")]
/*Akbar-start*[Required]*Akbar-end*/
public int CallTypeID { get; set; }
<div class="form-group col-3">
<label asp-for="Intake.CallTypeID" class="control-label"></label>
<select asp-for="Intake.CallTypeID"class="form-control">asp-items="Model.CallTypes">
<option value="">Please Select</option>
</select>
<span asp-validation-for="Intake.CallTypeID" class="text-danger"></span>
</div>
Error:
enter image description here
I also see javascript like below but not sure how this is getting invoked:
$('input').each(function () {
var req = $(this).attr('data-val-required');
var hide = $(this).attr('hide-required-indicator');
var hasIndicator = $(this).hasClass('has-required-indicator');
if (undefined != req && undefined == hide && !hasIndicator) {
var label = $('label[for="' + $(this).attr('id') + '"]');
var text = label.text();
if (text.length > 0) {
label.append('<span style="color:red" class="required-indicator"> *</span>');
$(this).addClass('has-required-indicator');
}
}
});
$('select').each(function () {
var req = $(this).attr('data-val-required');
var hasIndicator = $(this).hasClass('has-required-indicator');
if (undefined != req && !hasIndicator) {
var label = $('label[for="' + $(this).attr('id') + '"]');
var text = label.text();
if (text.length > 0) {
label.append('<span style="color:red"> *</span>');
$(this).addClass('has-required-indicator');
}
}
});
I was able to solve this issue.
Here is the trick:
Changed int to int?
public int CallTypeID { get; set; }
i.e.
public int? CallTypeID { get; set; }
? indicates that this field is nullable. It was overriding [Required] attribute
Related
My requirement is I have 4 textboxes rendered using a for loop on model, when I entered a value and focus out of any text box, I need to capture the value into a variable and show it in a span before submit
I have tried with call a function in blur event
<EditForm EditContext="#EditContext">
<DataAnnotationsValidator />
#for (int j = 0; j < transactionModels.Count; j++)
{
int i = j;
<input type="text" class="form-control"
#bind="transactionModels[i].Amount" #onblur="Getvalue" placeholder="Amount" />
<span>**Textboxvalue** </span>
}
</EditForm>
#code{
public void Getvalue()
{
Textboxvalue= transactionModels.Amount
}
The code below is a demo page showing how to link an array of values into a set of text boxes and have the array update. You should be able to adapt it to your specific circumstances. (I made an assumption that amount is a number, not text).
#page "/"
<h2>Home Page</h2>
<EditForm EditContext="this.editContext">
#foreach (var modelData in _model.data)
{
<div>
<InputNumber #bind-Value="modelData.Amount"></InputNumber>
</div>
<div>
Value: #modelData.Amount
</div>
}
</EditForm>
#code {
public class ModelData
{
public int Amount { get; set; }
}
public class Model
{
public List<ModelData> data = new List<ModelData> {
new ModelData { Amount = 12},
new ModelData { Amount = 10},
new ModelData { Amount = 8},
new ModelData { Amount = 6},
};
}
private EditContext editContext;
protected Model _model { get; set; } = new Model();
protected override Task OnInitializedAsync()
{
editContext = new EditContext(_model);
return base.OnInitializedAsync();
}
}
Stick with #foreach for these situations. If you use #for you need to define a local variable for each loop.
I don't think you really need to use "onblur", which is javascript-minded, not Blazor.
Replace your <input type="text"... by
<InputText type="text" class="form-control" #bind-Value="transactionModels[i].Amount" placeholder="Amount" />
The span should become
<span>#transactionModels[i].Amount </span>
If transactionModels[i].Amount is of numeric type (what is suggested by the name, but not your choice of type="text"), replace <InputText type="text" by <InputNumber.
If it is a string, do not forget to remove special characters to prevent XSS.
Edit after 2nd comment:
In the transactionModel class, add these properties
private double amount;
internal double Amount
{
get => amount;
set
{
LoanRelatedPopupVisible = (value < 0);
DepositRelatedPopup = (value > 0);
amount = value;
}
}
internal bool LoanRelatedPopupVisible { get; set; }
internal bool DepositRelatedPopup { get; set; }
To manage the visibility of the popup
#if (transactionModels[i].LoanRelatedPopupVisible)
{
<div here the popup ...
}
I am using a razor view for showing the scored of an examination and it contains an enum value that holds 3 values "pass","Fail","absent" and i want to choose it accordingly. The model i used is
model
public class VerifyResultModel
{
[Display(Name = "StudnetId")]
public int StudentId { get; set; }
[Display(Name = "Student")]
[Required]
public string Student { get; set; }
[Display(Name = "Mark")]
[Required]
public int Mark { get; set; }
[Display(Name = "Score")]
[Required]
public string Score { get; set; }
[Display(Name = "Result")]
public App.EnumValues.ExamResultStatus Result { get; set; }
}
Controller
[HttpGet]
public ActionResult Verify(int Id)
{
List<VerifyResultModel> model_result = new List<VerifyResultModel>();
VerifyResultModel _resultItem;
foreach (exammark item in marks)
{
SchoolApp.EnumValues.ExamResultStatus result = SchoolApp.EnumValues.ExamResultStatus.Absent;
if(item.Mark >= MinMark)
{
result= SchoolApp.EnumValues.ExamResultStatus.Pass;
}
else
{
result = App.EnumValues.ExamResultStatus.Fail;
}
_resultItem = new VerifyResultModel { StudentId = (int)item.StudentId, Student = item.studentmaster.StudentName, Mark = (int)item.Mark, Score = item.Mark.ToString(), Result = result };
model_result.Add(_resultItem);
}
LoadResultsDropdown();
return View(model_result);
}
private void LoadResultsDropdown()
{
var types = (from App.EnumValues.ExamResultStatus type in Enum.GetValues(typeof(SchoolApp.EnumValues.ExamResultStatus))
select new { Id = type.ToString(), Name = type.ToString() }).ToList();
ViewBag.ResultList = new SelectList(types, "Id", "Name");
}
View
#model IList<SchoolApp.ViewModels.VerifyResultModel>
<tbody>
#for (int item = 0; item < Model.Count(); item++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[item].Student)
</td>
<td>
#Html.DisplayFor(modelItem => Model[item].Mark)
</td>*#
<td>
#Html.DisplayFor(modelItem => Model[item].Score)
</td>
<td>
#Html.DropDownListFor(model => model[item].Result, (SelectList)ViewBag.ResultList) //Here All values are showing as Pass ( first item in dropdown)
</td>
</tr>
}
</tbody>
The problem is even if i pass values Fail / Absent to enum it shows as Pass in combobox . How can i show the correct value ?
Can you please try this:
private void LoadResultsDropdown()
{
var types = (from App.EnumValues.ExamResultStatus type in Enum.GetValues(typeof(SchoolApp.EnumValues.ExamResultStatus))
select new { Id = type.ToString(), Name = type.ToString() }).ToList();
var types=Enum.GetValues(typeof(ExamResultStatus)).Cast<ExamResultStatus>();
var EnumData= types.Select(c => new { c.Key, c.Value });
ViewBag.ResultList = new SelectList(types.AsEnumerable(), "key", "value");
}
Hope this helps..
I have a viewmodel to use in the Create view:
ViewModel
public class ReportViewModel
{
public int ID { get; set; }
[Display(Name = "Platform")]
public string Platform { get; set; }
[Display(Name = "Logo")]
public HttpPostedFileBase Logo { get; set; }
}
Create View
#model HPRWT.ViewModels.ReportViewModel
#using (Html.BeginForm("Create", "Report", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="editor-label">
#Html.LabelFor(model => model.Platform )
#Html.EditorFor(model => model.Platform )
#Html.ValidationMessageFor(model => model.Platform)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Logo)
<input type="file" id="Logo" name="Logo" />
</div>
}
This work perfect. But now I need an array of checkboxes (7x24) to get free hours (7 day, 24 hours). I have an array of ids (i need a defined id because I use jquery). In Create view:
#for(int i = 1; i < labels.Length; i++)
{
<tr>
<td>#labels[i][0]</td>#for(int j = 1; j < labels[i].Length; j++)
{
<td><div><input type="checkbox" id="#ids[i][j]" /><label for="#ids[i][j]"></label></div></td>
}
My ids are like R02C00 (R of row + numer of row with 2 digits + C (column) + number of column (2 digits). I generate them with:
for (int i = 1; i < 8; i++)
for (int j = 1; j < 25; j++)
ids[i][j] = "R" + i.ToString("00") + "C" + (j-1).ToString("00");
This also works well. Now my problem is how I get the checkboxes values.
Controller
[HttpPost]
public ActionResult Create(ReportViewModel rvm)
{
if (ModelState.IsValid)
{
rdb.Reports.Add(CreateReport(rvm));
rdb.SaveChanges();
return RedirectToAction("Index");
}
return View(rvm);
}
// Create a report from a reportviewmodel
private Report CreateReport(ReportViewModel rvm)
{
Report report = new Report();
// Platform
string platform = rvm.Platform;
report.Platform = platform ;
// Logo
HttpPostedFileBase inputFile = rvm.InputFile; // Some code to get the path
return report;
}
How can I get the checkboxes values? If I add in reportviewmodel a bool[][], is there is any way to do a #Html.Checkbox? (If I have to change ids names in jquery, I donĀ“t mind, is not mandatory to have a id like R01C01... only the ids in jquery be the same as html)
Why don't you use a view model?
public class FreeHourViewModel
{
public string Label { get; set; }
public bool Selected { get; set; }
}
public class ReportViewModel
{
public ReportViewModel()
{
this.FreeHours = Enumerable
.Range(1, 7)
.Select(day =>
Enumerable.Range(1, 24).Select(hour => new FreeHourViewModel
{
Label = string.Format("day: {0}, hour: {1}", day, hour)
}
).ToArray()
).ToArray();
}
public int ID { get; set; }
[Display(Name = "Platform")]
public string Platform { get; set; }
[Display(Name = "Logo")]
public HttpPostedFileBase Logo { get; set; }
public FreeHourViewModel[][] FreeHours { get; set; }
}
and then:
#for (int i = 0; i < Model.FreeHours.Length; i++)
{
for (int j = 0; j < Model.FreeHours[i].Length; j++)
{
#Html.LabelFor(x => x.FreeHours[i][j].Selected, Model.FreeHours[i][j].Label)
#Html.CheckBoxFor(x => x.FreeHours[i][j].Selected)
}
}
And when the form is submitted, since you have used a real view model, model binding will work as expected. Also you don't need any jQuery to generate those checkboxes. Strongly typed helpers such as Html.CheckBoxFor is the way to go.
How about having a strongly-typed view in relation to your checkboxes?
public class ReportViewModel
{
public ReportViewModel()
{
Days = new List<Day>();
}
public int ID { get; set; }
[Display(Name = "Platform")]
public string Platform { get; set; }
[Display(Name = "Logo")]
public HttpPostedFileBase Logo { get; set; }
public IList<Day> Days { get; set; }
}
public class Hour
{
public int Id { get; set; }
public bool Selected { get; set; }
}
public class Day
{
public Day()
{
Hours = new List<Hour>();
}
public int Id { get; set; }
public bool Selected { get; set; }
public IList<Hour> Hours { get; set; }
}
You then return a view like this:
foreach (var d in Enum.GetValues(typeof(DayOfWeek)))
{
var day = new Day { Id = (int)d };
for (var i = 0; i < 25; i++)
{
day.Hours.Add(new Hour { Id = i });
}
model.Days.Add(day);
}
return View(model);
And add this to your view:
for (var i = 0; i < 7; i++)
{
<div id="days">
<ul>
#for (var j = 0; j < 24; j++)
{
<li>#Html.CheckBoxFor(m=>Model.Days[i].Hours[j].Selected)</li>
}
</ul>
</div>
}
Now when you receive your input you have an array of bool values where you have a sort of Ids, that is 0-6 for days and 0-23 for hours. You can easily determine what hour in what particular day was selected.
Of course, you have to fill in the missing pieces with my suggestion like showing the labels for each checkboxes.
I have a main view using a ViewModel. Inside the ViewModel I do this (Edited to show complete ViewModel):
namespace MyNameSpace.ViewModels
{
public class MyViewModel
{
public ModelOne ModelOne { get; set; }
public ModelTwo ModelTwo { get; set; }
}
}
On my main view I do this (EDIT: Added #Html.Hidden code):
#using MyNameSpace.ViewModels
#using MyNameSpace.Models
#model MyViewModel
...
#using (Html.BeginFormAntiForgeryPost())
{
#Html.Hidden("myData", new MvcSerializer()
.Serialize(Model, SerializationMode.Signed))
....
<div>
#{Html.RenderPartial("_MyCheckBox",
Model.ModelTwo, new ViewDataDictionary());}
</div>
}
....
My partial view is:
#using MyNameSpace.Models
#model ModelTwo
<div>
<fieldset>
<div class="editor-label">
#Html.LabelFor(x => x.MyCheckBox)</div>
<div class="editor-field">
<select multiple="multiple" id="#Html.FieldIdFor(x =>
x.MyCheckBox)" name="#Html.FieldNameFor(x =>
x.MyCheckBox)">
#foreach (MyEnum item in Enum.GetValues(typeof(MyEnum)))
{
var selected = Model.MyCheckBox.Contains(item); //ERROR HERE
<option value="#((int)item)" #if (selected)
{<text>selected="selected"</text>}>
#T(item.ToString())
</option>
}
</select>
</div>
</fieldset>
</div>
I am getting the Object reference not set to an instance ... error and am not sure how to correct it.
Originally, I had that <fieldset> inside my main view and was getting that error. I thought it was because of the two models and that's why I placed it in a partial view. But only to discover I am running into the same problem.
I am not setting the MyCheckBox in my partial view on the line var selected = Model.MyCheckBox.Contains(item); properly.
Any thoughts?
EDIT (Adding MyCheckBox code)
Here is MyCheckBox inside ModelOne.cs:
[Mandatory(ErrorMessage = "Please select at least one option")]
[Display(Name = "Please select one ore more options")]
[MySelector]
public virtual int MyCheckBox { get; set; }
And here it is inside ModelTwo.cs:
private IList<MyEnum> _myEnum;
public IList<MyEnum> MyCheckBox
{
get
{
if (_myEnum== null)
{
_myEnum= new List<MyEnum>();
foreach (MyEnumitem in Enum.GetValues(typeof(MyEnum)))
{
if (((MyEnum)Record.MyCheckBox& item) == item)
_myEnum.Add(item);
}
}
return _myEnum;
}
set
{
_myEnum= value;
Record.MyCheckBox= 0;
foreach (var item in value)
{
Record.MyCheckBox|= (int)item;
}
}
}
Please note, I am using Orchard (hence the Record) which, in turn, uses NHibernate. I don't believe that is relevant, but I could be wrong. The MyCheckBox code is using [Flags] attribute of enum and storing the value as an int in the DB (hence the proxy). Here is what the enum would look like:
MyEnum.cs:
[Flags]
public enum MyEnum
{
[Display(Name="Name 1")]
Enum1 = 1,
[Display(Name="Name 2")]
Enum2 = 2,
[Display(Name="Name 3")]
Enum3 = 4,
[Display(Name="Name 4")]
Enum4 = 8,
[Display(Name="Name 5")]
Enum5 = 16
}
MyController.cs
private MyViewModel myData;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var serialized = Request.Form["myData"];
if (serialized != null) //Form was posted containing serialized data
{
myData= (MyViewModel)new MvcSerializer().Deserialize
(serialized, SerializationMode.Signed);
TryUpdateModel(myData);
}
else
myData= (MyViewModel)TempData["myData"] ?? new MyViewModel();
TempData.Keep();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["myData"] = myData;
}
Then in the particular Action within *MyController.cs:
public ActionResult Step5(string backButton, string nextButton)
{
if (backButton != null)
return RedirectToAction("Step4");
else if ((nextButton != null) && ModelState.IsValid)
return RedirectToAction("Confirm");
else
return View(myData);
}
I defined a Person entity:
public partial class Person
{
public string persID { get; set; }
public string last_name { get; set; }
public string driving_licence { get; set; }
}
where the driving licence is as follows:
public class DrivingLicence
{
public string drivingLicenceValue { get; set; }
public string drivingLicenceText { get; set; }
public DrivingLicence(string paValue, string paText)
{
drivingLicenceValue = paValue;
drivingLicenceText = paText;
}
}
having a repository where is defined this function:
public List<DrivingLicence> GetAll()
{
try
{
var drivingLicenceList = new List<DrivingLicence>();
DrivingLicence oneDrivingLicence = new DrivingLicence("A", "A");
drivingLicenceList.Add(oneDrivingLicence );
oneDrivingLicence = new DrivingLicence("B", "B");
drivingLicenceList.Add(oneDrivingLicence );
oneDrivingLicence = new DrivingLicence("C", "C");
drivingLicenceList.Add(oneDrivingLicence );
oneDrivingLicence = new DrivingLicence("D", "D");
drivingLicenceList.Add(oneDrivingLicence );
return drivingLicenceList;
}
catch (Exception)
{
throw new Exception("An error occured. Failed to Get the list.");
}
}
Now: I want the driving licences displayed as a CheckBoxList and on submit I want the person to get assigned the checked driving licence categories, e.g.: the "A" and "C" categories are selected, the resulting person.driving_licence must be "AC".
The problem is that this does not happen, the person is created but the driving_licence property is empty. I payed attention that the check boxes name be identical to that of the corresponding property (Person.driving_licence).
Is that an error in the present code? Or should I modify the Person entity?
Thank you for your advice.
Here is the view model:
public class PersonFormViewModel
{
// Properties
public Person person { get; set; }
public SelectList DrivingLicenceList { get; set; }
public string ActionToPerform { get; set; }
public PersonFormViewModel() { }
// Constructor
public PersonFormViewModel(Person pPerson, SelectList pDrivingLicenceList)
{
person= pPerson;
DrivingLicenceList = pDrivingLicenceList;
if (String.IsNullOrEmpty(person.persID))
{
ActionToPerform = "Create";
}
else
{
ActionToPerform = "Edit";
}
}
}
The controller:
//
// GET: /Person/Create
[Authorize]
public ActionResult Create()
{
Person person = new Person();
SelectList drvLicenceList = new SelectList(drvLicenceRepository.GetAll(), "drivingLicenceValue", "drivingLicenceText");
return View("Create", new PersonFormViewModel(person, drvLicenceList));
}
//
// POST: /Person/Create
[HttpPost, Authorize]
public ActionResult Create(PersonFormViewModel model)
{
Person person = model.person;
SelectList drvLicenceList = new SelectList(drvLicenceRepository.GetAll(), "drivingLicenceValue", "drivingLicenceText");
if (ModelState.IsValid)
{
try
{
db.Entry(person).State = EntityState.Added;
db.SaveChanges();
return RedirectToAction("Details");
}
catch (...)
{
...
}
}
return View("Create", new PersonFormViewModel(person, drvLicenceList));
}
And the view:
#model MyApp.ViewModels.PersonFormViewModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm())
{
#Html.ValidationSummary(false, "Errors occured.")
<fieldset>
<legend>Fill in your details</legend>
#Html.LabelFor(model => model.person.last_name)
#Html.TextBoxFor(model => model.person.last_name)
#Html.ValidationMessageFor(model => model.person.last_name, "*")
#Html.HiddenFor(model => model.person.persID)
#foreach (var ctg in (Model.DrivingLicenceList))
{
<input type="checkbox" name="driving_licence" value=ctg.value />#ctg.Text
}
<input type="submit" value="Sauvegarder" class="submit" />
</fieldset>
}
I would use a collection property in order to store the selected driving licence categories (multiple checkboxes can be selected => collection):
public partial class Person
{
public string persID { get; set; }
public string last_name { get; set; }
public string[] driving_licence { get; set; }
}
and then you will need to fix the name of the checkbox in order for it to bind correctly:
#foreach (var ctg in Model.DrivingLicenceList)
{
<input type="checkbox" name="person.driving_licence" value="#ctg.Value" />
#ctg.Text
}
and if you wanted to preserve the selected values you will need to set the checked property accordingly:
#foreach (var ctg in Model.DrivingLicenceList)
{
<input type="checkbox" name="person.driving_licence" value="#ctg.Value" #((Model.person.driving_licence ?? Enumerable.Empty<string>()).Contains(ctg.Value) ? "checked=\"checked\"" : "") />
#ctg.Text
}
This being said, we now have a working solution but it is far from anything I would content myself with and stop here. From now on we could start refactoring this mess in order to comply with C# naming conventions (things like property names start with capital letter, ...), introduce real view models (which do not reference domain models), custom HTML helpers that will generate this checkbox lists to avoid writing loops in the views and hardcoding checkboxes, ...