Retrieve an array in viewmodel - asp.net-mvc

I'm trying to create a page for editing my attachments.
The Attachment Model:
public class Attachment
{
...
private IList<JSONI18NText> titles = new List<JSONI18NText>();
private IList<JSONI18NText> descriptions= new List<JSONI18NText>();
...
public virtual IList<JSONI18NText> Titles
{
get { return titles; }
set { this.titles = value; }
}
public virtual IList<JSONI18NText> Descriptions
{
get { return descriptions; }
set { this.descriptions= value; }
}
The JSONI18NText Model:
public class JSONI18NText
{
public int LanguageId { get; set; }
public string Text { get; set; }
}
The Attachment ViewModel:
public class AttachmentModel
{
public AttachmentModel() { }
public AttachmentModel(Attachment at) {
...
this.Titles = new List<JSONI18NTextModel>();
this.Descriptions = new List<JSONI18NTextModel>();
foreach (JSONI18NText title in at.Titles)
{
this.Titles.Add(new JSONI18NTextModel(title, "Title"));
}
foreach (JSONI18NText description in at.Descriptions)
{
this.Descriptions.Add(new JSONI18NTextModel(description, "Description"));
}
}
[Display(Name = "Title", Description = "Title of the file")]
public IList<JSONI18NTextModel> Titles { get; set; }
[Display(Name = "Description", Description = "Description of the attachment file")]
[DataType(DataType.MultilineText)]
public IList<JSONI18NTextModel> Descriptions { get; set; }
The JSONI18NText ViewModel:
public class JSONI18NTextModel
{
public JSONI18NTextModel() { }
public JSONI18NTextModel(JSONI18NText jsonI18nText)
{
this.LanguageId = jsonI18nText.LanguageId;
this.Text = jsonI18nText.Text;
}
[HiddenInput(DisplayValue = false)]
public int LanguageId { get; set; }
public string Text { get; set; }
}
Now, what I'm trying to achieve is an edit form with a tabbed list for the languages: for example two tabs, one for English and one for Italian, if you click on each tab you read the input value of title and description for that particular language.
Everything works like a charm: I used a view script with two partial views, one for the lists and another for the JSONI18NTextModel:
Edit.cshtml:
...
#Html.EditorFor(model => model.Titles, "EditLabels")
#Html.EditorFor(model => model.Descriptions, "EditLabels")
...
EditLabels.cshtml:
#model List<CR2.Web.Areas.Admin.Models.JSONI18NTextModel>
#using CR2.Web.Infrastructure
#using CR2.Web.Areas.Admin.Models
#if(Model.Count() == 1)
{
#Html.EditorFor(model => model[0], "EditLabel");
}
else
{
for(int i = 0; i < Model.Count(); ++i)
{
<div>
<ul>
#Html.EditorFor(model => model[i], "EditLabel")
</ul>
</div>
}
}
EditLabel.cshtml:
#model CR2.Web.Areas.Admin.Models.JSONI18NTextModel
#using CR2.Web.Infrastructure
<li>
#Html.HiddenFor(model => model.LanguageId)
<div>
#Html.LabelWithTooltip(model => model.Text)
</div>
<div>
#Html.EditorFor(model => model.Text)
#Html.ValidationMessageFor(model => model.Text)
</div>
</li>
When I render it, it builds fields with names like "Titles.[0].Text", which is perfect I think...
The problem comes when I submit the form: "Titles" and "Descriptions" aren't populated in the AttachmentModel...(everything else is populated)
Any ideas? What am I doing wrong?
Thanks a lot!!!

Iterating over the list and populating each value should be something like:
#foreach (JSONI18NTextModel item in model)
{
Html.EditorFor(i => item.Titles, "EditLabels");
Html.EditorFor(i => item.Descriptions, "EditLabels");
}
Then I assume you are posting only one model to the controller action:
[HttpPost]
public ActionResult Edit(JSONI18NTextModel model)
{
// The only Model you are posting should be accessible here.
}
If you have a list of models on your page, then you may want to create a Details view where you access only one model at a time and you post only that model to the controller.

Related

Binding complex object .net core

I have a model view that has a list of objects in it, so it has a list of other class in it:
public class CpdTestFeedbackFormModel
{
public Guid WebsiteKey { get; set; }
//
//some other simple fileds
public List<SelectListItem> StarItems;
public List<CpdFeedbackQuestionAnswerModel> Questions;
public CpdTestFeedbackFormModel()
{
//some initialization
}
}
and the other class definition:
public class CpdFeedbackQuestionAnswerModel
{
public Guid Questionkey { get; set; }
public string Question { get; set; }
public string QuestionType { get; set; }
public int RatingAnswer { get; set; }
public string TextAnswer { get; set; }
}
I render my data like this in the view:
using (Html.BeginForm("SubmitFeedbackAnswers", "Form", FormMethod.Post, new
{
enctype = "multipart/form-data"
}))
{
#Html.HiddenFor(x => Model.WebsiteKey)
#Html.HiddenFor(x => Model.Testkey)
<div>
<div>
<h1>Feedback Questions</h1>
#for (int i = 0; i < #Model.Questions.Count(); i++)
{
<p>Q.<span>#Model.Questions[i].Question</span></p>
<p>
#if (#Model.Questions[i].QuestionType == "Star Rating")
{
#foreach (var starItem in Model.StarItems)
{
#Html.RadioButtonFor(model => Model.Questions[i].RatingAnswer, starItem.Value)
#Html.Label(starItem.Text)
}
}
else
{
#Html.HiddenFor(m => Model.Questions[i].Questionkey)
#Html.HiddenFor(m => Model.Questions[i].Question)
#Html.HiddenFor(m => Model.Questions[i].QuestionType)
#Html.HiddenFor(m => Model.Questions[i].RatingAnswer)
#Html.TextBoxFor(m => Model.Questions[i].TextAnswer)
}
</p>
}
</div>
</div>
<div>
<button type="submit" data-type="submit" class="bg-btn-primary">
Save Answer
</button>
</div>
</div>
}
when I inspect the view binding seems perfect:
but in my controller, the questions field is empty all other data are coming ok except that list.
[HttpPost]
public async Task<StatusCodeResult> SubmitFeedbackAnswers(CpdTestFeedbackFormModel model)
did I miss something?
After having another look I noticed a mistake in my CpdTestFeedbackFormModel class, my Questions don't have a get; set; method!! and that's it, it's working fine now.
public List<CpdFeedbackQuestionAnswerModel> Questions { get; set; }
Only missed part.

Problem in showing ViewModel in Create form

I am learning how to use ViewModel to show the fields from 2 different models. I have one model containing the MsgTypeId, MsgType and MsgStatus and the another model OptStatus containing the StatusId, StatusName and StatusValue. The MsgStatus will be shown in form of drop down list and show all the values in OptStatus. Both models have a separate database table to store their values.
namespace theManager.Areas.Settings.Models
{
public class OptStatus
{
[Required]
[Key]
public int StatusId { get; set; }
[Required]
public string StatusName { get; set; }
[Required]
public char StatusValue { get; set; }
}
}
namespace theManager.Areas.Settings.Models
{
public class OptMsgType
{
[Required]
[Key]
public int MsgTypeId { get; set; }
[Required]
public string MsgType { get; set; }
[Required]
public string MsgStatus { get; set; }
}
}
I have created a ViewModel to show these fields in the Create form of OptMsgType. However, when I run the code, I got an error
"System.NullReferenceException: 'Object reference not set to an instance of an object.'"
I would like to ask if there is something wrong with my ViewModel. Thanks!
namespace theManager.Areas.Settings.ViewModels
{
public class OptMsgTypeCreateViewModel
{
public OptMsgType OptMsgType { get; set; }
public IEnumerable<SelectListItem> OptStatuses { get; set; }
}
}
OptMsgTypeController.cs
public IActionResult Create(int id)
{
var OptMsgTypeViewModel = new OptMsgTypeCreateViewModel();
OptMsgTypeViewModel.OptStatuses = _context.OptStatus.ToList().Select(x => new SelectListItem
{
Text = x.StatusName,
Value = x.StatusValue.ToString()
});
OptMsgTypeViewModel.OptMsgType = _context.OptMsgType.Where(a => a.MsgTypeId == id).FirstOrDefault();
//var v = _context.OptMsgType.Where(a => a.MsgTypeId == id).FirstOrDefault();
return View(OptMsgTypeViewModel);
}
I have problems in displaying the Create form which will show the fields declared in the ViewModel.
#model theManager.Areas.Settings.ViewModels.OptMsgTypeCreateViewModel
#{
ViewData["Title"] = "Create";
Layout = null;
}
<h2>Message Type Settings</h2>
#using (Html.BeginForm("Create","OptMsgType", FormMethod.Post, new { id= "popupForm" }))
{
if (Model != null && Model.OptMsgType.MsgTypeId > 0)
{
#Html.HiddenFor(a=>a.OptMsgType.MsgTypeId)
}
<div class="form-group">
<label>Message Type ID</label>
#Html.TextBoxFor(a=>a.OptMsgType.MsgTypeId,new { #class = "form-control" })
#Html.ValidationMessageFor(a=>a.OptMsgType.MsgTypeId)
</div>
<div class="form-group">
<label>Leave Type</label>
#Html.TextBoxFor(a => a.OptMsgType.MsgType, new { #class = "form-control" })
#Html.ValidationMessageFor(a => a.OptMsgType.MsgType)
</div>
<div class="form-group">
<label>Status</label>
#Html.DropDownListFor(model => model.OptStatuses, new SelectList(Model.OptStatuses, "Value", "Text"), htmlAttributes: new { #class = "form-control", id = "OptStatus" })
#Html.ValidationMessageFor(a => a.OptStatuses)
</div>
<div>
<input type="submit" value="Create" />
</div>
}
The System.NullReferenceException indicates that you are using a field without initializing it. It coulbe a problem with your view model or it could be a problem anywere else. For example from the code smaple is not possible to see where you initialize the context you are using to get the data, and that could be the cause of the exception you are getting.
Either way I would advise you to pay attention to yout IDE, it usualy indicates in which line adnd class the exception is being thown. If you navigate to that class at that line you will easily identify which field can be de cause of the exception.
Regarding your view model, its considered a good practice to always initialize the lists on your model on the constructor of your class. This way you can guarantee that they are already initialized when you try to use them.
So my sugestion would be to initialize your list on the constructor of your viewmodel
public OptMsgTypeCreateViewModel()
{
OptStatuses = new List<OptStatus>();
}
#George, thanks for the reply. Please try this then: instantiate your class in the viewmodel.
public class OptMsgTypeCreateViewModel
{
public OptMsgTypeCreateViewModel()
{
OptMsgType = new OptMsgType();
}
public OptMsgType OptMsgType { get; set; }
public IEnumerable<SelectListItem> OptStatuses { get; set; }
}
hi in action controller you should change this code:
OptMsgTypeViewModel.OptStatuses = _context.OptStatus.ToList().Select(x => new SelectListItem
{
Text = x.StatusName,
Value = x.StatusValue.ToString()
});
I think _context.OptStatus.ToList() in null so you get this exception. change code to this:
OptMsgTypeViewModel.OptStatuses =new list<SelectListItem>();
var temp= _context.OptStatus.ToList();
if(temp!=null&&temp.count()>0)
{
OptMsgTypeViewModel.OptStatuses = temp.Select(x => new SelectListItem
{
Text = x.StatusName,
Value = x.StatusValue.ToString()
}).tolist();
}
EDIT:
I think this object "Model.OptMsgType" is null
change code in view like this:
if (Model != null && Model.OptMsgType!=null && Model.OptMsgType.MsgTypeId > 0)
{
#Html.HiddenFor(a=>a.OptMsgType.MsgTypeId)
}

Dropdown list population from ViewModel

First of all, I know this question has been asked many, many times. I've read countless articles and Stack Overflow answers. I've tried to figure this problem out for four days and I think I need help if someone doesn't mind.
I have two databases. The employee database has a field called "DisplayName" -- the second database has a relationship with the first and they work together great. I'm able to call the two databases perfectly in another application.
You can see the in the picture Index Page
that I have a list of people. I want a dropdown below it that lists all display names in the database so employees can add themselves to the list. You'll see a dropdown in the image but it's not populated.
Seems simple. But geez. Part of a problem I'm having is my home controller already has a function to populate the list in the picture so I can't do another on that page. I've tried a lot of suggestions on a lot of sites. I get IEnumerable errors or display reference errors....
Here's my controller (again - it has nothing in it that helps the dropdown):
namespace SeatingChart.Controllers
{
public class HomeController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Employee
public ActionResult Index()
{
var lists = db.BreakModels
.Include("Employee")
.Include("TimeEntered")
.Include("TimeCleared")
.Include("DisplayName")
.Select(a => new HomeIndexViewModels
{
Employee = a.Employee,
DisplayName = a.EmployeeModels.DisplayName,
TimeEntered = a.TimeEntered,
TimeCleared = a.TimeCleared.Value,
Id = a.EmployeeModels.Id,
});
return View(lists);
}
View:
#model IEnumerable<SeatingChart.Models.HomeIndexViewModels>
#{
Layout = null;
}
#Html.Partial("_Header")
<div class="container_lists">
<div class="container_break col-md-8">
<h5 style="text-align:center">Break List</h5>
<table class="table-bordered col-lg-12">
#if (Model != null)
{
foreach (var item in Model)
{
if (item.TimeCleared == null)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.DisplayName)
</td>
<td>
 BV
</td>
<td>
 #item.TimeEntered.ToString("HH:mm")
</td>
</tr>
}
}
}
</table>
#using (Html.BeginForm())
{
<div class="row site-spaced">
<div class="col-3">
#Html.DropDownList("DisplayName", new SelectList(new List<string>() { "---Dispatcher---" }), new { #class = "required " })
</div>
</div>
<div class="col-3">
<input type="submit" value="Submit" class="site-control" />
</div>
}
</div>
</div>
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace SeatingChart.Models
{
public class HomeIndexViewModels
{
//Break Model
public int BreakId { get; set; }
public int Employee { get; set; }
public DateTime TimeEntered { get; set; }
public DateTime? TimeCleared { get; set; }
//Employee Model
public int Id { get; set; }
public string DisplayName { get; set; }
public string DisplayNames { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool NotActive { get; set; }
public int Force { get; set; }
public string EmployeeList { get; set; }
}
}
I hope this is clear enough. I've tried so many different ways with so much code - the errors are different with everything I've tried.
Thanks in advance for your patience and help!
You can add to your viewmodel
public List<SelectListItem> Employees { get; set; }
Then you can populate this list with controller then in view just call it with:
#Html.DropDownListFor(m => m.Id, Model.Employees, new { #class = "form-control", required = "required" })
Update - how to populate list. Should work (but not tested code).
public List<SelectListItem> GetEmployeeForDropdown(List<HomeIndexViewModels> list)
{
List<SelectListItem> empList = new List<SelectListItem>();
try
{
if (list != null && list.Count > 0)
{
foreach (var item in list)
{
empList.Add(new SelectListItem { Text = item.DisplayName, Value = item.Id.ToString() });
}
}
else
{
empList.Add(new SelectListItem { Text = "No items", Value = string.Empty });
}
}
catch (Exception ex)
{
//handle exceptions here
}
return empList;
}
Edit: Remember to use your model in view!

ASP.NET MVC 5 Html.CheckboxFor only return default value on post

I have read the tutorials and prepared a list of checkboxes for the page. When the form is submitted, the Selected property only get the value false.
Is there something I missed?
The Model
public class SelectStudentModel
{
public int StudentID { get; set; }
public string CardID { get; set; }
public string Name { get; set; }
public bool Selected { get; set;}
}
The ViewModel
public class SelectStudentViewModel
{
public List<SelectStudentModel> VMList;
public SelectStudentViewModel()
{
VMList = SelectStudentModel.GETStudent();
}
}
The View
#using Student.Models
#model SelectStudentViewModel
#using (Html.BeginForm("AddStudent", "SectionStudent", FormMethod.Post, new { #role = "form" }))
{
#{ for (int i = 0; i < Model.VMList.Count(); i++)
{
<tr>
<td>#Html.CheckBoxFor(m => m.VMList[i].Selected)</td>
<td>#Html.DisplayFor(model => model.VMList[i].Name)</td>
</tr>
}
}
<input type="submit" value="submit" />
}#* end form *#
The Controller for posted data
[HttpPost]
public ActionResult AddStudent(SelectStudentViewModel model)
{
foreach (SelectStudentModel m in model.VMList)
{
Console.Write(m.Selected.ToString());
}
return PartialView("StudentSelectForm", model);
}
VMList is a field in your SelectStudentViewModel model. You need to change it to a property (with a getter/setter) so the DefaultModelBinder can set the values
public class SelectStudentViewModel
{
public List<SelectStudentModel> VMList { get; set; } // change
public SelectStudentViewModel()
{
VMList = SelectStudentModel.GETStudent();
}
}
Side note: Suggest you change #Html.DisplayFor(model => model.VMList[i].Name) to #Html.LabelFor(m => m.VMList[i].Selected, Model.MList[i].Name) so that you get a label associated with the checkbox

