I read that EditorTemplates are loaded automatically, but from asp.net mvc 2 and now 3 with razor, I still cant get this to work.
My model looks like this:
public class RoleViewModel
{
public int RoleId { get; set; }
public bool InRole { get; set; }
public string RoleName { get; set; }
}
public class UserViewModel
{
public User User { get; set; }
public IEnumerable<RoleViewModel> Roles { get; set; }
}
My view looks like this:
~/Views/Roles/Edit.cshtml
#model Project.Web.ViewModel.UserViewModel
#using (Html.BeginForm()) {
#Html.EditorFor(model => model.Roles)
<!-- Other stuff here -->
}
~/Views/Roles/EditorTemplates/RoleViewModel.cshtml
#model Project.Web.ViewModel.RoleViewModel
#foreach (var i in Model)
{
<div>
#i.RoleName
#Html.HiddenFor(model => i.RoleId)
#Html.CheckBoxFor(model => i.InRole)
</div>
}
If i move the content from the EditorTemplate to the actual page, then it works, it shows the checkbox, etc. But with this current setup, all that shows up is the count of the number of roles.
What am I doing wrong?
~/Views/Roles/EditorTemplates/RoleViewModel.cshtml
#model MvcApplication16.Controllers.RoleViewModel
<div>
#Model.RoleName
#Html.HiddenFor(m => m.RoleId)
#Html.CheckBoxFor(m => m.InRole)
</div>
~/Views/Roles/Edit.cshtml
#model MvcApplication16.Controllers.UserViewModel
#using (Html.BeginForm()) {
#Html.EditorFor(m => m.Roles)
<!-- Other stuff here -->
}
Models
public class UserViewModel {
public User User { get; set; }
public IEnumerable<RoleViewModel> Roles { get; set; }
}
public class RoleViewModel {
public int RoleId { get; set; }
public bool InRole { get; set; }
public string RoleName { get; set; }
}
public class User {
public string Name { get; set; }
}
Controller
public ActionResult Edit() {
return View(
new UserViewModel() {
User = new User() { Name = "Test" },
Roles = new List<RoleViewModel>() {
new RoleViewModel() {
RoleId = 1,
InRole = true,
RoleName = "Test Role" }}
});
}
The above code works just fine. Compare it with yours and see if you see anything amiss :)
Related
I wanted to add the value of checkbox ids to many to many relation table between two tables Course-Student
i have 3 tables Course{ CourseID,CourseName }, Studdent{StudentID,StudentName} and CourseStudet{CourseID, StudentID}
Course table already have course{1.DataScience,2.English,3.Physics}
while Inserting Student i have shown course checkboxes with these options fetching list of these courses from database to show in view to user when he is about to register now i am confused how to insert into database?
public class CourseModel {
public List<Course> mycourse{ get; set; }
public string StudentName {get; set;}
}
EF generated Class
public partial class Course
{
public Course()
{
this.Student= new HashSet<Student>();
}
public int CourseID { get; set; }
public string CourseName { get; set; }
i have inserted this field to check for checked value
public bool Ischecked { get; set; }
public virtual ICollection<Student> Student { get; set; }
}
public partial class Student
{
public Student()
{
this.Course= new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public virtual ICollection<Course> Course{ get; set; }
}
public ActionResult Index()
{
CourseModel coursemodel = new CourseModel();
using (Entities db = new Entities())
{
coursemodel.mycourse = db.Course.ToList<Course>();
return View(coursemodel);
}
}
[HttpPost]
public ActionResult Index(CourseModel course)
{
return View(course);
}
View
#using (Html.BeginForm("index", "Course", FormMethod.Post))
<input type="Text" name="StudentName" placeholder="Name" />
{
<table>
#for (int i = 0 ; i < Model.mycourse.Count; i++)
{
if (i % 3 == 0) {
#:<tr></tr>
}
<div>
#Html.CheckBoxFor(x => x.mycourse[i].Ischecked)
<label>#Model.mycourse[i].CourseName</label>
#Html.HiddenFor(x => x.mycourse[i].CourseID)
#Html.HiddenFor(x => x.mycourse[i].CourseName)
</div>
}
</table>
<input type="submit" value="Submit" />
}
i am getting checkbox id,name and which course is checked now how can i add student with including these values to relationship table CourseStudent ?
You have problems with your database design. Remove ischecked field.Remember while you are designing entities, you shouldn't put fields that are for view. It is like that I make Reports table from my each query.
correct your models
public partial class Course
{
public Course()
{
this.Student = new HashSet<Student>();
}
public int CourseID { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Student> Student { get; set; }
}
public partial class Student
{
public Student()
{
this.Course = new HashSet<Course>();
}
public int StudentID { get; set; }
public string StudentName { get; set; }
public virtual ICollection<Course> Course { get; set; }
}
Add viewmodels(You can use view models for showing custom data for your view)
You can read more
ViewModel
public class CourseViewModel
{
public Course course { get; set; }
public bool CheckBox { get; set; }
}
public class StudentCourseViewModel
{
public List<CourseViewModel> coursesVM { get; set; }
public Student student { get; set; }
}
Controller
public ActionResult index()
{
Entities db = new Entities();
List<CourseViewModel> courselist = new List<CourseViewModel>();
foreach (var item in db.Course.ToList())
{
courselist.Add(new CourseViewModel { course = item});
}
StudentCourceViewModel model = new StudentCourseViewModel(
{
student = new student(),
coursesVM = courselist }
};
return View(model);
}
[HttpPost]
public ActionResult Save(StudentCourseViewModel model)
{
Entities db = new Entities();
Student stdindb = db.Students.FirstorDefault(c => c.StudentName == model.student.StudentName);
if(stdindb == null)
{
stdindb = new student(){//your properties};
db.students.add(stdindb);
}
foreach (var item in model.coursesVM)
{
if (item.Ischecked)
{
stdindb.Course.Add(db.course.single(c=>c.CourseId == item.course.CourseId ));
}
}
db.SaveChanges();
return View();
}
View
#model SchoolCMS.Models.StudentCourseViewModel
#{
ViewBag.Title = "Select Course";
}
#using (Html.BeginForm("Save", "home", FormMethod.Post))
{
#Html.TextBoxFor(c=>c.student.StudentName)
<table>
#for (int i = 0; i < Model.coursesVM.Count; i++)
{
<tr>
<td>
#Html.CheckBoxFor(c => c.coursesVM[i].Ischecked)
#Html.HiddenFor(c => c.coursesVM[i].course.CourseID)
</td>
<td>#Html.DisplayFor(c => c.coursesVM[i].course.CourseName)</td>
</tr>
}
</table>
<input type="submit" value="Submit" />
}
I am trying to find the best solution so that on any given page I always have a login model, a register model and another model (or more). The login and register models are found in the navbar and the footer respectively on each page.
Specifically I have a situation whereby I have a course page which populates from a table depending on which course has been looked up via the url inputted. So the page loads the course page model. On the same page in the header and footer I need to have the login and register forms which both require their own models.
The course page is populated using a foreach loop:
COURSE PAGE VIEW (SHORTENED):
#model IEnumerable<oltinternational_mvc.Models.Course_page>
#{
Layout = "~/Views/Shared/_courselayout.cshtml";
foreach (var cpage in Model) { ViewBag.Title = #cpage.page_title; }
}
#foreach (var cpage in Model)
{
if (cpage.template_type == 2)
{
<div id="main_container">
<article class="content">
<h1>
#cpage.Title
</h1>
<section>
#Html.Raw(cpage.main_image)
<h3>
#cpage.Country
</h3>
<p>#cpage.intro_1</p>
#if (!string.IsNullOrEmpty(cpage.intro_2))
{
<p>#cpage.intro_2</p>
}
#if (!string.IsNullOrEmpty(cpage.intro_3))
{
<p>#cpage.intro_3</p>
}
View sample pages
#if (!string.IsNullOrEmpty(cpage.website_button))
{
#Html.Raw(cpage.website_button)
}
else {
Licensing options
}
#Html.Raw(cpage.popup_script)
<div class="clearfloat"></div>
</section>
</article>
</div>
The controller is as follows:
public ActionResult Course_page(string id)
{
string abbrev = id;
var cpage = from c in db.Course_page
select c;
if (!String.IsNullOrEmpty(abbrev))
{
cpage = cpage.Where(x => x.abbrev.Contains(abbrev));
}
return View(cpage);
}
and the model:
[Table("course_page")]
public class Course_page
{
[Key]
public int CourseID { get; set; }
public string Meta { get; set; }
public string Title { get; set; }
public string Country { get; set; }
public string main_image { get; set; }
public string list_1 { get; set; }
public string list_2 { get; set; }
public string list_3 { get; set; }
public string list_4 { get; set; }
public string list_5 { get; set; }
public string list_6 { get; set; }
public string list_7 { get; set; }
public string list_8 { get; set; }
public string list_9 { get; set; }
public string list_10 { get; set; }
public string testim_1 { get; set; }
public string testim_2 { get; set; }
public string testim_3 { get; set; }
public string course_site { get; set; }
public string popup_script { get; set; }
public string abbrev { get; set; }
public string page_title { get; set; }
public int template_type { get; set; }
public string intro_1 { get; set; }
public string intro_2 { get; set; }
public string intro_3 { get; set; }
public string website_button { get; set; }
}
In the navbar I have the following list item which references my ajax logging in form:
<li class="login">
<span>Login</span>
#using (Ajax.BeginForm("login", "Account", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "login_box"
}, new { id = "login_box" }))
{
#Html.Partial("_login")
}
</li>
Which loads this form:
#model myproject_mvc.Models.LoginViewModel
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div id="login_box">
<div class="sign_up_box"> Sign up in seconds </div>
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
<div class="login_box_lower">
<p class="login_box_or">or</p>
<p class="login_sign_in">Sign in</p>
<div style="position:relative;">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { placeholder = "Email", maxlength = "18", #class = "login_username clearable" } })
<span class="login_username_icon"></span>
</div>
<div style="position:relative;">
#Html.EditorFor(model => model.Password, new { htmlAttributes = new { placeholder = "Password", maxlength = "18", #class = "login_pw clearable" } })
<span class="login_pw_icon"></span>
</div>
Login
<div class="clearfloat"></div>
Forgot password?
</div>
</div>
With the following model:
public class LoginViewModel
{
[Required]
[Display(Name = "Email")]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
The same situation is such for the Register form in the footer, which uses the RegisterViewModel. Bearing in mind the actual form above for logging in isn't completed yet, it just directs to a /account url for now.
I've tried a few solutions I've found online but can't seem to make any of them work, I think in part because I am using foreach to populate the view from the course page model. I don't see how I can use a viewmodel because I am using a foreach loop on the page.
What I would like to know is what is the best way to deal with this situation?
You should create and use viewmodel(s) instead of directly referencing your objects. Perhaps something like this.
Create a new class, MyViewModel.cs (or whatever name you prefer)
public class MyViewModel
{
public IEnumerable<oltinternational_mvc.Models.Course_page> CoursePages { get; set; }
public myproject_mvc.Models.LoginViewModel { get; set; }
}
Now in your view, instead of referencing the models directly, you would reference the view model. Something like #model myproject_mvc.ViewModels.MyViewModel
In your foreach loop you would so something like this #foreach (var cpage in Model.CoursePages)
I have a Menusettings pages which displays all the menuname from the database(Menutable).I want to save all the details into MenuRole table.For that I think I have to iterate over each menuitem and store the details in the MenuRole table(Is it the correct method?).But the problem is I am getting MenuList as null.So I couldnot iterate over the menulist .Also I am not sure how can i bind the checkbox value to the MenuRole table.
The view is
Model is
public class MenuRoleVM
{
public int? RoleId { get; set; }
public SelectList RoleList { get; set; }
public MenuRole MenuRole { get; set; }
public IEnumerable<Menu> MenuList { get; set; }
}
public partial class MenuRole
{
public int Id { get; set; }
public Nullable<int> MenuID { get; set; }
public Nullable<int> RoleID { get; set; }
public Nullable<System.DateTime> TransactionTime { get; set; }
public bool CanAdd { get; set; }
public bool CanEdit { get; set; }
public bool CanDelete { get; set; }
public bool CanView { get; set; }
public virtual Menu Menu { get; set; }
public virtual Role Role { get; set; }
}
public partial class Menu
{
public Menu()
{
this.MenuRoles = new HashSet<MenuRole>();
}
public int Id { get; set; }
public string MenuName { get; set; }
public string NavigateUrl { get; set; }
public Nullable<int> ParentID { get; set; }
public virtual ICollection<MenuRole> MenuRoles { get; set; }
}
Controller for binding the View
public ActionResult Add()
{
var _menuRoleVM = new MenuRoleVM
{
RoleList = new SelectList(_db.Roles.ToList(), "Id", "RoleName"),
MenuList = _db.Menus.Where(m => m.NavigateUrl != "#"),
MenuRole = new MenuRole()
};
return View(_menuRoleVM);
}
HTML Markup of View
#model SMS.Models.ViewModel.MenuRoleVM
#foreach (var item in Model.MenuList.Select((x, i) => new { Data = x, Index = i }))
{
<tr>
<td>
<input type="checkbox" class="minimal checkAll" />
</td>
<td>#item.Data.MenuName</td>
<td>
#Html.CheckBoxFor(m => m.MenuRole.CanAdd, new { #class = "minimal single" })
</td>
<td>
#Html.CheckBoxFor(m => m.MenuRole.CanEdit, new { #class = "minimal single" })
</td>
<td>
#Html.CheckBoxFor(m => m.MenuRole.CanDelete, new { #class = "minimal single" })
</td>
<td>
#Html.CheckBoxFor(m => m.MenuRole.CanView, new { #class = "minimal single" })
</td>
</tr>
}
Any help is highly appreciated?
You need view models that represent what you want to display/edit
public class MenuVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool CanAdd { get; set; }
public bool CanEdit { get; set; }
public bool CanDelete { get; set; }
public bool CanView { get; set; }
}
public class MenuRoleVM
{
public int? RoleId { get; set; }
public SelectList RoleList { get; set; }
public List<MenuVM> MenuList { get; set; }
}
and in the view
#model MenuRoleVM
#using (Html.BeginForm())
{
#Html.DropDownListFor(m => m.RoleId, Model.RoleList)
for(int i = 0; i < Model.MenuList.Count; i++)
{
#Html.HiddenFor(m => m.MenuList[i].ID)
#Html.DisplayFor(m => m.MenuList[i].Name)
#Html.CheckBoxFor(m => m.MenuList[i].CanAdd)
#Html.CheckBoxFor(m => m.MenuList[i].CanEdit)
....
}
<input type="submit" ... />
}
I am new to MVC so here is my issue. I have a parent view and a partial view which is rendered inside it.
As a model I pass an IEnumerable to the parent view. I iterate thru the list and for each item i render the partial view having the list item as model. On the partial view I have a form which on a submit triggers a child action which accepts as parameter the type of the list. My issue is that the param comes always with it's values null.
These are my domain entities.
public class Contact
{
[Key]
public int IdContacts { get; set; }
public int UserId { get; set; }
public int CreatedByUserId { get; set; }
public int UpdatedByUserId { get; set; }
public int AddressId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public long HomePhone { get; set; }
public long? WorkPhone { get; set; }
public bool IsRelated { get; set; }
public bool IsEmergency { get; set; }
public bool IsDeceased { get; set; }
public string Relationship { get; set; }
public DateTime EntryDate { get; set; }
public DateTime? ChangeDate { get; set; }
}
public class Address
{
[Key]
public int IdAddresses { get; set; }
public int CountryId { get; set; }
public int StateId { get; set; }
public int CreatedByUserId { get; set; }
public int UpdatedByUserId { get; set; }
public string Street { get; set; }
public string City { get; set; }
public long PostalCode { get; set; }
public string OfficeOrApt { get; set; }
public int AreaGroup { get; set; }
public int? SuperUserId { get; set; }
public DateTime EntryDate { get; set; }
public DateTime? ChangeDate { get; set; }
}
This is my view model
public class ContactModel
{
public Contact Contact { get; set; }
public Address Address { get; set; }
public bool IsEditMode { get; set; }
}
This is my parent view
#model IEnumerable<Cricket.WebUI.Models.ContactModel>
#{
ViewBag.Title = "Contacts";
}
<h2 align="center">
Contacts</h2>
<div class="iggr_container">
<div class="iggr_clear">
</div>
#foreach (var contact in Model)
{
ViewDataDictionary dictionary = new ViewDataDictionary();
string guid = (Guid.NewGuid()).ToString();
dictionary.Add("prefix", guid);
#Html.Hidden("Contact.Index", guid)
#Html.Hidden("Address.Index", guid)
#Html.Partial("ContactSummary", contact, dictionary)
<hr style="width: 385px;" align="left" />
}
</div>
This is my partial view
#model Models.ContactModel
<div class="iggr_clear">
</div>
#if (!Model.IsEditMode)
{
var prefixContact = "Contact[" + ViewData["prefix"] + "].";
var prefixAddress = "Address[" + ViewData["prefix"] + "].";
using (Html.BeginForm("Edit", "Contacts", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
TempData["ContactModelObject"] = Model;
<div>
<b>
#Html.Hidden(prefixContact + "FirstName", Model.Contact.FirstName);
#Html.Hidden(prefixContact + "LastName", new { name = "Contact" + ViewData["prefixContact"] + ".LastName" })
#Html.LabelFor(m => m.Contact.FirstName, Model.Contact.FirstName)
#Html.LabelFor(m => m.Contact.LastName, Model.Contact.LastName)
</b>
<div>
<span>Home Phone:</span>
#Html.Hidden(prefixContact + "HomePhone", Model.Contact.HomePhone)
#Html.LabelFor(m => m.Contact.HomePhone, Model.Contact.HomePhone.ToString())</div>
<div>
<span>Work Phone:</span>
#Html.Hidden(prefixContact + "WorkPhone", Model.Contact.WorkPhone)
<span>
#if (Model.Contact.WorkPhone == null)
{
#:N/A
}
else
{
#Html.LabelFor(m => m.Contact.WorkPhone, Model.Contact.WorkPhone.ToString())
}
</span>
</div>
<div>
#Html.Hidden(prefixAddress + "Street", Model.Address.Street)
#Html.LabelFor(m => m.Address.Street, Model.Address.Street)
</div>
<div>
#Html.Hidden(prefixAddress + "City", Model.Address.City)
#Html.Hidden(prefixAddress + "PostalCode", Model.Address.PostalCode)
#Html.LabelFor(m => m.Address.City, Model.Address.City) #Html.LabelFor(m => m.Address.PostalCode, Model.Address.PostalCode.ToString())
</div>
#Html.Hidden(prefixContact + "IsRelated", Model.Contact.IsRelated)
#if (Model.Contact.IsRelated)
{
<b>Family</b>
if (Model.Contact.IsEmergency || Model.Contact.IsDeceased)
{
<b>/</b>
}
}
#Html.Hidden(prefixContact + "IsEmergency", Model.Contact.IsEmergency)
#if (Model.Contact.IsEmergency && !Model.Contact.IsDeceased)
{
<b>Emergency</b>
}
#Html.Hidden(prefixContact + "IsDeceased", Model.Contact.IsDeceased)
#if (Model.Contact.IsDeceased)
{
<b>Deceased</b>
}
<input type="submit" name="button" value="Edit" class="iggr_button_edit" style="margin-left: 150px;" />
</div>
}
}
And finally my controller class
public class ContactsController : Controller
{
[HttpGet]
public ActionResult Index()
{
ContactsRepository repository = new ContactsRepository();
CDE.User user = (from u in repository.Users where u.IdUsers == 1 select u).FirstOrDefault();
var contacts = (from u in repository.Users
join c in repository.Contacts on new { UserId = u.IdUsers } equals new { UserId = c.UserId }
join a in repository.Addresses on new { AddressId = c.AddressId } equals new { AddressId = a.IdAddresses }
select new ContactModel()
{
Contact = c,
Address = a
}).AsEnumerable();
return View("Contacts", contacts);
}
[HttpPost]
[ActionName("Edit")]
[#ActionFilter(ActionInvokerType = "button", ActionInvokerValue = "Edit")]
public ViewResult Edit(ContactModel contact)
{
//Here contact.Contact comes as null same for contact.Address
return View("Contacts", null);//Ignore this line
}
}
I have a feeling that your prefix structure is interfering with the binding that normally happens in MVC. You could use a custom model binding implementation, or find a way to do without your prefixes.
How do I handle a many to many object mapping in the view and controller in the context of users and roles?
I used entity framework to map to pure POCOs like this:
public class Role
{
public int RoleId { get; set; }
public string RoleName { get; set; }
public List<User> Users { get; set; }
}
public class User
{
public int UserId { get; set; }
public List<Role> Roles { get; set; }
}
In my view, I'd like to add a User to a role using checkboxes. I list all the roles then check one to add the user to that role. How do I handle this?
I would start by designing a view model for this scenario:
public class UserRolesViewModel
{
public int UserId { get; set; }
public IEnumerable<RoleViewModel> Roles { get; set; }
}
public class RoleViewModel
{
public int RoleId { get; set; }
public bool InRole { get; set; }
public string RoleName { get; set; }
}
Then a roles controller:
public class RolesController : Controller
{
public ActionResult Edit(int userId)
{
// TODO: Use a repository to fetch the roles associated to the given
// user id and then AutoMapper to map your model POCOs
// to a UserRolesViewModel
var model = new UserRolesViewModel
{
UserId = userId,
Roles = new[]
{
new RoleViewModel { RoleId = 1, InRole = false, RoleName = "Role 1" },
new RoleViewModel { RoleId = 2, InRole = true, RoleName = "Role 2" },
new RoleViewModel { RoleId = 3, InRole = true, RoleName = "Role 3" }
}
};
return View(model);
}
[HttpPut]
public ActionResult Update(UserRolesViewModel model)
{
// Here you will get the view model back containing the
// user id and the selected roles
// TODO: use AutoMapper to map back to a POCO and
// invoke the repository to update the database
return RedirectToAction("Edit");
}
}
then the Edit view (~/Views/Roles/Edit.cshtml):
#model YourAppName.Models.UserRolesViewModel
#{
ViewBag.Title = "Edit user roles";
}
<h2>Roles for user #Model.UserId</h2>
#using (Html.BeginForm("Update", "Roles"))
{
#Html.HttpMethodOverride(HttpVerbs.Put)
#Html.HiddenFor(x => x.UserId)
#Html.EditorFor(x => x.Roles)
<input type="submit" value="update roles" />
}
and finally the corresponding editor template (~/Views/Roles/EditorTemplates/RoleViewModel.cshtml):
#model YourAppName.Models.RoleViewModel
<div>
#Model.RoleName
#Html.HiddenFor(x => x.RoleId)
#Html.CheckBoxFor(x => x.InRole)
</div>