Error in my upload page after i changed my model [duplicate] - asp.net-mvc

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
I added the code to show many checkboxes from my table (HairTags) and in my form CreationUpload.cshtml i got the following error :
An exception of type 'System.NullReferenceException' occurred in
App_Web eba142hb.dll but was not handled in user code Additional
information: Object reference not set to an instance of an object.
Object reference not set to an instance of an object.
<div class="col-md-12">
#for (int i = 0; i < Model.CreationHairTags.Count; i++)
{
#Html.CheckBoxFor(m => Model.CreationHairTags[i].IsChecked)
#Model.CreationHairTags[i].Text
#Html.HiddenFor(m => Model.CreationHairTags[i].Value)
#Html.HiddenFor(m => Model.CreationHairTags[i].Text)<br />
}
</div>
this is my model Creation.cs (in bold the added code)
namespace HairCollection3.Models
{
public class Creation
{
public string UserId { get; set; }
[Key]
public int CreationId { get; set; }
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ViewRes.ValidationStrings))]
[Display(Name = "Sex", ResourceType = typeof(ViewRes.Names))]
public string CreationSex { get; set; }
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ViewRes.ValidationStrings))]
[Display(Name = "CreationTitle", ResourceType = typeof(ViewRes.NamesCreation))]
[StringLength(2000)]
[AllowHtml]
public string CreationTitle { get; set; }
public string CreationPhotoBis { get; set; }
public string Creationtag { get; set; }
public virtual ICollection<CreationLike> CreationLikes { get; set; }
}
public class CreationLike
{
public int CreationId { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
[Key]
public int CreationLikeId { get; set; }
public virtual Creation ParentCreation { get; set; }
}
public class HairTag
{
[Key]
public int HairTagId { get; set; }
[Required]
public string HairTagTitle { get; set; }
[Required]
public string HairTagType { get; set; }
[Required]
public int HairTagOrder { get; set; }
}
***//CHECKBOXES
public class HairTagModel
{
[Key]
public int Value { get; set; }
public string Text { get; set; }
public bool IsChecked { get; set; }
}
public class HairTagList
{
private ApplicationDbContext creationdb = new ApplicationDbContext();
public HairTagList()
{
var HairTagList = creationdb.HairTags.ToList();
List<HairTagModel> obj = new List<HairTagModel>();
foreach (var tags in HairTagList)
{
obj.Add(new HairTagModel
{
Text = tags.HairTagTitle,
Value = tags.HairTagId,
IsChecked = false
});
}
this.CreationHairTags = obj;
}
public List<HairTagModel> CreationHairTags { get; set; }
//public List<HairTagModel> ListHairTags { get; set; }
}
public class CreationHairTagsModel
{
public Creation Creation { get; set; }
public List<HairTagModel> CreationHairTags { get; set; }
}
}***
My controller CreationController.cs
// GET: /Creation/CreationUpload
[Authorize]
public ActionResult CreationUpload()
{
CreationHairTagsModel creation = new CreationHairTagsModel();
return View(creation);
//return View();
}
// POST: /Creation/CreationUpload
// Afin de déjouer les attaques par sur-validation, activez les propriétés spécifiques que vous voulez lier. Pour
// plus de détails, voir http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult CreationUpload([Bind(Include = "CreationId,CreationSex,CreationTitle,CreationPhotoBis,CreationHairTags")] CreationHairTagsModel creation, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
// update each field manually
foreach (var file in files)
{
if (file != null)
{
if (file.ContentLength > 0)
{
....CODE UPLOAD HIDDEN....
//Avoid Script
var CreationTitletocheck = Regex.Replace(creation.Creation.CreationTitle, #"<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>", string.Empty);
CreationTitletocheck = Regex.Replace(CreationTitletocheck, #"(?></?\w+)(?>(?:[^>'""]+|'[^']*'|""[^""]*"")*)>", string.Empty);
creation.Creation.CreationTitle = CreationTitletocheck;
//Tags
StringBuilder sb = new StringBuilder();
foreach (var item in creation.CreationHairTags)
{
if (item.IsChecked)
{
sb.Append(item.Text + ",");
}
}
creation.Creation.Creationtag = sb.ToString();
creation.Creation.UserId = User.Identity.GetUserId();
db.Creations.Add(creation.Creation);
db.SaveChanges();
}
}
}
}
//UserId
return RedirectToAction("CreationList", "Creation", new { UserId = User.Identity.GetUserId() });
}
return View(creation);
}
My page of upload CreationUpload.cshtml
#model HairCollection3.Models.CreationHairTagsModel
#using Microsoft.AspNet.Identity
#{
ViewBag.Title = ViewRes.NamesCreation.CreationUploadTitle;
}
<div class="col-sm-12 col-md-12 chpagetop">
<h1>#ViewRes.Shared.PublishAPhoto</h1>
<hr />
#using (Html.BeginForm("CreationUpload", "Creation", FormMethod.Post, new { id = "CreationUpload", enctype = "multipart/form-data", onsubmit = "$('#creationloading').show(); $('#creationform').hide();" }))
{
#Html.AntiForgeryToken()
<div class="col-md-12" id="creationloading" style="display:none">
<div id="progress">
<p>#ViewRes.Shared.UploadPhotoProgress<strong>0%</strong></p>
<progress value="5" min="0" max="100"><span></span></progress>
</div>
</div>
<div class="col-md-12" id="creationform">
<div class="col-md-12">
#Html.ValidationMessageFor(m => m.Creation.CreationSex)
#Html.RadioButtonFor(m => m.Creation.CreationSex, "F", new { #checked = true }) #ViewRes.Shared.WomanHairstyle #Html.RadioButtonFor(m => m.Creation.CreationSex, "M") #ViewRes.Shared.ManHairstyle
</div>
<div class="col-md-12">
#Html.ValidationMessageFor(m => m.Creation.CreationTitle)
#Html.TextBoxFor(m => m.Creation.CreationTitle, new { #class = "inputplaceholderviolet wid100x100", placeholder = HttpUtility.HtmlDecode(Html.DisplayNameFor(m => m.Creation.CreationTitle).ToHtmlString()), onfocus = "this.placeholder = ''", onblur = "this.placeholder = '" + HttpUtility.HtmlDecode(Html.DisplayNameFor(m => m.Creation.CreationTitle).ToHtmlString()) + "'" })
</div>
<div class="col-md-12">
#for (int i = 0; i < Model.CreationHairTags.Count; i++)
{
#Html.CheckBoxFor(m => Model.CreationHairTags[i].IsChecked)
#Model.CreationHairTags[i].Text
#Html.HiddenFor(m => Model.CreationHairTags[i].Value)
#Html.HiddenFor(m => Model.CreationHairTags[i].Text)<br />
}
</div>
<div class="col-md-12" style="text-align: center">
<p style="display: inline-block">
<input type="file" accept="image/*" onchange="loadFile(event)" name="files" id="file1" translate="yes" data-val="true" data-val-required="A File is required." class="wid100x100" /><label for="file1"></label>
<img id="output" style="max-width:200px;"/>
</p>
</div>
<div class="col-sm-12 col-md-12 chpagetopdiv">
<button type="submit" title="#ViewRes.Shared.Publish"><span class="glyphicon glyphicon-share-alt"></span> #ViewRes.Shared.Publish</button>
</div>
</div>
}
</div>
What is wrong in my code please help and explain ?