Create View with Model and List<Model>

I have a project model and a technology model. There can be multiple technologies in one project. There will be a limited amount of technology objects, around 5-10, that will be used across an unlimited amount of projects. I thought of keeping the technology items in an enum or just as constant variables, but I want the ability to add or edit down the road, so I figured I would put them in a table.
I tend to get hung up when dealing with lists. I want to be able to create a single project, and in the same view check a checkbox for the technology that was used on the project (ex. HTML5 or CSS3). I am not able to get a list of technologies to show up in the view for me to mark as checked for the particular project.
Project Class:
public class Project
{
public int Id { get; set; }
public string Website { get; set; }
public List<Technology> Technologies { get; set; }
}
Technology Class:
public class Technology
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
ViewModel:
public class ProjectTechnologyViewModel
{
public IEnumerable<Technology> Technologies { get; set; }
public Project Projects { get; set; }
public ProjectTechnologyViewModel()
{
Projects = new Project();
}
}
DbContext:
public class NovaDB : DbContext
{
public NovaDB(): base("DefaultConnection")
{
}
public DbSet<Technology> Technologies { get; set; }
public DbSet<Project> Projects{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Controller:
public ActionResult CreateProject()
{
return View();
}
[HttpPost]
public ActionResult CreateProject(ProjectTechnologyViewModel viewModel)
{
var proj = new Project();
if (ModelState.IsValid)
{
proj.LaunchDate = viewModel.Projects.LaunchDate;
proj.ProjectType = viewModel.Projects.ProjectType;
proj.ServiceId = viewModel.Projects.ServiceId;
proj.ShowInOurWork = viewModel.Projects.ShowInOurWork;
proj.Website = proj.Website;
proj.Technologies = new List<Technology>();
foreach (var t in viewModel.Technologies)
{
proj.Technologies.Add(new Technology()
{
Name = t.Name,
FAClassName = t.FAClassName,
IsActive = t.IsActive,
});
}
_db.Projects.AddOrUpdate(proj);
_db.SaveChanges();
}
return View(proj);
}
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Project</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Projects.Website, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.Projects.Website, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.Projects.Website, "", new {#class = "text-danger"})
</div>
</div>
#for (int i = 0; i < Model.Technologies.Count(); i++)
{
#Html.CheckBoxFor(x=>x.Technologies[i].)
}
<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>
}
Image of View:
The checkbox is for the IsActive property of the Technology, right? So, you can do this:
#Html.CheckBoxFor(model => model.Technologies.ToList()[i].IsActive) #Model.Technologies.ToList()[i].Name
You also need to instantiate your ViewModel and send it to your view in your GET action, like this:
public ActionResult CreateProject()
{
var model = new ProjectTechnologyViewModel();
model.Project = new Project();
model.Technologies = new List<Technology>();
return View(model);
}
Also, don't instantiate the properties in your ViewModel. Do that in your controller (see above):
public class ProjectTechnologyViewModel
{
public IEnumerable<Technology> Technologies { get; set; }
public Project Project { get; set; }
}
Why are you referring to a IEnumerable as an array?
this - someIEnumerable[0] will not be compiled.
Why don't you use foreach?
foreach(var i in Model.Technologies){
var a = i.Website;
}
Firstly, you will need a table to store the Technologies associated with a Project, (say ProjectTechnlogies) that will include FK fields to the Project ID field and the Technology ID field.
Then you will need view models to represent what your wanting to edit in the view
public class TechnologyVM
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; } // for binding to a checkbox
}
public class ProjectVM
{
public string Website { get; set; }
public IEnumerable<TechnologyVM> Technologies { get; set; }
}
and your GET method would be
public ActionResult Create()
{
ProjectVM model = new ProjectVM
{
Technologies = _db.Technologies.Where(t => t.IsActive).Select(t => new TechnologyVM
{
Id = t.Id,
Name = t.Name
})
};
return View(model);
}
Note I am assuming here that your IsActive property means that if the value is false its now an obsolete technology (it may have been assigned to previous Projects) and that you don't want to allow to to be selected in the view when creating a new Project.
Then create an EditorTemplate (partial) for TechnologyVM in /Views/Shared/EditorTemplates/TechnologyVM.cshtml (note the name of the file must match the name of the class)
#model TechnologyVM
<div>
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.Name) // if you want this value to be posted
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.IsSelected, Model.Name)
</div>
and the main view will be
#model ProjectVM
....
#using (Html.BeginForm())
{
....
#Html.TextBoxFor(m => m.Website)
....
#Html.EditorFor(m => m.Technologies)
<input type="submit" ... />
}
The EditorFor() method will correctly generate the html for each Technology
Finally you POST method will be
[HttpPost]
public ActionResult Create(ProjectVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
Project project = new Project
{
Website = model.Website,
// ... other properties of Project
}
_db.Projects.Add(project);
_db.SaveChanges(); // The Project's Id property has now been set
IEnumerable<int> selectedTechnologies = model.Where(t => t.IsSelected).Select(t => t.Id);
foreach(int ID in selectedTechnologies)
{
ProjectTechnology technology = new ProjectTechnology
{
ProjectId = project.Id,
Technology = ID
};
_db.ProjectTechnologies.Add(technology);
}
_db.SaveChanges(); // save the project technologies
// redirect
}
I had to change a few models and I added a table to map the two models. I decided to save the "link" between the Project & Technology models in a shared table called ProjectTechnologyMap. For the project I create, I insert a record with the project Id and the Technology Id. The project Id stays constant and there are multiple technology Ids, depending on how many are selected in the view. I also save my project details to the project table. I do not save anything to the technology table as it is static (I do not create technologies on my Create Project View).
Here is my solution that worked:
Models:
public class Project
{
public int Id { get; set; }
public string Website { get; set; }
}
public class Technology
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
public class ProjectTechnologyMap
{
public int Id { get; set; }
public int ProjectId { get; set; }
public int TechnologyId { get; set; }
}
ViewModel:
public class ProjectTechnologyViewModel
{
public List<Technology> Technologies { get; set; }
public Project Projects { get; set; }
public ProjectTechnologyMap ProjectTechnologyMapping { get; set; }
public ProjectTechnologyViewModel()
{
Projects = new Project();
ProjectTechnologyMapping = new ProjectTechnologyMap();
}
}
DB Context:
public class NovaDB : DbContext
{
public NovaDB(): base("DefaultConnection")
{
}
public DbSet<Technology> Technologies { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<ProjectTechnologyMap> ProjectTechnologyMappings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Controller:
public ActionResult Create()
{
var technologies = from t in _db.Technologies
orderby t.Name
where t.IsActive
select t;
var viewModel = new ProjectTechnologyViewModel();
viewModel.Technologies = technologies.ToList();
return View(viewModel);
}
[HttpPost]
public ActionResult Create(ProjectTechnologyViewModel viewModel)
{
if (ModelState.IsValid)
{
var proj = new Project
{
LaunchDate = viewModel.Projects.LaunchDate,
ProjectType = viewModel.Projects.ProjectType,
ServiceId = viewModel.Projects.ServiceId,
ShowInOurWork = viewModel.Projects.ShowInOurWork,
Website = viewModel.Projects.Website
};
_db.Projects.AddOrUpdate(proj);
_db.SaveChanges();
var map = new ProjectTechnologyMap();
foreach (var item in viewModel.Technologies)
{
if (item.UsedInProject)
{
map.TechnologyId = item.Id;
map.ProjectId = proj.Id;
_db.ProjectTechnologyMappings.Add(map);
_db.SaveChanges();
}
}
}
return RedirectToAction("Index", "Project");
}
Loop in my View to handle the list of technologies:
#for (var i = 0; i < Model.Technologies.Count; i++)
{
<div class="form-group">
#Html.LabelFor(x => x.Technologies[i].Name, Model.Technologies[i].Name, new {#class = "control-label col-md-2"})
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(x => x.Technologies[i].UsedInProject)
#Html.HiddenFor(x => x.Technologies[i].Id)
</div>
</div>
</div>
}

Resources