There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'BranchQuickChange' - asp.net-mvc-4

I've been on this error for a while and the ienumerable object is blocking can someone pls help me the error is in the description.
HTML:
#model IEnumerable<DatabaseDAL.Models.WAGTripHdr>
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$("select#BranchQuickChange").change(function () {
var branchName = $("select#BranchQuickChange option:selected").text();
alert(branchName);
window.location.href = '#Url.Action("QuickBranchChange", "TripSheets")?branchName=' + branchName;
});
</script>
<div class="row-fluid">
<div class="span4" style="margin-top: 15px">
#if (User.IsInRole("Administrator") || User.IsInRole("SuperUser"))
{
<strong>Quick Switch</strong> #Html.DropDownList("BranchQuickChange",ViewBag.CompanyList as SelectList)
}
</div>
Controller:
{
List<WAGBranch> listWagBranch = WAGBranchRepository.GetAllBranches(CompanyEnum.WAG).OrderBy(i => i.BRName).ToList();
List<string> listCompany = new List<string>();
foreach (WAGBranch branch in listWagBranch)
{
listCompany.Add(branch.BRName); // + " - " + branch.Branch);
}
//listCompany.Insert(0, "WAG HEAD OFFICE - WAG");
if ((string)selected == "") selected = null;
ViewBag.CompanyList = new SelectList(listCompany, selected);
}
Model:
[TableNameAttribute("WAGTripHdr")]
public class WAGTripHdr : SQLSelectUpdateInsertHelper
{
public string DebName { get; set; }
}
Waiting for some advices.

That error usually occurs when the collection passed to DropDownListFor is null. As a fallback, the helper tries to find the options in the ViewBag under a member named after the property, i.e. ViewBag.BranchQuickChange. When it fails to find anything usable there, as well, it gives up and you get the exception you reference.
That said, it appears you are in fact setting ViewBag.CompanyList in your action. Additionally, it is being set to a SelectList instance, so casting it back to SelectList in the view as you're doing should materialize the value. The only thing I can think of is that perhaps a different action than the one you've posted here is being loaded. In particular, if you have GET and POST versions of this action, make sure that both set ViewBag.CompanyList. It's possible you only added that line to one and not the other.

Related

Select dropdown value after post

I was hoping for some guidance on an issue I am having with preserving the value in a dropdownlist after post (razor)
I have a simple page:
#model testContingency.Models.ListByWardDD
#{
ViewBag.Title = "TestDropDowns";
}
<h2>TestDropDowns</h2>
<div>
#Html.DropDownList("HospModel", Model.Hospital, new { #onchange = "ChangeHospital(this.value)" })
#Html.DropDownList("WardModel", Model.Wards)
<script type="text/javascript">
function ChangeHospital(val) {
window.location.href = "/PatientListByWardDD/TestDropDowns?hospID=" + val;
}
</script>
</div>
here's the controller
public ActionResult TestDropDowns(int? hospID)
{
PASInpatientRepository pasRepo = new PASInpatientRepository();
var returnModel = new ListByWardDD();
var HospitalData = pasRepo.GetPatientHospitalsEnum();
returnModel.Hospital = pasRepo.GetHopspitalListItems(HospitalData);
var WardData = pasRepo .GetPatientWardsEnum(hospID);
returnModel.Wards = pasRepo.GetWardListItems(WardData);
ViewBag.HospSearch = hospID;
return View(returnModel);
}
In the controller PASInpatientRepository() communicates with a cache database. It passes back public IEnumerable < SelectListItem > GetHopspitalListItems. It calls stored procedures written within a cache database (same as sql stored procedures in essence). This is all working fine in its own crude way.
The issue I am having is that when I select the dropdownlist #Html.DropDownList("HospModel", Model.Hospital, new { #onchange = "ChangeHospital(this.value)" }) and the controller is called to refresh the Wards dropdown, I want to preserve the value I have selected in the hospital dropdown. I have tried a few different ways, but I admit, I'm a bit stuck. Most examples I found are for strongly typed.
As I mentioned, I'm new to MVC, but any advice on how to solve this issue, or suggestions on improving my code are greatly appreciated.
So I'm not sure what the Hospital property looks like but I'll make the assumption that each one has a unique ID.
Furthermore to bind the posted data to the view model you'll need to use forms in your view. To create the drop down list use the DropDownListFor-Helper. This way the data will be bound back to your Model after submitting the form.
So your view could look something like this
#model testContingency.Models.ListByWardDD
#{
ViewBag.Title = "TestDropDowns";
}
<h2>TestDropDowns</h2>
<div>
#using (Html.BeginForm("TestDropDowns", "YourController", FormMethod.Post))
{
#Html.DropDownListFor(x => x.HospitalID, Model.Hospital)
#Html.DropDownListFor(x => x.WardID, Model.Wards)
<input type="submit" value="send" />
}
</div>
Your ViewModel testContigency.Models.ListByWardDD must have at least the following properties
public class ListByWardDD {
public int HostpitalID { get;set; }
// the value of the SelectListItem-objects should be the hospital ID
public IEnumerable<SelectListItem> Hospital { get;set; }
public int WardID { get;set; }
// the value of the SelectListItem-objects should be the ward ID
public IEnumerable<SelectListItem> Wards { get;set; }
}
Once you post the form (for simplicity I added a button to send the form and left the javascript part out) the method TestDropDowns of your controller (which you need to fill in the BeginForm-Helper) will be called. That method expects expects an object of type ListByWardDD as a parameter and the framework will automatically populate the values for you.
[HttpPost]
public ActionResult TestDropDowns(ListByWardDD viewModel) {
// your code here, viewModel.HospitalID should contain the selected value
}
Note: After submitting the form the properties Hospital and Wards will be empty. If you need to display the form again, you need to repopulate those properties. Otherwise your dropdown lists are empty.
I tried my best to post valid code but I did not compile or test it.

