How to save Dictionary object to database in MVC 4? - asp.net-mvc-4

So, I am sending a dictionary object to my view from the controller.
// GET: QuestionResponses/Create
public ActionResult Create(int questionnaireUID)
{
var questions = from q in db.QUESTIONS
where q.QuestionnaireUID == questionnaireUID
select q;
ViewBag.NextQuestion = from q in db.QUESTIONS
where q.QuestionnaireUID == questionnaireUID
select new SelectListItem
{
Selected = (q.QuestionnaireUID == questionnaireUID),
Text = q.Question1,
Value = q.QuestionUID.ToString()
};
Dictionary<QUESTION, QUESTION_RESPONSES> dict = new Dictionary<QUESTION, QUESTION_RESPONSES>();
foreach (var question in questions)
{
dict.Add(question, new QUESTION_RESPONSES { QuestionUID = question.QuestionUID, Response = "", NextQuestion = "" });
}
return View(dict);
}
The reasoning behind this is that I need to view data from one model and need to add/edit data from another model. I tried using Tuples and was not able to get it to work (if you could tell me how to do this with Tuples, that would be helpful too).
This is what the view does with this Dictionary object.
<div class="form-group">
<h2> Reponses </h2>
<p> For each question, enter in the appropriate response(s). All questions must have at least one response. <p>
<div id="editorRows">
<div class="rows_no_scroll">
#foreach (var item in Model.ToArray())
{
<!-- The question that responses are being added to. -->
Html.RenderPartial("QuestionRow", item.Key);
<!-- All questions pertaining to this questionnaire. -->
// <p>Please select the question which should be asked as a response to this question.</p>
#Html.DropDownList("NextQuestion", null, htmlAttributes: new { #class = "form-control", id = "ddl_questions_" + count})
#Html.ValidationMessageFor(model => item.Value.NextQuestion, "", new { #class = "text-danger" })
<!-- The next question link and responses being inputted by user. -->
Html.RenderPartial("ResponseEditorRow", item.Value);
// <p> Question #count </p>
count += 1;
}
</div> <!--/rows_no_scroll-->
</div> <!-- /editorRows -->
</div> <!-- /form-group -->
For completeness, here are what the partial views are doing.
QuestionRow:
<div class="questionRow">
<!-- Hide attribute(s) not being viewed/edited. -->
#Html.HiddenFor(model => model.QuestionUID)
#Html.HiddenFor(model => model.QuestionnaireUID)
<!-- Show attribute(s) being viewed. -->
#Html.DisplayFor(model => model.Question1)
<div class="addQuestion">Add Response</div>
</div>
ResponseEditorRow:
<div class="editorRow">
#using (Html.BeginCollectionItem("questions"))
{
<!-- Hide attribute(s) not being viewed/edited. -->
#Html.HiddenFor(model => model.ResponseUID)
#Html.HiddenFor(model => model.QuestionUID)
<br>
<!-- Display attribute(s) being edited. -->
#Html.EditorFor(model => model.Response, new { htmlAttributes = new { #type = "text", #name = "question", #class = "question_input" } })
#Html.ValidationMessageFor(model => model.Response, "", new { #class = "text-danger" })
<input type="button" name="addRow[]" class="deleteRow" value="Delete">
}
</div>
The problem that I am having is that when I get back to my controller to POST the data inserted by the user, my Dictionary is empty. I'm not sure if I am inserting the information correctly. I am changing the dictionary object toArray(), not sure if this is affecting anything...
Here is the HTTP POST create method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ResponseUID, QuestionUID, Response, NextQuestion")] Dictionary<QUESTION, QUESTION_RESPONSES> question_question_response)
{
if (ModelState.IsValid)
{
foreach (var item in question_question_response.ToArray())
{
db.QUESTION_RESPONSES.Add(item.Value);
db.SaveChanges();
return RedirectToAction("Index"); // Update to take user to Actions/Create page.
}
}
ViewBag.NextQuestion = new SelectList(db.QUESTIONS, "QuestionUID", "Question1");
return View(question_question_response);
}
Open to any suggestions of different ways I could do this or on what may be wrong with what I am currently doing.

