ASP.NET MVC EditorFor and DateTime default value - asp.net-mvc

I want to set default value for an EditorFor HTML helper but just the helper text is displayed in it. Why EditorFor does not let me to set its default value, please?
class Person {
public int Id { get; set; }
public DateTime DateOfBirth { get; set; }
...
}
class PersonVM {
public Person { get; set; }
...
}
public ActionResult Edit(int id)
{
var vm = new PersonVM ();
vm.Person = db.Persons.Where(x => x.Id == id).FirstOrDefault();
...
return View(vm);
}
#model Project.Models.PersonVM
#Html.EditorFor(model => model.Person.DateOfBirth , new { htmlAttributes = new { #class = "form-control" } })

Set the default value by assigning a value to the model property.
Either in the Controller Action:
public ActionResult Edit(int id) {
var vm = new PersonVM ();
vm.Person = db.Persons.Where(x => x.Id == id).FirstOrDefault();
if (vm.Person.DateOfBirth == default(DateTime)) {
vm.Person.DateOfBirth = new DateTime(1900, 01, 01); // default value
}
// ...
return View(vm);
}
Or in the ViewModel (make sure that you only map valid DateOfBirth from the DB to the ViewModel):
public class PersonVM {
public PersonViewModel () {
DateOfBirth = new DateTime(1900, 01, 01); // default value
}
public int Id { get; set; }
public DateTime DateOfBirth { get; set; }
// ...
}

Related

Populate DropDownList in ASP.NET MVC from database table using Entity Framework 6 and ViewModel

I have been scratching my head for a whole night on an issue I can do quickly using ajax/jquery and stored procedures. I want to
1) Populate a drop down list from values obtained from a database table using Entity Framework and view model. I DO NOT WANT TO USE VIEWBAG OR VIEWDATA. Any help appreciated.
2) How can I generate a Create View using the View Model with the all the default fields ? The scaffholding works on a model but not on a view model ?
MY MODELS
public class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public string Level { get; set; }
public int DepartmentId { get; set; }
}
public class Grade
{
public int ID { get; set; }
public string Level { get; set; }
}
View Model
public class GradeSelectListViewModel
{
public Employee Employee { get; set; }
public IEnumerable<SelectListItem> Grades { get; set; }
public GradeSelectListViewModel(Employee employee, IEnumerable grades)
{
Employee = employee;
Grades = new SelectList(grades, "Grade", "Name", employee.Level);
}
}
MY CONTEXT CLASS
public class EmployeeContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Grade> Grades { get; set; }
}
MY CONTROLLER
public ActionResult Edit (int? id)
{
using (var db = new EmployeeContext())
{
var model = new GradeSelectListViewModel(db.Employees.Find(id), db.Grades);
//model.Employee = db.Employees.Single(x => x.EmployeeID == id);
model.Grades = db.Grades.ToList().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Level
});
return View(model);
}
}
MY RAZOR PAGE CSHTML
#model MVCDemo.ViewModels.GradeSelectListViewModel
....
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
....
#Html.DropDownListFor(x => Model.Employee.Level,
new SelectList(Model.Grades, "ID", "Level"),
"Select Level")
....
<input type="submit" value="Create" class="btn btn-default" />
}
The main issue is that in the view you have new SelectList(Model.Grades, "ID", "Level") but Grades is IEnumerable<SelectListItem> and SelectListItem does not contain properties named ID and Level.
However there are a a few other issues with your code. First a view model should not contain a data model, and instead your view model should be
public class GradeSelectListViewModel
{
public int? ID { get; set; } // make this ID so you do not need an input for it
public string Name { get; set; }
.... // other properties of Employee that your editing
[Required(ErrorMessage = "..")]
public int? Level { get; set; } // make value types nullable to protect against under-posting attacks
public IEnumerable<SelectListItem> Grades { get; set; }
}
and add display and validation attributes as required. Note that I deleted the constructor (you don't seem to be using it, but if you did, then you also need to include a parameter-less constructor, otherwise an exception will be thrown when submitting to the POST method. I also assume that Level should be typeof int since you binding to the int ID property of Grade.
The the code in your GET method should be
Employee employee = db.Employees.Find(id);
var model = new GradeSelectListViewModel()
{
ID = employee.EmployeeID,
Name = employee.Name,
Level = employee.Level, // convert to int?
....
Grades = db.Grades.Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Level
})
};
return View(model);
and in the view
#Html.DropDownListFor(x => Model.Level, Model.Grades, "Select Level")
Note also that in the POST method, your need to reassign the SelectList if you return the view because ModelState is invalid.
You can use the following approach that populates three DropDownListFor at the same View:
ViewModel:
public class GroupViewModel
{
public IEnumerable<SelectListItem> Schedules { get; set; }
public int ScheduleId { get; set; }
public IEnumerable<SelectListItem> Labs { get; set; }
public int LabId { get; set; }
public IEnumerable<SelectListItem> Terms { get; set; }
public int TermId { get; set; }
}
Controller:
public ActionResult Create()
{
//Populate DropDownList binding values
var model = new GroupViewModel
{
//Preselect the Lab with id 2
//LabId = 2,
Labs = repository.Labs.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
}),
Terms = repository.Terms.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
}),
Schedules = repository.Schedules.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
})
};
return View("Create", model);
}
View:
#Html.DropDownListFor(m => m.LabId, new SelectList(Model.Labs, "Value", "Text"),
"Select", new { #class = "selectpicker" })
#Html.DropDownListFor(m => m.ScheduleId, new SelectList(Model.Schedules, "Value", "Text"),
"Select", new { #class = "selectpicker" })
#Html.DropDownListFor(m => m.TermId, new SelectList(Model.Terms, "Value", "Text"),
"Select", new { #class = "selectpicker" })

Dropdown for Saving Model Not Working

The code will not save the value to the Musician Entity.
I'm using a ViewBag that is saving a SelectList and it displays the content from the database but on save it is null for the musician.PrimaryInstrument field when debugging.
Razor :
<td>
#Html.LabelFor(model => model.PrimaryInstrument, htmlAttributes: new { #class = "control-label col-md-2" })
</td>
<td>
#Html.DropDownList("InstrumentList")
</td>
Controller:
public ActionResult Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Musician musician = (Musician)db.Contractor.Find(id);
if (musician == null)
{
return HttpNotFound();
}
ViewBag.InstrumentList = new SelectList(db.Instrument, "ID", "Name");
return View(musician);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Musician musician, HttpPostedFileBase image)
{
if(ModelState.IsValid)
{
if (image != null)
{
UploadImage(musician, image);
}
musician.YearsOfExperience = Convert.ToInt16(Request["yearsOfExperience"]);
musician.CreateDate = DateTime.Now;
musician.NextDateAvailable = DateTime.Now;
db.Entry(musician).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Profile");
}
return View();
}
Instrument Model:
public class Instrument
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Musician> Musician { get; set; }
}
}
Musician Model:
public class Musician : Contractor
{
[Display(Name="Primary Instrument")]
public string PrimaryInstrument { get; set; }
[Display(Name = "Primary Genre")]
public string PrimaryGenre { get; set; }
[Display(Name = "Website Link")]
public string WebsiteLink { get; set; }
[Display(Name = "Youtube Link")]
public string YouTubeLink { get; set; }
[Display(Name = "SoundCloud Link")]
public string SoundCloudLink { get; set; }
[Display(Name = "ReverbNation Link")]
public string ReverbNationLink { get; set; }
public ICollection<Instrument> Instruments { get; set; }
}
Your not currently binding the selected instrument to the property PrimaryInstrument. Your helper should be
#Html.DropDownListFor(m => m.PrimaryInstrument, (SelectList)ViewBag.InstrumentList)
Note this will bind the ID property of Instrument to the property PrimaryInstrument
Note also that if ModelState is not valid, you also need to reassign the ViewBag.InstrumentList property - ViewBag.InstrumentList = new SelectList(db.Instrument, "ID", "Name"); before you call return View(musician);