How update view depending on user selection on Asp.Net core

I want to be able to display a form which changes depending on the value of a select on Dot.Net Core. I've seen many things like dynamic forms, View Components, razor and partials and also there is a lot of info out there but very confusing. Any info about the proper way to do what I want would be very appreciated.
I Have Categories>SubCategories>>Products
An order can be for one Category>>SubCategory only. So I want to display a select and depending on what category the user selects for the new Order, the products that I have to display. So I dont want to pick the user selection and go back to the controller and back to the view again and so on. I want to be able to dynamically display data according to the user selection.
Here an extract of the code just to briefly figure out what Im doing..I am not pasting the classes like Products,etc..
public class OrderCreateViewModel
{
public IEnumerable<Category> Categories { get; set; }
public IEnumerable<Branch> Branches { get; set; }
public int BranchId { get; set; }
public int CategoryId { get; set; }
}
Controller :
[HttpGet]
public IActionResult Create()
{
//Create vm
IEnumerable<Branch> branchList = _branchDataService.GetAll();
IEnumerable<Category> categoryList = _categoryDataService.GetAll();
OrderCreateViewModel vm = new OrderCreateViewModel
{
Categories = categoryList,
Branches = branchList
};
return View(vm);
}
View:
#model OrderCreateViewModel
<p>Create New Order </p>
<form asp-controller="Order" asp-action="Create" method="post">
<div class="form-group">
<label >Select Category</label>
<select class="form-control col-md-2" asp-for="CategoryId"
asp-items="#(new SelectList(Model.Categories ,"CategoryId","Name"))">
</select>
</div>
<div class="form-group">
<label>Select Branch</label>
<select class="form-control col-md-2" asp-for="BranchId"
asp-items="#(new SelectList(Model.Branches,"BranchId","Name"))">
</select>
</div>
<div >
<input type="submit" value="Save" />
</div>
</form>
Im just filling the select on the viewside and depending on what the user picks, the products I want to display. I am not passing the product list yet because I don't know where the "filter" for that particular Category takes place.
Hope you understand the idea of what i need :)
You've got two options here:
# 1 Use a Partial View And AJAX to get your data
Go have a look at the link below, it describes exactly what you want to achieve.
Populating Dropdown using partial view
# 2 Use Javascript to populate your second select:
First off you need to persist your data when the page loads
At the start of your view, add this:
#{
<text>
<script>
var data = "#Newtonsoft.Json.JsonConvert.SerializeObject(Model)";
</script>
</text>
}
Next use your on change event on the branch selector:
At the bottom of your view, do the following in the page ready event:
<script>
(function ()
{
var sltBranch = document.getElementsByName("BranchId")[0];
var sltCat = document.getElementsByName("CategoryId")[0]
sltCat.onchange = function () {
var dataAsObj = JSON.parse(data);
var branches = "";
for (i = 0; i < dataAsObj.Branches.length; i++)
{
if (dataAsObj.Branches[i].CategoryId == sltCat.value)
{
branches += "<option value='" + dataAsObj.Branches[i].BranchId + "'>" + dataAsObj.Branches[i].BranchName + "</option>"; //Whatever The branch name may be
}
}
sltBranch.innerHTML = branches;
}
}
)(document, window);
</script>
I would however advise you to follow option 1 as it is a lot more future proof strategy. This would mean that you need to change your view model etc, but if you plan on making extensive use of this strategy you need to make it more robust with something like option 1.
Good luck anyhow - happy coding.