Create 2 ViewModels:
public class QuestionAireViewModel {
public int QuestionAireId {get;set;}
public List<QuestionViewModel> Quesitons {get;set;}
}
public class QuestionViewModel{
public int QuestionId {get;set;}
public string Question {get;set;}
public string QuestionResponse {get;set;}
}
In your view pass this QuestionAireViewModel
Generate QuestionAireViewModel in your controller like this:
public ActionResult GetQuestions(int id)
{
var questionAire = db.QuesitonAire.First(s => s.QuestionAireId == id)
var questions = new List<QuestionViewModel>();
foreach(var question in questionAire.Questions){
questions.Add(new QuestionViewModel(){
Quesiton = question.Question,
});
}
var model = new QuestionAireViewModel(){
QuestionAireId = questionAire.Id,
Quesitons = questions
};
return View(model);
}
Then on POST Form method will be:
[HttpPost]
public ActionResult SaveQuestions(QuestionAireViewModel model)
{
}

Related

MVC Ajax with Dynamic Partial View Creation

How can I create dynamic ajax.actionlinks that will call dynamic partial views.
For example:
I have a page that will generate x number of comments
Each comment can be voted up or down (individually)
The number of up votes and down votes are counted into a single integer
Each comment div will have its own ajax.actionlink
Each ajax.actionlink will pass to the controller the ID of the comment
The controller will calculate the total votes and call the partial view to display back into the div with the correct ID.
What have I done so far:
I have been able to create successful ajax.actionlink
That will call a controller and sum the votes
That will call the partial view and display the votes
What is the issue
I don't want to hard code 30-100 different ajax.actionlinks to call 30-100 hard coded partial views.
How can I accomplish this dynamically?
Existing Code:
My ajax.actionlink inside my razor view
#Html.Raw(Ajax.ActionLink("[replacetext]", "VoteUp",
new { UserPostID = #Model.Id },
new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "CountVote" }).ToHtmlString().Replace("[replacetext]",
"<img src=\"/Images/up_32x32.png\" />"))
My div inside the same razor view to display the returning results from the partial view.
<div id="CountVote" class="postvotes"></div>
My controller
public PartialViewResult VoteUp(int UserPostID)
{
try
{
UserVotes vote = new UserVotes();
vote.SubmitedVote = 1;
vote.UserId = Convert.ToInt32(Session["id"]);
vote.UserPostID = UserPostID;
ViewBag.SumVotes = postRepository.InsertUserPostVote(vote);
}
catch (Exception e)
{
xxx.xxx.xxxx().Raise(e);
}
return PartialView("_TotalVotes");
}
And finally my partial view (_TotalVotes.cshtml)
#ViewBag.SumVotes
Now my main view for Viewpost shows the comments in a loop using the viewbag.
foreach (var item in (List<UserComment>)ViewData["Comments"])
{
CommentVote = "cv" + i.ToString();
<div class="postlinewrapper">
<div class="postvotesframe">
<div class="postvotes">
#Html.Raw(Ajax.ActionLink("[replacetext]", "VoteUp",
new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "CountVote" }).ToHtmlString().Replace("[replacetext]",
"<img src=\"/Images/up_32x32.png\" />"))
</div>
<div id="#CommentVote" class="#CommentVote">0</div>
<div class="postvotes">
#Html.Raw(Ajax.ActionLink("[replacetext]", "VoteDown",
new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "CountVote" }).ToHtmlString().Replace("[replacetext]",
"<img src=\"/Images/down_32x32.png\" />"))
</div>
</div>
<div class="postleftbar">
#Html.Raw(item.Comment)
</div>
<div class="postrightbar">
<div>
<div class="post_spec">
<div class="post_spec_title">Call Sign: </div>
<div class="post_spec_detail">#item.CallSign</div>
</div>
<div class="post_spec">
<div class="post_spec_title">When: </div>
<div class="post_spec_detail">#item.CommentDate.ToString("dd/MM/yyyy")</div>
</div>
</div>
<br />
<br />
</div>
</div>
i += 1;
}
I have implemented the login to increase or decrease votes up and down:
public PartialViewResult VoteUp(int userPostId)
{
try
{
UserVotes vote = new UserVotes();
vote.SubmitedVote = 1;
vote.UserId = Convert.ToInt32(Session["id"]);
vote.UserPostID = userPostId;
ViewBag.SumVotes = postRepository.InsertUserPostVote(vote);
}
catch (Exception e)
{
xxxx.xxxx.xxxx().Raise(e);
}
return PartialView("_TotalVotes");
}
public PartialViewResult VoteDown(int userPostId)
{
try
{
UserVotes vote = new UserVotes();
vote.SubmitedVote = -1;
vote.UserId = Convert.ToInt32(Session["id"]);
vote.UserPostID = userPostId;
ViewBag.SumVotes = postRepository.InsertUserPostVote(vote);
}
catch (Exception e)
{
xxx.xxxx.xxxx().Raise(e);
}
return PartialView("_TotalVotes");
}
Now all this code works for 1 ajax call just fine, but what I need to is to display separate ajax calls for separate divs dynamically.
Try it this way.
Main view
I'm supposing you have a model with a collection property Comments of Comment items
#model MyNamespace.CommentAndOtherStuff
<ul>
#foreach(item in Model.Comments)
{
<li>
<a href="#Url.Action("VoteUp", "VoteControllerName", new { UserPostId = item.Id })"
class="vote-link"
data-id="#item.Id">#item.Votes</a><img src="vote.jpg" />
</li>
}
</ul>
And your controller just returns a class called VoteResult as JSON.
[HttpPost]
public ActionResult VoteUp(int UserPostID)
{
...
var model = new VoteResult
{
UserPostID = UserPostID,
Votes = service.tallyVote(UserPostID)
};
return Json(model);
}
Now hook all of those up with a jQuery event handler and setup an AJAX call
$(document).ready(function() {
$("a.vote-link").on("click", function(event) {
event.preventDefault();
var link = $(this); // the link instance that was clicked
var id = link.attr("data-id");
var url = link.attr("href");
$.ajax({
url: url,
type: "post"
})
.done(function(result) {
// JSON result: { UserPostID: 1, Votes: 5 }
// replace link text
link.html(result.Votes);
});
});
});
But I want a partial view html fagment.
[HttpPost]
public ActionResult VoteUp(int UserPostID)
{
...
var model = new VoteResult
{
UserPostID = UserPostID,
Votes = service.tallyVote(UserPostID)
};
return PartialView("_TotalVotes", model);
}
_TotalVotes partial
#model MyNamespace.VoteResult
#if (Model.Votes < 0)
{
<span class="unpopular">#Model.Votes</span>
}
else
{
<span class="awesome">#Model.Votes</span>
}
And adjust the AJAX callback
.done(function(result) {
link.html(result);
});
Now you could write a helper for the link fragment but it obfuscates things in my opinion (it's a judgement call). All you really need here is the class name and the data-id which your javascript will bind.
Using the Ajax helpers here seems an unnecessary overhead and I suggest you just use jquery methods to update the DOM. Your current code suggests you might be missing some logic to make a comment voting system work, including indicating what action the user may have already performed. For example (and assuming you want it to work similar to SO), if a user has previously up-voted, then clicking on the up-vote link should decrement the vote count by 1, but clicking on the down-vote link should decrement the vote count by 2 (the previous up-vote plus the new down-vote).
Refer to this fiddle for how this might be styled and behave when clicking the vote elements
Your view model for a comment might look like
public enum Vote { "None", "Up", "Down" }
public class CommentVM
{
public int ID { get; set; }
public string Text { get; set; }
public Vote CurrentVote { get; set; }
public int TotalVotes { get; set; }
}
and assuming you have a model that contains a collection of comments
public class PostVM
{
public int ID { get; set; }
public string Text { get; set; }
public IEnumerable<CommentVM> Comments { get; set; }
}
and the associated DisplayTemplate
/Views/Shared/DisplayTemplates/CommentVM.cshtml
#model CommentVM
<div class="comment" data-id="#Model.ID" data-currentvote="#Model.CurrentVote">
<div class="vote">
<div class="voteup" class="#(Model.CurrentVote == Vote.Up ? "current" : null)"></div>
<div class="votecount">#Model.TotalVotes</div>
<div class="votedown" class="#(Model.CurrentVote == Vote.Down ? "current" : null)"></div>
</div>
<div class="commenttext">#Html.DisplayFor(m => m.Text)</div>
</div>
Then in the main view
#model PostVM
.... // display some properties of Post?
#Html.DisplayFor(m => m.Comments)
<script>
var voteUpUrl = '#Url.Action("VoteUp")';
var voteDownUrl = '#Url.Action("VoteDown")';
$('.voteup').click(function() {
var container = $(this).closest('.comment');
var id = container.data('id');
var voteCount = new Number(container.find('.votecount').text());
$.post(voteUpUrl, { id: id }, function(response) {
if (!response) {
// oops, something went wrong - display error message?
return;
}
container.find('.votecount').text(response.voteCount); // update vote count
if (response.voteCount < voteCount) {
// the user previously upvoted and has now removed it
container.find('.voteup').removeClass('current');
} else if (response.voteCount == voteCount + 1) {
// the user had not previously voted on this comment
container.find('.voteup').addClass('current');
} else if (response.voteCount == voteCount + 2) {
// the user previoulsy down voted
container.find('.votedown').removeClass('current');
container.find('.voteup').addClass('current');
}
});
});
$('.votedown').click(function() {
... // similar to above (modify logic in if/elseif blocks)
});
</script>
and the controller method
public JsonResult VoteUp(int id)
{
int voteCount = // your logic to calculate the new total based on the users current vote (if any) for the comment
return Json(new { voteCount = voteCount });
}

using MVC4 Strongly typed view with Knockout

I am trying to use knockout with MVC strongly typed view. Since my model will have over 20 properties, I prefer to use strongly-typed view model to post back data by using ko.mapping.toJS and ko.Util.postJson. The Eligible field was passed back correctly, however the following code does not post back the selected option from drop down list, it just showed value as 0 when I looked that selectOptionModel on the controller. Can someone point out what I did wrong?
the view model from server side is as follows:
public class SelectOptionModel
{
public bool Eligible { get; set; }
public int selectedOption { get; set; }
public IEnumerable<SelectListItem> AvailableOptions
{
get
{
return Enum.GetValues(typeof(OptionEnum)).Cast<OptionEnum>()
.Select(x => new SelectListItem
{
Text = x.ToString(),
Value = x.ToString()
});
}
}
}
public enum OptionEnum
{
[Description("First")]
FirstOption = 1,
[Description("Second")]
SecondOption = 2,
[Description("Third")]
ThirdOption = 3
}
The razor view is like following:
#model TestKo.Models.SelectOptionModel
...
subViewModel = ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)));
...
}
#using (Html.BeginForm()){
<button type="submit" class="button" id="SaveBtn">Save</button>
<div data-bind="with:vm">
<div>
#Html.LabelFor(model => model.Eligible)
#Html.CheckBoxFor(model => model.Eligible, new { data_bind = "checked: selectOptionVM.Eligible" })
</div>
<div>
#Html.LabelFor(model => model.selectedOption)
#Html.DropDownListFor(model => model.selectedOption, Model.AvailableOptions,
new
{ data_bind = "options: selectOptionVM.AvailableOptions, optionsText: 'Text', optionsValue: 'Value', value: selectOptionVM.selectedOption"
})
</div>
</div>
}
The javascript for the knockout view model is:
sectionVM = function (data) {
var self = this;
var selectOptionVM = data;
return {
selectOptionVM: selectOptionVM
}
}
$(document).ready(function () {
var viewModel = {
vm: new sectionVM(subViewModel)
};
ko.applyBindings(viewModel);
$("#SaveBtn").click(function () {
var optionModel = ko.toJS(viewModel.vm.selectOptionVM);
ko.utils.postJson($("form")[0], optionModel)
});
});
The controller part:
[HttpPost]
public ActionResult Create(SelectOptionModel selectOptionModel)
{
try
{
// TODO: Add insert logic here
var modelSaved = selectOptionModel;
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I'm venturing a bit of a guess here, but this could be the problem: the id-bit of your selected option will always be a string (because it will go in the <option value="" attribute). Your endpoint expects an int. As far as I can see, you don't convert the selectedOption before sending it to the server. try parseInt(selectedOption, 10) before sending it to the server. Also, use the network tool in your browser to debug the info that is being sent to the controller. That might help you to zone in on the problem.
Actually it works. Somehow it was not working previously, but after I cleared cache, cookies etc, it just worked. Thanks everyone!

Adding a record to the database based on input passed from a link on another form MVC 4

I have been using ASP.NET MVC 4 for a while but I have not yet come across a situation where i need to insert a value into the database from a scaffolded Create view which is based on a value passed from another view. I have tried to infer from the Edit view to try and modify my code to work but I have run into a snag. I got an error similar to this post. Here is my code from the view passing the value
#Html.ActionLink("Allocate", "Create", "Allocation", new { id=item.requestID}, null)
this is from the list of requests already in the database from the Index view
here is my code on the controller that is trying to force the Create method to use the ID passed from the link above
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(request);
}
then here is the posting code to the db
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Allocation allocation)
{
if (ModelState.IsValid)
{
db.Allocations.Add(allocation);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", allocation.requestID);
return View(allocation);
}
Basically what I am trying to do is allocate funds to a request made where by the allocation is entered into the db based on the request id. I am trying to prevent the user from choosing the request id from a drop down list. When I run this i get an error
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Request_A52006F7570E0448EE323CB36858E4D13EED0BAD958340B32FF166708545DA8C', but this dictionary requires a model item of type 'BudgetAllocation.Models.Allocation'.
If theres anyone out there who can help me out with this please do as soon as you can. I appreciate all the effort offred!!!!!
//EDIT
Here is my Create view
#model BudgetAllocation.Models.Allocation
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Allocation</legend>
#Html.HiddenFor(model => model.requestID)
<div class="editor-label">
#Html.LabelFor(model => model.allocAmount, "Amount")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.allocAmount)
#Html.ValidationMessageFor(model => model.allocAmount)
</div>
<p>
<input type="submit" value="Allocate" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The problem is your view id strongly typed with BudgetAllocation.Models.Allocation while in get action of Create you are passing object of type BudgetAllocation.Models.Request thats why you are getting the exception.
You have to pass object of type BudgetAllocation.Models.Allocation in Create get action as well because you view is strongly typed to it.
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
return View(request) // <-------------- here is the mistake
}
it should return allocation object, something like this, it is just an example may be you need to do some other thing instead of selecting:
public ActionResult Create(int id = 0)
{
Allocation allocation = db.Allocations.Find(x=>x.requestID == id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(allocation);
}
UPDATE:
you simply need to do like this not return allocaiton object return simply View:
public ActionResult Create(int id = 0)
{
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View();
}

View not binding correcty with the model

I can figure out why it's not binding. So I have a form where a ListBox is in a partial view which I reload everytime I click on a checkbox to fill the listbox.
The code of my ModelView for the form is :
<div class="row-fluid">
<div class="span3">
<label>Fonction(s):</label>
</div>
<div class="span9" id="ListeFonction">
#Html.Partial("ListerFonction", Model)
</div>
</div>
<div class="row-fluid">
<div class="span5 offset3">
<div class="fonctions_container">
#foreach (extranetClient.Models.Classes.FonctionContact fonction in ViewBag.Fonctions)
{
string coche = "";
if ((#Model.ListeFonctions).Any(c => c.IdFonction == fonction.IdFonction))
{
coche = "checked";
}
<input type="checkbox" #coche class="checkbox" value="#fonction.IdFonction" />#fonction.LibelleFonction <br />
}
</div>
</div>
</div>
So as you can see, I render a partial view just after the "Email" Textbox. The code for it is :
#Html.LabelFor(contact => contact.SelectedFonctionIds, "ListeFonctions")
#Html.ListBoxFor(contact => contact.SelectedFonctionIds, new MultiSelectList(Model.ListeFonctions, "IdFonction", "LibelleFonction"), new { disabled = "disabled")
The model associated to that view looks like that:
private List<int> _selectedFonctionIds;
public List<int> SelectedFonctionIds
{
get
{
return _selectedFonctionIds ?? new List<int>();
}
set
{
_selectedFonctionIds = value;
}
}
public List<FonctionContact> ListeFonctions = new List<FonctionContact>();
public MultiSelectList ListeFonctionsSelectList
{
get
{
return new MultiSelectList(
ListeFonctions,
"IdFonction", // dataValueField
"LibelleFonction" // dataTextField
);
}
}
public Contact() { }
public Contact( List<FonctionContact> listeFonctions, List<int> selectedFonctionIds)
{
this.ListeFonctions = listeFonctions;
this.SelectedFonctionIds = selectedFonctionIds;
}
public Contact(int idContact, string nom, string prenom, string email, string telephoneFixe, string telephonePort) {
this.IdContact = idContact;
this.Nom = nom;
this.Prenom = prenom;
this.Email = email;
this.TelephoneFixe = telephoneFixe;
this.TelephonePort = telephonePort;
}
public Contact(int idContact, string nom, string prenom, List<int> selectedFonctionIds, List<FonctionContact> listeFonctions, string email, string telephoneFixe, string telephonePort)
{
this.IdContact = idContact;
this.Nom = nom;
this.Prenom = prenom;
this.SelectedFonctionIds = selectedFonctionIds;
this.ListeFonctions = listeFonctions;
this.Email = email;
this.TelephoneFixe = telephoneFixe;
this.TelephonePort = telephonePort;
}
But the ListBox of the partial view is not binding with the model. I get well the other informations but not these in the listbox. Somebody has an idea ?
Why are you forcing the ListBox's id here:
#Html.ListBoxFor(contact => contact.SelectedFonctionIds,
new MultiSelectList(Model.ListeFonctions, "IdFonction", "LibelleFonction"),
new { disabled = "disabled", **id="idFonctions"** })
ListBoxFor helper is supposed to generate the ListBox's id for you, and the Id should be the same as the attribute it should bind with. Shouldn't it be SelectedFonctionIds?
Was the binding working before you started using the PartialView? Because from your previous question, I see that you had:
#Html.ListBoxFor(contact => contact.SelectedFonctionIds, Model.ListeFonctionsSelectList, new { disabled = "disabled" })
in your View (i.e., you didn't set the id attribute).

Cascade Drop down list

I am trying to create a cascading drop down list, and I am getting an error.
This contains what I am try to do with in my controller class:
public ActionResult Create()
{
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName");
ViewBag.CategoryID = new SelectList(db.pjt_Categories, "pjt_Category_ID", "CatName");
return View();
}
public ActionResult SubCategory(int id)
{
var SubCategory = from s in db.pjt_SubCategories
where s.CategoryID == id
select s;
return Json(SubCategory.ToList());
}
// POST: /Project/Create
[HttpPost]
public ActionResult Create(pjt_Projects pjt_projects)
{
if (ModelState.IsValid)
{
pjt_projects.CreationDate = DateTime.Now;
db.pjt_Projects.Add(pjt_projects);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Status = new SelectList(db.pjt_Statuses, "pjt_Status_ID", "StatusName", pjt_projects.Status);
ViewBag.CategoryID = new SelectList(db.pjt_Categories, "pjt_Category_ID", "CatName", pjt_projects.CategoryID);
return View(pjt_projects);
}
View
This shows what I am try to do on the front end. I am getting a error with the bold line in my view code below. The error I am getting is:
There is no ViewData item of type IEnumerable<SelectListItem> that has the key pjt_SubCat_ID.
Code:
<div class="span3 offset1">
#Html.LabelFor(model => model.CategoryID, "Category")
#Html.DropDownList("CategoryID", String.Empty)#*, null, new { #onchange = "FetchSubCategories();" })*#
<br />
#Html.ValidationMessageFor(model => model.CategoryID)
</div>
<div class="span3 offset1">
<label>Sub Category</label>
#Html.DropDownList("pjt_SubCat_ID", String.Empty)
<br />
#Html.ValidationMessageFor(model => model.SubCategoryID)
</div>
Can someone advise me what is going wrong here?
The problem is that the engine is trying to get the SelectList from the viewbag and it cannot find it. I am guessing that you want the Dropdown to display the items you have stored in the viewbag under "pjt_SubCat_ID" but you are not adding that item to the viewbag anywhere in the code that you have listed in your question.
If that is supposed to be the data returned from the SubCategory() method, you will not find that data in the viewbag and you should have a javascript that calls this method on the click event of the original SelectList (category id one) and binds the returned data to the subcategory one.