How to use a View Model to populate a Drop Down list

I'm currently using a ViewBag to pass data to the DropDown list.
I want to use a model instead but I can't get it to work. Here is what I have :
public ActionResult Index(int? catID)
{
GiftListItems viewModel = new GiftListItems
{
Categories = **how do I use this property for DropDown list ?**
};
// using this for DropDown list now :
var query = _categoryRepository.Table
.Select(x => new { x.Id, x.Name })
.Distinct()
.OrderBy(x => x.Name);
ViewBag.Values = new SelectList(query.AsEnumerable(), "Id", "Name");
return View(viewModel);
}
In View :
#Html.DropDownList("catID", (SelectList)ViewBag.Values, new { onchange = "this.form.submit();" })
Model :
public class GiftListItems
{
public IEnumerable<Category> Categories { get; set; }
}
Is this easy to do? Thanks
public class Model
{
public int SelectedItem{get;set;}
public IList<DropDownObj> ListObj{get;set;
public IList<SelectListItem> SelectListItemListObj{get;set;}
{
get
{
var list = (from item in ListObj
select new SelectListItem()
{
Text = item.Id.ToString(CultureInfo.InvariantCulture),
Value item.Name
}).ToList();
return list;
}
set{}
}
}
public class DropDownObj
{
public int Id{get;set;}
public string Name{get;set;
}
usage:
#Html.DropDownListFor(c=>c.SelectedItem,Model.SelectListItemListObj)
Example:
Models:
public class VmSysCategoryModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class GiftListItemsDropDown
{
public int SelectedCategoryId { get; set; }
public IEnumerable<VmSysCategoryModel> Categories { get; set; }
public IList<SelectListItem> SelectListItemListObj
{
get
{
var list = (from item in Categories
select new SelectListItem()
{
Text = item.Id.ToString(CultureInfo.InvariantCulture),
Value=item.Name
}).ToList();
return list;
}
set { }
}
}
Controller:
public ActionResult Index(int? catID)
{
var listCategories = _categoryRepository.Table
.Select(x => new {x.Id, x.Name})
.Distinct()
.OrderBy(x => x.Name);
var obj = new GiftListItemsDropDown()
{
Categories = Mapper.Map<IList<listCategories>, IList<VmSysCategoryModel>>(listCategories)
//here you mast to map from domain to viewmodel
};
return View(obj);
}
View:
#model GiftListItemsDropDown
#Html.DropDownListFor(c=>c.SelectedCategoryId ,Model.SelectListItemListObj)
You can use the view model like this -
public ActionResult NewsEdit(int ID, dms_New dsn)
{
var query = _categoryRepository.Table
.Select(x => new { x.Id, x.Name })
.Distinct()
.OrderBy(x => x.Name)).ToList();
GiftListItems viewModel = new GiftListItems
{
Categories = query.Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
})
};
return View(viewModel);
}
and in your view -
#model GiftListItems
#Html.DropDownList(
"catID",
Model.Categories,
new { onchange = "this.form.submit();" }
)
And your View model now should look like this -
public class GiftListItems
{
public IEnumerable<SelectListItem> Categories { get; set; }
// public IEnumerable<Category> Categories { get; set; } --
}