Important: In C#, every collection must be initialized before being accessed
The error occurs when you are trying to access from the View to the collection CreationHairTags, which is not initialized. Replace your model to initialize collection in the class constructor:
public class CreationHairTagsModel
{
public Creation Creation { get; set; }
public List<HairTagModel> CreationHairTags { get; set; }
public CreationHairTagsModel()
{
CreationHairTags = new List<HairTagModel>();
}
}

Related

Asp.NET MVC Product> ProductPhoto

I have 2 Separate Tables Products and Product Photo
When I examine any details in the products table, I want the pictures of that product to come. In that case, I pull it into the Detail table in a field called _UrunFotoPartitialView as # html.partitial ("") but always
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Urun_C7B3883A1159F8EE0177C29B1CA535182B157B3C5BB798ABCC8C2A72FB5CFED9', but this dictionary requires a model item of type 'Tututuncu.Models.UrunFotoViewModel'.
gives an error. How many days I have been dealing but I couldn't do it.
Ürün Class
public partial class Urun
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Urun()
{
this.Firma = new HashSet<Firma>();
this.Musteri = new HashSet<Musteri>();
this.Satis = new HashSet<Satis>();
}
public int UrunID { get; set; }
public Nullable<int> UrunFotoID { get; set; }
public Nullable<int> MarkaID { get; set; }
public string UrunAdi { get; set; }
public Nullable<decimal> UrunFiyat { get; set; }
public Nullable<decimal> UrunAlisFiyat { get; set; }
public Nullable<int> UrunStok { get; set; }
public string UrunAciklama { get; set; }
public Nullable<System.DateTime> UretimYili { get; set; }
public Nullable<System.DateTime> EklenmeTarihi { get; set; }
public Nullable<System.DateTime> GuncellenmeTarihi { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Firma> Firma { get; set; }
public virtual Markalar Markalar { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Musteri> Musteri { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Satis> Satis { get; set; }
public virtual UrunFoto UrunFoto { get; set; }
}
Ürün Foto Class
public partial class UrunFoto
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public UrunFoto()
{
this.Urun = new HashSet<Urun>();
}
public int FotoID { get; set; }
public Nullable<int> UrunFotoID { get; set; }
public string BuyukYol { get; set; }
public string OrtaYol { get; set; }
public string KucukYol { get; set; }
public Nullable<bool> Varsayilan { get; set; }
public string SiraNo { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Urun> Urun { get; set; }
}
My UrunController
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using Tututuncu.Models;
namespace Tututuncu.Areas.Yonetim.Controllers
{
[Authorize]
public class UrunController : Controller
{
private StokDBEntities db = new StokDBEntities();
// GET: Yonetim/Urun
public ActionResult Index()
{
return RedirectToAction("Listele");
}
public ActionResult Listele()
{
var urun = db.Urun.Include(u => u.Markalar).Include(u => u.UrunFoto);
return View(urun.ToList());
}
public ActionResult Yeni()
{
ViewBag.MarkaID = new SelectList(db.Markalar, "MarkaID", "MarkaAd");
ViewBag.UrunFotoID = new SelectList(db.UrunFoto, "FotoID", "BuyukYol");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Yeni([Bind(Include = "UrunID,UrunFotoID,MarkaID,UrunAdi,UrunFiyat,UrunAlisFiyat,UrunStok,UrunAciklama,UretimYili,EklenmeTarihi,GuncellenmeTarihi")] Urun urun)
{
if (ModelState.IsValid)
{
db.Urun.Add(urun);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.MarkaID = new SelectList(db.Markalar, "MarkaID", "MarkaAd", urun.MarkaID);
ViewBag.UrunFotoID = new SelectList(db.UrunFoto, "FotoID", "BuyukYol", urun.UrunFotoID);
return View(urun);
}
public ActionResult Guncelle(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Urun urun = db.Urun.Find(id);
if (urun == null)
{
return HttpNotFound();
}
ViewBag.MarkaID = new SelectList(db.Markalar, "MarkaID", "MarkaAd", urun.MarkaID);
ViewBag.UrunFotoID = new SelectList(db.UrunFoto, "FotoID", "BuyukYol", urun.UrunFotoID);
return View(urun);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Guncelle([Bind(Include = "UrunID,UrunFotoID,MarkaID,UrunAdi,UrunFiyat,UrunAlisFiyat,UrunStok,UrunAciklama,UretimYili,EklenmeTarihi,GuncellenmeTarihi")] Urun urun)
{
if (ModelState.IsValid)
{
db.Entry(urun).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.MarkaID = new SelectList(db.Markalar, "MarkaID", "MarkaAd", urun.MarkaID);
ViewBag.UrunFotoID = new SelectList(db.UrunFoto, "FotoID", "BuyukYol", urun.UrunFotoID);
return View(urun);
}
public ActionResult Sil(int id)
{
var silinecekUrun = db.Urun.Find(id);
if (silinecekUrun == null)
return HttpNotFound();
db.Urun.Remove(silinecekUrun);
db.SaveChanges();
return RedirectToAction("Index", "Urun");
}
public ActionResult UrunResimEkle(int id)
{
Urun urun = db.Urun.Find(id);
ViewBag.Foto = urun;
return View(urun);
}
public ActionResult FotoListele(int id)
{
Urun urun = db.Urun.Find(id);
ViewBag.Foto = urun;
return View(urun);
}
[HttpPost]
public ActionResult UrunResimEkle(int uId, HttpPostedFileBase fileUpload)
{
if (fileUpload != null)
{
Image img = Image.FromStream(fileUpload.InputStream);
Bitmap kucukResim = new Bitmap(img, ResimAyar.UrunKucukBoyut);
Bitmap ortaResim = new Bitmap(img, ResimAyar.UrunOrtaBoyut);
Bitmap buyukResim = new Bitmap(img, ResimAyar.UrunBuyukBoyut);
string buyukYol = "/images/UrunFoto/Buyuk/" + Guid.NewGuid() + VirtualPathUtility.GetExtension(fileUpload.FileName);
string ortaYol = "/images/UrunFoto/Orta/" + Guid.NewGuid() + VirtualPathUtility.GetExtension(fileUpload.FileName);
string kucukYol = "/images/UrunFoto/Kucuk/" + Guid.NewGuid() + VirtualPathUtility.GetExtension(fileUpload.FileName);
kucukResim.Save(Server.MapPath(kucukYol));
ortaResim.Save(Server.MapPath(ortaYol));
buyukResim.Save(Server.MapPath(buyukYol));
UrunFoto rsm = new UrunFoto();
rsm.BuyukYol = buyukYol;
rsm.OrtaYol = ortaYol;
rsm.KucukYol = kucukYol;
rsm.UrunFotoID = uId;
if (db.UrunFoto.FirstOrDefault(x => x.UrunFotoID == uId && x.Varsayilan == false) != null)
rsm.Varsayilan = true;
else
rsm.Varsayilan = false;
db.UrunFoto.Add(rsm);
db.SaveChanges();
return Redirect(ControllerContext.HttpContext.Request.UrlReferrer.ToString());
}
return View(uId);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Urun View Page
#model IEnumerable<Tututuncu.Models.Urun>
#{
ViewBag.Title = "Ürüne Resim Ekle";
Layout = "~/Areas/Yonetim/Views/Shared/_Layout.cshtml";
}
<!-- Page Content -->
<div id="page-wrapper">
<div class="container-fluid">
<div class="row bg-title">
<div class="col-lg-3 col-md-4 col-sm-4 col-xs-12">
<h4 class="page-title">File Upload</h4>
</div>
<div class="col-lg-9 col-sm-8 col-md-8 col-xs-12">
<ol class="breadcrumb">
<li>Yönetim Paneli</li>
<li class="active">File Upload</li>
</ol>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- .row -->
<div class="row">
<div class="col-sm-12 ol-md-6 col-xs-12">
<div class="white-box">
<h3 class="box-title">File Upload1</h3>
<label for="input-file-now">Your so fresh input file — Default version</label>
<form action="/Yonetim/Urun/UrunResimEkle" method="post" enctype="multipart/form-data">
<input type="hidden" name="uId" value="#Model" />
<input type="file" name="fileUpload" />
<input type="submit" name="name" value="Kaydet" class="btn btn-primary" />
</form>
</div>
</div>
</div>
#Html.Partial("FotoListele")
</div>
</div>
My Partitial View Page
#model IEnumerable<Tututuncu.Models.UrunFoto>
#{
ViewBag.Title = "FotoListele";
Layout = "~/Areas/Yonetim/Views/Shared/_Layout.cshtml";
}
<h2>FotoListele</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.BuyukYol)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.BuyukYol)
</td>
</tr>
}
</table>
You have two model types.
Parent: #model IEnumerable<Tututuncu.Models.Urun>
Partial: #model IEnumerable<Tututuncu.Models.UrunFoto>
You're calling Partial using #Html.Partial("FotoListele")
You can use #Html.Partial("FotoListele", THE-NEW-MODEL-OF-LIST-UrunFoto)
When using Partial without passing the new model, it uses the parent model. Thus, it gets exception when trying to perform the casting.
You can either create a new Model that fits the Partial needs, or accept the parent model.
Note: partial class doesn't relate at all to razor engine Html.Partial. more on that Here

insert multiple row in a single form using ASP.NET MVC

here my question is that where user enters area details like place-name, noofplaces, like that after creating user details here user entered noofplaces, so how many enters(10,20 or even 100) that many rows should be created.
here is the code worked for me
Area Model
`public class Area
{
[Key]
public int AreaID { get; set; }
public string ParkingPlaceName { get; set; }
public int NoOfParkingPlaces { get; set; }
[DataType(DataType.Currency)]
public decimal MinimumCharges { get; set; }
public string Address { get; set; }
[Precision(25,22)]
public decimal Latitude { get; set; }
[Precision(25,22)]
public decimal Longitude { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual ICollection<ParkingPlace> ParkingPlaces { get; set; }
}
}`
ParkingPlace Model
public class ParkingPlace
{
[Key]
public int ParkID { get; set; }
public string PlaceId { get; set; }
public int AreaID { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual Area Areas { get; set; }
}
controller code
public ActionResult Create(string areaName)
{
Area area = db.Areas.SingleOrDefault(x => x.ParkingPlaceName == areaName);
return View(area);
}
[HttpPost]
public ActionResult Create([Bind(Include = "ParkID,PlaceId,AreaID")] List<Place> place)
{
if (ModelState.IsValid)
{
foreach(var i in place)
{
db.Places.Add(i);
}
db.SaveChanges();
return RedirectToAction("Index", "Area");
}
return View(place);
}
View Code
#model CarParking.Models.Area
#using (Html.BeginForm("Create","ParkingPlace", FormMethod.Post))
{
<hr />
<table>
<tr>
<th>Place ID's</th>
<th>Area ID's</th>
</tr>
#for (int i = 0; i < Model.NoOfParkingPlaces; i++)
{
<tr class="form-group">
<td>
#Html.TextBox("[" + i + "].PlaceId", "P.Id_" + i + "", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessage("[" + i + "].PlaceId", "", new { #class = "text-danger" })
</td>
<td>
#Html.TextBox("[" + i + "].AreaID", Model.AreaID, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessage("[" + i + "].AreaID", "", new { #class = "text-danger" })
</td>
<td>
#Html.Hidden("[" + i + "].PlaceId_Status", false)
#Html.ValidationMessage("[" + i +"].PlaceId_Status", "", new { #class = "text-danger"})
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Create" class="btn btn-default" />
</p>
}

Pass Foreign Key via Post Form

I am doing an exercise of creating an helpdesk system. I'm using code first so i create some scripts that i'll describe briefly.
This class is my main class
public class Ticket
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Required]
[Display(Name = "Descrição")]
public string Description { get; set; }
public TicketStatus TicketStatus { get; set; }
public byte TicketStatusId { get; set; }
}
and i created this class to handle ticket answer with an fk to a ticket
public class TicketAnswer
{
public int Id { get; set; }
public Ticket Ticket { get; set; }
public int TicketId { get; set; }
public string Message { get; set; }
}
To create my form i created a viewmodel to handle all ticket answers
public class AnswerTicketViewModel
{
//public IEnumerable<TicketStatus> TicketStatus { get; set; }
public Ticket Ticket { get; set; }
public List<TicketAnswer> TicketAnswer { get; set; }
public string Message { get; set; }
}
and passing this form
#using (Html.BeginForm("SaveAnswer", "Ticket"))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Ticket.Id)
<div class="form-group">
#Html.LabelFor(model => model.Message, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.Message, 10, 50, new { htmlAttributes = new { #readonly = "readonly", disabled = "disabled", #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Message, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Enviar Resposta" class="btn btn-default" />
</div>
</div>
}
this is the action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveAnswer(TicketAnswer ticket)
{
if (!ModelState.IsValid)
{
var ticketStatus = _context.TicketStatus.ToList();
var ticketAnswer = _context.TicketAnswer.Where(t => t.TicketId == ticket.Ticket.Id).ToList();
var viewModel = new AnswerTicketViewModel
{
Ticket = ticket.Ticket,
TicketAnswer = ticketAnswer
};
return View("AnswerTicketForm", viewModel);
}
_context.TicketAnswer.Add(ticket);
_context.SaveChanges();
return RedirectToAction("Index", "Ticket");
}
I'm getting an error "The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo_TicketAnswers_dbo_Tickets_TicketId" how i change that and handle this fk? I try all kinds of solution can someone give a tip?
Got it guys on my viewmodel i put a variable that i set on the form to the id of the ticket and it persists on the post method
public class AnswerTicketViewModel
{
//public IEnumerable<TicketStatus> TicketStatus { get; set; }
public Ticket Ticket { get; set; }
public int TicketId { get; set; }
public List<TicketAnswer> OtherAnswers { get; set; }
public TicketAnswer TicketAnswer { get; set; }
}
#Html.HiddenFor(model => model.TicketId, new { Value=Model.Ticket.Id })
So i was able to handle the database with that foreign key, thanks guys

Unable to populate checkbox from database data in mvc 4

This is my Controller code.
public ActionResult Create()
{
ViewBag.grp_id = new SelectList(db.tm_grp_group, "grp_id", "grp_name");
ViewBag.perm_id = new SelectList(db.tm_perm_level, "perm_id", "perm_levelname");
return View();
}
Below is my view code.
#model Permission.ts_grp_perm_mapping
....
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ts_grp_perm_mapping</legend>
<div class="editor-label">
#Html.LabelFor(model => model.grp_permid)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.grp_permid)
#Html.ValidationMessageFor(model => model.grp_permid)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.grp_id, "tm_grp_group")
</div>
<div class="editor-field">
#Html.DropDownList("grp_id", String.Empty)
#Html.ValidationMessageFor(model => model.grp_id)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.perm_id, "tm_perm_level")
</div>
<div class="editor-field">
#Html.DropDownList("perm_id", String.Empty)
#Html.ValidationMessageFor(model => model.perm_id)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
In controller ViewBag.perm_id contains some values (this is foreign key). In view perm.id displays in the form of dropdownbox but I want it in the form of checkboxlist. How can I achieve this?
This is the viewmodel I created.
public class AssignUserViewModel
{
public tm_perm_level[] perms { get; set; }
public int grp_id { get; set; }
}
Now in controller how can i send values to view? This is my tm_perm_level model
public partial class tm_perm_level
{
public tm_perm_level()
{
this.ts_grp_perm_mapping = new HashSet<ts_grp_perm_mapping>();
}
public int perm_id { get; set; }
public string perm_levelname { get; set; }
public string perm_description { get; set; }
public bool perm_status { get; set; }
public virtual ICollection<ts_grp_perm_mapping> ts_grp_perm_mapping { get; set; }
}
This is ts_grp_perm_mapping model
public partial class ts_grp_perm_mapping
{
public ts_grp_perm_mapping()
{
this.ts_perm_levelmapping = new HashSet<ts_perm_levelmapping>();
}
public int grp_permid { get; set; }
public int grp_id { get; set; }
public int perm_id { get; set; }
public List<tm_perm_level> permissions { get; set; }
public virtual tm_grp_group tm_grp_group { get; set; }
public virtual tm_perm_level tm_perm_level { get; set; }
public virtual ICollection<ts_perm_levelmapping> ts_perm_levelmapping { get; set; }
}
Especially when editing, always start with view models to represent what you want to display (refer What is ViewModel in MVC?)
public class PermissionVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class GroupPermissionVM
{
public int GroupID { get; set; }
public IEnumerable<SelectListItem> GroupList { get; set; }
public IEnumerable<PermissionVM> Permissions { get; set; }
}
Then create an EditorTemplate for PermissionVM. In the /Views/Shared/EditorTemplates/PermissionVM.cshtml folder
#model PermissionVM
<div>
#Html.HiddenFor(m => m.ID)
#Html.HiddenFor(m => m.Name)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.IsSelected, Model.Name)
</div>
and the main view will be
#model GroupPermissionVM
....
#using (Html.BeginForm())
{
// dropdownlist
#Html.LabelFor(m => m.GroupID)
#Html.DropDownListFor(m => m.GroupID, Model.GroupList, "Please select")
#Html.ValidationMessageFor(m => m.GroupID)
// checkboxlist
#Html.EditorFor(m => m.Permissions)
<input type="submit" value="Create" />
}
The controller methods would then be
public ActionResult Create()
{
var groups = db.tm_grp_group;
var permissions = db.tm_perm_level;
GroupPermissionVM model = new GroupPermissionVM
{
GroupList = new SelectList(groups, "grp_id", "grp_name"),
Permissions = permissions.Select(p => new PermissionVM
{
ID = p.perm_id,
Name = p.perm_levelname
}
};
return View(model);
}
[HttpPost]
public ActionResult Create(GroupPermissionVM model)
{
if (!ModelState.IsValid)
{
var groups = db.tm_grp_group;
model.GroupList = new SelectList(groups, "grp_id", "grp_name");
return View(model);
}
// map the view model to a new instance of your data model(s)
// note: to get the ID's of the selected permissions -
// var selectedPermissions = model.Permissions.Where(p => p.IsSelected).Select(p => p.ID);
// save and redirect
}
Side note: I strongly recommend you follow normal naming conventions
Edit
Based on OP's comment for an option using radio buttons to select only one item, the revised code would be
public class PermissionVM
{
public int ID { get; set; }
public string Name { get; set; }
}
public class GroupPermissionVM
{
public int GroupID { get; set; }
public int PermissionID { get; set; }
public IEnumerable<SelectListItem> GroupList { get; set; }
public IEnumerable<PermissionVM> Permissions { get; set; }
}
and the view would be (no separate EditorTemplate required)
#model GroupPermissionVM
....
#using (Html.BeginForm())
{
// dropdownlist as above
// radio buttons
foreach (var permission in Model.Permissions)
{
<label>
#Html.RadioButtonForm(m => m.PermissionID, permission.ID)
<span>#permission.Name</span>
</label>
}
<input type="submit" value="Create" />
}
and in the POST method, the value of model.PermissionID will contain the ID of the selected Permission.

ASP.net MVC 3 handling multiple checkboxes in each row of my table

I'm building an admin interface for a word guessing game so admin users are allowed to setup the game by selecting the words that will appear in the game and then select which letters in the words will be encoded.
MainGameTable Edit page.....
#model GameServer.ViewModels.GameTableModel
#section Javascript
{
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
}
#{
ViewBag.Title = "GameTableEdit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>GameTableEdit</h2>
#using (Html.BeginForm("GameTableEdit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>GameTable</legend>
#Html.HiddenFor(model => model.GameTableId)
#Html.HiddenFor(model => model.GameTableNumber)
<div class="editor-label">
Table #: #Html.DisplayFor(model => model.GameTableNumber)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SubjectId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.SubjectId, new SelectList(Model.Subjects, "Key", "Value"))
#Html.ValidationMessageFor(model => model.SubjectId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ComplexityId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ComplexityId, new SelectList(Model.Complexities, "Key", "Value"))
#Html.ValidationMessageFor(model => model.ComplexityId)
</div>
<button type="submit" name="button" value="GetWords">Get Words</button>
#Html.Partial("GameMatrix/_LineWordsTable", Model)
<p>
<button type="submit" name="button" value="Save">Save</button>
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Partial Page_for each of the words in the table
#model GameServer.ViewModels.GameTableModel
#if (Model.SelectedLinewords.Count != null && Model.SelectedLinewords.Count > 0)
{
<table>
<tr>
<th>
Select Word
</th>
<th>
LineWord
</th>
<th>
Characters to Display
</th>
</tr>
#Html.EditorFor(x => x.SelectedLinewords)
</table>
}
The Editor Template for each row:
#model GameServer.ViewModels.SelectedLineWord
<tr>
<td>
#Html.CheckBoxFor(x => x.isSelected)
</td>
<td>
#Html.DisplayFor(x => x.LineWord)
</td>
<td>
#Html.HiddenFor(x=>x.LineWordId)
#Html.HiddenFor(x=>x.LineWord)
#{ char[] lineword = Model.LineWord.ToCharArray(); }
#for (int i = 0; i < Model.LineWord.Length; i++)
{
<input type="checkbox" name="DisplayCharPosition" value="#i" /> #lineword[i]
}
</td>
</tr>
Here is my ViewModel
public class SelectedLineWord
{
[Required]
public Guid LineWordId { get; set; }
[Required]
public String LineWord { get; set; }
public int[] DisplayCharPosition { get; set; }
[Required]
public bool isSelected { get; set; }
public SelectedLineWord()
{
}
public SelectedLineWord(Guid linewordid, String word, String displaycharposition)
{
LineWordId = linewordid;
LineWord = word;
String[] pos = displaycharposition.Split(',');
DisplayCharPosition = new int[word.Length];
for (int i = 0; i < word.Length; i++)
{
DisplayCharPosition[i] = 0;
}
for (int i = 0; i < pos.Length; i++)
{
DisplayCharPosition[Int32.Parse(pos[i])] = 1;
}
}
public SelectedLineWord(Guid linewordid, String word, bool issel)
{
LineWordId = linewordid;
LineWord = word;
isSelected = issel;
}
}
public class GameTableModel
{
[Required]
public Guid GameTableId { get; set; }
[Required]
public Guid GameMatrixId { get; set; }
[Required]
[Display(Name = "Table Subject")]
public int SubjectId { get; set; }
[Required]
[Display(Name = "Minimum Complexity")]
public int ComplexityId { get; set; }
[Required]
public int GameTableNumber { get; set; }
[Required]
[Display(Name = "Include a Bonus table")]
public bool IsBonus { get; set; }
[Display(Name = "Table Subject")]
public Dictionary<int, string> Subjects;
[Display(Name = "Minimum Complexity")]
public Dictionary<int, int> Complexities;
public List<GameTableLine> GameTableLines { get; set; }
public List<SelectedLineWord> SelectedLinewords { get; set; }
public GameTableModel ()
{
try
{
//get a connection to the database
var data = new GameServerDataModelDataContext();
//Fetch the subjects reference data
var subjects = from c in data.Subjects orderby c.Subject1 select new { c.SubjectId, c.Subject1};
Subjects = new Dictionary<int, string>();
foreach (var subject in subjects)
{
Subjects.Add(subject.SubjectId, subject.Subject1);
}
//Fetch the complexities questions
Table<Complexity> dComplexities = data.GetTable<Complexity>();
Complexities = new Dictionary<int, int> { { 0, 0 } };
foreach (var complexity in dComplexities)
{
if (complexity.Complexity1 != null)
Complexities.Add(complexity.ComplexityId, (int)complexity.Complexity1);
}
}
catch (Exception ex)
{
//[TODO: Complete the exception handeling code.]
}
}
}
My problem is when I hit the save button the model passed to the controller has everything populated correctly but returns null for the check boxes that where selected for the DisplayCharPosition. What i was expecting was an int[] populated with the index of the character selected for display.
Could someone please help me understand what I'm doing wrong?
I've manage to solve this (but i'm still open to suggestions for a better way to do it).
What I did was I changed the following line <input type="checkbox" name="DisplayCharPosition" value="#i" /> #lineword[i] to #Html.CheckBoxFor(x => x.DisplayCharPosition[i]) #lineword[i] and my model type to public bool[] DisplayCharPosition { get; set; } so that i store an array of bools. Now the bool array has a true/false value for each char that the user wants to display in the game table. I then store this in the database as a comma delimited string (e.g. 1,4,6 - which i later split so i know that char in pos 1, 4 and 6 must be displayed and the rest encoded).
I also changed my model as follows:
public class SelectedLineWord
{
[Required]
public Guid LineWordId { get; set; }
[Required]
public String LineWord { get; set; }
public bool[] DisplayCharPosition { get; set; }
[Required]
public bool isSelected { get; set; }
public SelectedLineWord()
{
}
public SelectedLineWord(Guid linewordid, String word, String displaycharposition)
{
LineWordId = linewordid;
LineWord = word;
String[] pos = displaycharposition.Split(',');
DisplayCharPosition = new bool[word.Length];
//set all to false
for (int i = 0; i < word.Length; i++)
{
DisplayCharPosition[i] = false;
}
//now only set the ones that were already in the db.
for (int i = 0; i < pos.Length; i++)
{
DisplayCharPosition[Int32.Parse(pos[i])] = true;
}
}

Resources