can't pass multiple parameters using mvc4 html.beginform(...)

In my mvc4 application i want to use html.beginform() to pass multiple parameters to an actionResult on the same controller.
I do it like this:
view:
<div>
#using (Html.BeginForm("AddNote", "Lead",FormMethod.Post, null))
{
#Html.Hidden("leadID",#Model.ID)
<input type="text" name="noteBody" />
<input type="submit" class="mainButton" value="Add New!"/>
}
</div>
Controller (LeadController):
[HttpPost]
ActionResult AddNote(int leadID, string noteBody)
{
Note note = new Note();
note.DateModified = DateTime.Now;
note.Title = "No Title";
note.Body = noteBody;
Lead lead = unitOfWork.LeadRepository.GetById(leadID);
lead.Notes.Add(note);
unitOfWork.Save();
return RedirectToAction("Details", new { id = leadID });
}
when i press the submit button i get an exception:
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Lead/AddNote
this is the place to say that i have tried it withput parameters and it worked just fine.
I've also tried to pass the "leadID" parameter inside the form declaration (new {leadID = #Model.ID}).
Any idea what am i doing wrong ?
Just add the 'public' modifier to your action and it will do the magic.
The AddNote method should be public. Use the public keyword and it will work.
Add the HTTPPOST attribute , like this
[HttpPost]
ActionResult AddNote(int leadID, string noteBody)
{
Note note = new Note();
note.DateModified = DateTime.Now;
note.Title = "No Title";
note.Body = noteBody;
Lead lead = unitOfWork.LeadRepository.GetById(leadID);
lead.Notes.Add(note);
unitOfWork.Save();
return RedirectToAction("Details", new { id = leadID });
}
Perhaps it helps you

ASP.NET MVC How to Use two Actionresults with Html.BeginForm?