Partial Create view with ViewModel has a data type mismatch

I am using a ViewModel for a create action, which consists of an entity with type Device and two IEnumerable<SelectListItem> to poulate 2 dropdownlists while creating a new item.
public class DeviceEditViewModel
{
public Device dev { get; set; }
public int SelectedManufactor { set; get; }
public IEnumerable<SelectListItem> ManufactorListItems { get; set; }
public int SelectedCategory { set; get; }
public IEnumerable<SelectListItem> CategoriesListItems { get; set; }
}
public ActionResult Create()
{
var vm = new DeviceEditViewModel
{
CategoriesListItems = repo.GetCategories().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
}),
ManufactorListItems = repo.GetManufactors().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
})
};
return View(vm);
}
There is per se nothing wrong with that, as I can create, read and update everything just fine.
Now I wanted to update my Index View to hold a partial Create View. On the right side of the page, there should be the same create form as in the standalone view.
<div class="col-lg-4">
#{ Html.RenderPartial("_Create", new DeviceEditViewModel()); }
</div>
Now upon running this, I recieve the following error (free translation):
"SelectedManufactor" is of type "System.Int32", but requires the type "IEnumerable<SelectListItem>".
The Index view renders and wants to call the Create Method in the device controller. The Create method instanciates a new DeviceEditViewModel and populates two IEnumerable<SelectListItem>. Why does this fail in the partial View, but not in the regular View - And how can I solve this?
UPDATE
Lins answer was not totally correct, but brought me on the right track - which in my world counts as an upvote and an acceptance as the answer.
What I've done is created an DeviceIndexViewModel, which holds the EditViewModel, which is needed for creating/editing Devices.
public class DeviceIndexViewModel
{
public IEnumerable<Device> Devices { get; set; }
public DeviceEditViewModel DeviceEditViewModel { get; set; }
}
Now the Index Action needed to be updated accordingly:
public ActionResult Index(string searchString)
{
DeviceIndexViewModel vm = new DeviceIndexViewModel();
// ...
// omitted
// ...
vm.DeviceEditViewModel = new DeviceEditViewModel()
{
CategoriesListItems = repo.GetCategories().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
}),
ManufactorListItems = repo.GetManufactors().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
})
};
return View(vm);
}
Now I could call the PartialView with:
#{ Html.RenderPartial("_Create", Model.DeviceEditViewModel); }
And finally tell the partialView to call a specific method:
#using (Html.BeginForm("Create", "Device", FormMethod.Post))
{
// ... omitted
}
Thanks
You need to create the DeviceEditViewModel like below, then use it as strongly typed view in your Index View, then pass the object DropDownListViewModel to your partial view.
public class DeviceEditViewModel
{
public Device dev { get; set; }
public DropDownListViewModel DropDownListViewModels { get; set; }
}
public class DropDownListViewModel
{
public int SelectedManufactor { set; get; }
public IEnumerable<SelectListItem> ManufactorListItems { get; set; }
public int SelectedCategory { set; get; }
public IEnumerable<SelectListItem> CategoriesListItems { get; set; }
}
Pass the object DropDownListViewModel to your partial view
#{ Html.RenderPartial("_Create", Model.DropDownListViewModels);}
Change your Create action method like below:
public ActionResult Create()
{
var vm = new DeviceEditViewModel
{
DropDownListViewModels = new DropDownListViewModel()
{
CategoriesListItems = repo.GetCategories().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
}),
ManufactorListItems = repo.GetManufactors().Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
})
}
};
return View(vm);
}
Your partial view:
#model DropDownListViewModel
#Html.DropDownListFor(n => n.SelectedManufactor, Model.ManufactorListItems)
#Html.DropDownListFor(n => n.SelectedCategory, Model.CategoriesListItems)

ASP.NET MVC DropDownListFor Model binding

I am trying to bind a dropdown to my model, but I am having issues. My model that is passed into my HttpPost function is NULL, but only if I try to bind to the "product" object's CategoryID field. If I exclude trying to bind to product.CatgeoryID, then the IncidentNumber string is not null. Thanks for any input.
Here is my model.
public class BIFireTypeModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Product
{
public int CategoryID { get; set; }
public Product()
{
CategoryID = 0;
}
}
And here is my controller:
//
// GET: /BasicIdentification/
[HttpGet]
public ViewResult BasicIdentificationIndex()
{
Product newproduct = new Product();
ViewModelData vmd = new ViewModelData();
vmd.product = newproduct;
vmd.product.CategoryID = 2;
ViewBag.Categories = GetItems();
return View(vmd);
}
[HttpPost]
public ActionResult BasicIdentificationIndex(ViewModelData product)
{
ViewBag.Categories = GetItems();
return View(product);
}
public List<BIFireTypeModel> GetItems()
{
List<BIFireTypeModel> categories = new List<BIFireTypeModel>();
categories.Add(new BIFireTypeModel() { ID = 1, Name = "IA" });
categories.Add(new BIFireTypeModel() { ID = 2, Name = "Extended Attack" });
categories.Add(new BIFireTypeModel() { ID = 3, Name = "Large Fire Support" });
return categories;
}
public class ViewModelData
{
public String IncidentNumber { get; set; }
public Product product { get; set; }
}
And finally my cshtml:
#{
using (Html.BeginForm())
{
<h4>Incident Number</h4><input id="txtIncidentNumber" name="IncidentNumber" type="text" />
#Html.DropDownListFor(x => x.product.CategoryID, new SelectList(ViewBag.Categories, "ID", "Name"))
#* WILL CAUSE IncidentNumber in BasicIdentificationIndex(ViewModelData product) TO BE NULL
<h4>Incident Number</h4><input id="afasf" name="product.CategoryID" type="text" />
*#
<input type="submit" value="Submit" />
}
}
EDIT
In my Post function, I can access product.CategoryID with Request[] like so:
[HttpPost]
public ActionResult BasicIdentificationIndex(ViewModelData product)
{
String tmp = Request["product.CategoryID"];
ViewBag.Categories = GetItems();
return View(product);
}
And it returns the right value. But this value will not bind in my model, and if I try to use DropDownListFor at all with product, ALL VALUES in ViewModelData product will be null.
FIXED:
Here is the issue.
public ActionResult BasicIdentificationIndex(ViewModelData product)
public class ViewModelData
{
public Employee product { get; set; }
}
The NAME of my object in my ViewModelData was the same as the PARAMETER in BasicIdentificationIndex(). This caused major issues. All I had to do was change the name.
EDIT:
Something else that is very IMPORTANT is that when I was using EditorForModel(), my dropdowns weren't binding, but when I would manually create them with #Html.EnumDropDownListFor the binding worked. Good to know.
Here is an example approach that populates three DropDownListFor at the same View:
ViewModel:
public class GroupViewModel
{
public IEnumerable<SelectListItem> Schedules { get; set; }
public int ScheduleId { get; set; }
public IEnumerable<SelectListItem> Labs { get; set; }
public int LabId { get; set; }
public IEnumerable<SelectListItem> Terms { get; set; }
public int TermId { get; set; }
}
Controller:
public ActionResult Create()
{
//Populate DropDownList binding values
var model = new GroupViewModel
{
//Preselect the Lab with id 2
//LabId = 2,
Labs = repository.Labs.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
}),
Terms = repository.Terms.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
}),
Schedules = repository.Schedules.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
})
};
return PartialView("_Create", model);
}
View:
#Html.DropDownListFor(m => m.LabId, new SelectList(Model.Labs, "Value", "Text"),
"Select", new { #class = "selectpicker" })
#Html.DropDownListFor(m => m.ScheduleId, new SelectList(Model.Schedules, "Value", "Text"),
"Select", new { #class = "selectpicker" })
#Html.DropDownListFor(m => m.TermId, new SelectList(Model.Terms, "Value", "Text"),
"Select", new { #class = "selectpicker" })
Hope this helps...

Resources