I'm trying to do the same as this ASP.NET MVC Using two inputs with Html.BeginForm question describes but with enough difference that I don't really know hwo to apply it on my project:
I have a view that has 3 dropdownlists(profilelist, connected salarylist & not connected salarylist)
Looks like this:
<div class="row bgwhite">
#using (Html.BeginForm("GetConnectedSalaries", "KumaAdmin", FormMethod.Get, new { Id = "ProfileListForm" }))
{
<div class="four columns list list1">
#Html.DropDownList("Profiles", (SelectList) ViewBag.Profiles, "--Välj profilgrupp--",
new
{
//onchange = "$('#ProfileListForm')[0].submit();"
// Submits everytime a new element in the list is chosen
onchange = "document.getElementById('ProfileListForm').submit();"
})
</div>
}
#using (Html.BeginForm("Index", "KumaAdmin", FormMethod.Get, new { Id = "SalaryListForm" }))
{
<div class="four columns list list2" style="margin-top:-19px;">
#Html.DropDownList("Salaries", (SelectList) ViewBag.Salaries, "--Kopplade LöneGrupper--")
</div>
}
#using (Html.BeginForm("GetNOTConnectedSalaries", "KumaAdmin", FormMethod.Get, new { Id = "NotConSalaryListForm" }))
{
<div class="four columns list list2" style="margin-top:-19px;">
#Html.DropDownList("Salaries", (SelectList)ViewBag.NotConSalaries, "--Ej Kopplade LöneGrupper--")
<input style="float: left;" type="submit" value="Knyt" />
</div>
}
</div>
as you can see above when i change an element i the profile list i have script code that submits the form and calls the following actionresult that populates my "connected salarylist".
[HttpGet]
public ActionResult GetConnectedSalaries(int Profiles = -1)
{
Model.SalaryGroups = AdminManager.GetConnectedSalaries(Profiles);
ViewBag.Salaries = new SelectList(Model.SalaryGroups, "Id", "SalaryName", "Description");
return (Index());
}
What I wan't to do:
When I chose a element in the profilelist i would like to call 2 actionresults, the one that i have shown above AND a second one that will populare my third list that will contain "not connected salaries".
Second Actionresult:
public ActionResult GetNOTConnectedSalaries(int Profiles = -1)
{
Model.SalaryGroups = AdminManager.GetNOTConnectedSalaries(Profiles);
ViewBag.NotConSalaries = new SelectList(Model.NotConSalaryGroups, "Id", "SalaryName", "Description");
return (Index());
}
I don't want to do this with AJAX/JSON, strictly MVC.
I read the question that i linked above but did not know how to apply it to my project or if it is even possible to do the same.
If more info is needed ask and i will do my best to provide it.
Thank you!
I was so sure that the best way to do this was to have two actionresults that i was totaly blinded to the soloution that i could call both my db methods from the same actionresult and populate both of the lists.
Simple soloution:
[HttpGet]
public ActionResult GetSalaries(int Profiles = -1)
{
Model.SalaryGroups = AdminManager.GetConnectedSalaries(Profiles);
ViewBag.Salaries = new SelectList(Model.SalaryGroups, "Id", "SalaryName", "Description");
Model.NotConSalaryGroups = AdminManager.GetNOTConnectedSalaries(Profiles);
ViewBag.NotConSalaries = new SelectList(Model.NotConSalaryGroups, "Id", "SalaryName", "Description");
return (Index());
}
Sorry if I wasted your time:( but hopefully this will help others that attempt the same.
However if there is a way to do this in two actionresults then I will leave the question as open, would be interesting to see how it is done.

Duplicates on runtime MVC4 Entity Framework

I get this strange "error". When i run my app (edit action i.e update) i get duplicate values stored in my dB. If i use the debugger, step by step, its working (no duplicates)...
It's a Many-to-Many Relationship so don't bother the Courses NULL value in the images, just trying to figure things out...
All Help is appreciated!
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
var course = db.Courses
.Where(c => c.Id == model.CourseId)
.Single();
if (ModelState.IsValid)
{
course.Name = model.CourseName;
course.Description = model.CourseDescription;
course.Students = model.Students;
if(course.Id != 0) {
db.Entry(course).State = System.Data.EntityState.Modified;
}
else {
db.Courses.Add(course);
}
db.SaveChanges();
return RedirectToAction("Index");
}
//modelstate not valid, display form
return View(model);
}
I get my viewModel back. All good.
My Old values from dB. I want to update this data. So everything is still good...
My old values are updated to my new Values. Great!
Ok everything works great IF I step with debugger like this. But if i run the app i will get duplicates.... Anyone?
New content:
My Edit-view
#model ValueInjecter.Web.Models.CourseStudentViewModel
#{
ViewBag.Title = "Edit"; }
Edit Course
#using (Html.BeginForm()) {
#Html.HiddenFor(c => Model.CourseId)
#Html.LabelFor(c => Model.CourseName)
#Html.EditorFor(c => Model.CourseName)
#Html.LabelFor(c => Model.CourseDescription)
#Html.EditorFor(c => Model.CourseDescription)
</div>
<hr />
<h2>Students</h2>
<div class="editor-field">
#for (int i = 0; i < Model.Students.Count(); i++)
{
<div style="border: dotted 1px; padding: 5px; margin: 10px;">
#Html.HiddenFor(s => s.Students[i].Id)
#Html.LabelFor(s => s.Students[i].Name[i + 1])
#Html.EditorFor(s => s.Students[i].Name)
</div>
}
</div>
<p>
Number of Students:
<b>#Html.DisplayFor(s => Model.StudentCount)</b>
</p>
<hr />
<p>
<input type="submit" value="Save" />
</p> }
It probably works in the debugger because by inspecting course.Students collection in a property watch window you trigger actually a second database query (after the query that loads the course) due to lazy loading of the Students collection. (Your Course.Students collection is most likely declared as virtual.) If you run without debugger no lazy loading occurs and course.Students stays empty.
You can force that the course.Students collection is always loaded by using eager loading instead of lazy loading (which also saves the second database roundtrip):
var course = db.Courses
.Include(c => c.Students)
.Where(c => c.Id == model.CourseId)
.Single();
Honestly I have no clue why your code works correctly with the loaded collection (in the debugger) and why it works at all. Assigning a complete detached collection like this: course.Students = model.Students, and then just setting the state of the parent to Modified is normally not enough to update a child collection.
But I see "ValueInjecter" in your screenshots. Maybe there is some automatic mapping magic happening that does (accidentally?) the right thing to get a working update.
Ok I finally figured out the solution of my problem. Of course much easier than first thought.
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
if (ModelState.IsValid)
{
var course = db.Courses.Find(model.CourseId);
course.Name = model.CourseName;
course.Description = model.CourseDescription;
if(model.Students != null)
{
foreach (var item in model.Students)
{
db.Entry(item).State = System.Data.EntityState.Modified;
}
}
if(course.Id != 0) {
db.Entry(course).State = System.Data.EntityState.Modified;
}
else {
db.Courses.Add(course);
}
db.SaveChanges();
return RedirectToAction("Index");
}
//modelstate not valid, display form
return View(model);
}
Still using the view ive pasted above.