How can I get selected Item of my DropDownList?
#using (Html.BeginForm("Doctors", "User", FormMethod.Get))
{
<input name="pageNumber" type="hidden" value="1" /><text>Hospital:</text><br />
#Html.DropDownList("HospitalId", (IEnumerable<SelectListItem>)ViewBag.HospitalList, new { style = "width:90%" }) <br />
<button type="submit" class="btn btn-mini"> Search </button>
}
This question isn't very clear as to when / where you want to get your drop down list item.
I will assume you want to pick it up in the controller for now. What you will need to do is make sure its included in your post to the controller and is using the correct name to be picked up when the form is read server side.
Here is an example:
#Html.DropDownList("SubworkType", "Select Work Item", new { #Id = "SubworkId" , #Name = "SubworkId" })
If You are looking to grab the selected value on the view side you could do something like this:
var workerType = $("#WorkerTypeFilter option:selected").val()
It should simply be accessible as a parameter in your Controller's action method.
public ActionResult Doctors(string pageNumber, string HospitalId)
{
// make use of HospitalId
...
}
I would prefer to avoid dynamic variables like ViewBag/ViewData and stick with strong types.
Use a ViewModel
public class AssignDoctorViewModel
{
//Other Properties also
public IEnumerable<SelectListItem> Hospitals { set;get;}
public int SelectedHospital { set;get;}
}
And in my GET Action method, I would return this with the filled properties
public ActionResult AssignDoctor
{
var vm=new AssignDoctorViewModel();
vm.Hospitals= new[]
{
new SelectListItem { Value = "1", Text = "Florance" },
new SelectListItem { Value = "2", Text = "Spark" },
new SelectListItem { Value = "3", Text = "Henry Ford" },
};
// can replace the above line with loading data from Data access layer.
return View(vm);
}
Now in your view which is strongly typed to our ViewModel class
#model AssignDoctorViewModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedHospital, Model.Hospitals, "Select..")
<input type="submit" value="save" />
}
Now in your HTTPPOST Action method, you can get the Selected value by accessing the SelectedHospital Property
public ActionResult AssignDoctor(AssignDoctorViewModel model)
{
//check for model.SelectedHospital value
}
Shyju's answer is good, I just want to expand on what Shyju has said with some pointers.
Use a view model per view with just the data that you need, anything not used please remove.
Your domain model could look like this:
public class Hospital
{
public int Id { get; set; }
public string Name { get; set; }
}
Your view model could look like this:
public class DoctorHospitalViewModel
{
public int HospitalId { get; set; }
public IEnumerable<Hospital> Hospitals { get; set; }
}
Your view could look like this (I put the dropdown in a table for display purposes):
<table>
<tr>
<td class="edit-label">Hospital <span class="required">**</span></td>
<td>
#Html.DropDownListFor(
x => x.HospitalId,
new SelectList(Model.Hospital, "Id", "Name", Model.HospitalId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.HospitalId)
</td>
</tr>
</table>
Your controller might look like this and assuming you are wanting to use this dropdown in a create view:
public class HospitalController : Controller
{
private readonly IHospitalRepository hospitalRepository;
public HospitalController(IHospitalRepository hospitalRepository)
{
// Check that hospitalRepository is not null
this.hospitalRepository = hospitalRepository;
}
public ActionResult Create()
{
DoctorHospitalViewModel viewModel = new DoctorHospitalViewModel
{
Hospitals = hospitalRepository.GetAll()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(DoctorHospitalViewModel viewModel)
{
// Check that viewModel is not null
if (!ModelState.IsValid)
{
viewModel.Hospitals = hospitalRepository.GetAll();
return View(viewModel);
}
// Do what ever needs to be done
// You can get the selected hospital id like this
int selectedHospitalId = viewModel.HospitalId;
return RedirectToAction("List");
}
}
I hope this helps.
Related
Not understanding what I am overseeing here ...
I have a Model which I render in a View.
This is the SubscriptionViewModel:
public Subscription Subscription { get; set; }
public DayOfWeek DayOfWeek { get; set; }
public List<DateTime> SomeDates { get; set; }
In the View I have populated a table with data from the SubscriptionViewModel.
In each table row there is an If/else statement, where in each part I placed a Form so that the data can be posted back to the SubscriptionController, this is a pseudo example:
if (condition)
{
using (Html.BeginForm("Subscribe", "Subscription", FormMethod.Post))
{
#Html.ActionLink("text", "Subscribe", new { #date = item }, new { #class = "btn btn-warning btn-radius" })
}
}
else
{
using (Html.BeginForm("UnSubscribe", "Subscription", FormMethod.Post))
{
#Html.ActionLink("text", "UnSubscribe", new { #date = item }, new { #class = "btn btn-danger btn-radius" })
}
}
This is the SubscriptionContoller method being triggered:
[AllowAnonymous]
public ActionResult Subscribe(SubscriptionViewModel model, string date)
{
return View();
}
The POST is triggered and my Model is not NULL, the date parameter also has the correct value, the only thing which is lost is the parameters from Subscription Entity from my SubscriptionViewModel. They are not NULL but they just don't have their initial values when coming to the View initially...
No clue what I am overseeing, I tried using TempData.Keep() into the View (which I never needed to do before) but that doesn't work either.
Any suggestion is welcome!
Thank you!
This answer assumes you don't want the values for the Subscription to come from the form but rather stay as they were when the values are originally sent to the view which sounds like what you are after.
You need to include the values for the subscription in the form using hidden fields (see example 1). Alternatively you will need to populate the subscription in your post method in the same way that it is in your get method (see example 2).
Here are 2 simple examples demonstrating what I mean
Suppose this is your subscription class
public class Subscription
{
public int Id { get; set; }
public string Name { get; set; }
}
Example 1
The HiddenField way
The controller
public class SubscriptionController : Controller
{
[AllowAnonymous]
public ActionResult Subscribe()
{
var viewModel = new SubscriptionViewModel
{
Subscription = GetSubscription()
};
return View(viewModel);
}
[AllowAnonymous]
[HttpPost]
public ActionResult Subscribe(SubscriptionViewModel model, string date)
{
return View();
}
private Subscription GetSubscription()
{
return new Subscription
{
Id = 1,
Name = "My Subscription"
};
}
}
The view
#model {The namespace}.SubscriptionViewModel
#using (Html.BeginForm("Subscribe", "Subscription", FormMethod.Post))
{
//Other fields
#Html.HiddenFor(x => x.Subscription.Id)
#Html.HiddenFor(x => x.Subscription.Name)
<input type="submit" value="submit" />
}
Example 2
The get back in the controller way
The controller
public class SubscriptionController : Controller
{
[AllowAnonymous]
public ActionResult Subscribe()
{
var viewModel = new SubscriptionViewModel
{
Subscription = GetSubscription()
};
return View(viewModel);
}
[AllowAnonymous]
[HttpPost]
public ActionResult Subscribe(SubscriptionViewModel model, string date)
{
model.Subscription = GetSubscription();
return View();
}
private Subscription GetSubscription()
{
return new Subscription
{
Id = 1,
Name = "My Subscription"
};
}
}
The view
#model {The namespace}.SubscriptionViewModel
#using (Html.BeginForm("Subscribe", "Subscription", FormMethod.Post))
{
//Other fields
<input type="submit" value="submit" />
}
Using MVC4 am wanting to implement functionality which will allow a user to add new items to the database.
I've managed to achieve this adding items to a single table, but now I need to display data from multiple tables, then populate the added / selected data to those tables.
I have these 3 tables
Threats
ID
Description
ThreatHasSecurityEvent
ThreatID
SecurityEventID
SecrutiyEvents
ID
Description
And here's my code so far:
ViewModel
public class ThreatWithSecurityEvents
{
public Threat Threat { get; set; }
public SecurityEvent SecurityEvent { get; set; }
public List<int> SecurityEventIds { get; set; }
public ThreatWithSecurityEvents()
{
SecurityEventIds = new List<int>();
}
}
Get Controller
[HttpGet]
public ActionResult AddNewThreat()
{
ThreatWithSecurityEvents ViewModel = new ThreatWithSecurityEvents();
var SecurityEvents = _DBContext.SecurityEvents.Select(x => new SelectListItem()
{
Text = x.Description,
Value = x.ID.ToString()
});
ViewBag.SecurityEventDropdown = SecurityEvents;
return View(ViewModel);
}
View
#model RiskAssesmentApplication.Models.ThreatWithSecurityEvents
#{
ViewBag.Title = "AddNewThreat";
//Layout = "~/Views/Shared/MasterLayout.cshtml";
}
<div style="font-family: Calibri">
<h2>AddNewThreat</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Threat</legend>
#using (Html.BeginForm("Add New Threat", "Threats"))
{
Html.HiddenFor(model => model.SecurityEventIds);
<div class="editor-label">
#Html.LabelFor(model => #Model.Threat.Description, "Threat Description")
</div>
<div class="editor-field">
#Html.EditorFor(model => #Model.Threat.Description)
#Html.ValidationMessageFor(model => #Model.Threat.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => #Model.SecurityEvent.Description, "Associated Security Event")
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.SecurityEventIds, ViewBag.SecurityEventDropdown as IEnumerable<SelectListItem>)
</div>
<p>
<input type="submit" value="Add New" />
</p>
}
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</div>
Am unsure how to implement the Post Action Method and a Save Method in the repository.
Previously I could inject a new Threat Object and send it to the edit view doing something like:
Previous Get Method - AddNewThreat
[HttpGet]
public ActionResult AddNewThreat()
{
return View("EditThreat", new Threat());
}
and I would then use the EditThreat Action Method to post back
Previous Post Action - AddNewThreat
[HttpPost]
public ActionResult EditThreat(Threat Threat)
{
if (ModelState.IsValid)
{
repository.SaveThreat(Threat);
TempData["message"] = string.Format("{0} new description has been saved", Threat.Description);
return RedirectToAction("GetThreat", new { ThreatID = Threat.ID });
}
else
{
// something is incorrect!
return View(Threat);
}
}
Previous Save Method - SaveThreat From Repository
public void SaveThreat(Threat Threat)
{
if (Threat.ID == 0)
{
_context.Threats.Add(Threat);
}
else
{
Threat dbEntry = _context.Threats.Find(Threat.ID);
if (dbEntry != null)
{
dbEntry.Description = Threat.Description;
}
}
_context.SaveChanges();
}
That's as far as I have got so far.
I want the user to be able to enter a new threat description and then select a security event or multiple events from a drop down list which will be associated with the new threat.
I realize am going to have to change the post back action method in the controller and the Save method in my repository, but I cant work out how to get both the new Threat description and the existing security events saved back to the database. I've had a search but as of yet haven't found / understood anything.
Any advice/help would be great.
Thanks
You view model should be
public class NewThreatVM
{
public string Description { get; set; } // add validation attributes as required
public List<int> SelectedSecurityEvents { get; set; }
public SelectList SecurityEventList { get; set; } // or IEnumerable<SelectListItem>
}
Side note: The Threat.ID property is not required in a create view, however if your want to use this for editing an existing Threat as well, add property int? ID and use if (model.ID.HasValue) in the POST method to determine if its a new or existing Threat
and the simplified view
#model yourAssembly.NewThreatVM
#Html.BeginForm())
{
#Html.TextBoxFor(m => m.Description)
#Html.ListBoxFor(m => m.SelectedSecurityEvents, Model.SecurityEventList)
<input type="Submit" value="Create" />
}
Side notes: Your view should not include a hidden input for the Security Event ID's (you cannot bind an input to a complex object or collection)
then the controller
public ActionResult Create()
{
NewThreatVM model = new NewThreatVM model();
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(NewThreatVM model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
// Initialize new data model and map properties from view model
Threat threat = new Threat() { Description = model.Description };
// Save it (which will set its ID property)
_context.Threats.Add(Threat);
_context.SaveChanges();
// Save each selected security event
foreach (int selectedEvent in model.SelectedSecurityEvents)
{
ThreatHasSecurityEvent securityEvent = new ThreatHasSecurityEvent()
{
ThreatID = threat.ID,
SecurityEventID = selectedEvent
};
_context.ThreatHasSecurityEvents.Add(securityEvent);
}
_context.SaveChanges();
return RedirectToAction("GetThreat", new { ThreatID = threat.ID });
}
private void ConfigureViewModel(NewThreatVM model)
{
var securityEvents = _context.SecurityEvents;
model.SecurityEventList = new SelectList(securityEvents, "ID", "Description");
}
I believe the easiest way to achieve this, is "dividing" your form into separated steps.
You have2 entities: Threats, SecurityEventID
Threat has a collection of SecurityEvents
Create a form to add/edit Threats (url: Threats/Add | Threats/Edit/ThreatId)
Create a form to add/delete Events of an existing Threat (url: Threats/AddEvent/ThreatIdHere
Use custom ViewModels instead of the original class to send data to controller. Examples:
public class AddThreatViewModel
{
public string Description { get; set; }
//since it's a add view model, we dont need a ThreatId here
}
[HttpPost]
public ActionResult AddThreat(AddThreatViewModel model)
{
//convert the view model to Threat, add to database
}
public class AddThreatEvent
{
public int ThreatId { get; set; }
public int SecrutiyEventId { get; set; }
}
[HttpPost]
public ActionResult AddThreatEvent(AddThreatEventmodel)
{
//add threat event into existing threat
}
I have dropdownlist, which I have filled from database. Now I need to get the selected value in Controller do some manipulation. But not getting the idea. Code which I have tried.
Model
public class MobileViewModel
{
public List<tbInsertMobile> MobileList;
public SelectList Vendor { get; set; }
}
Controller
public ActionResult ShowAllMobileDetails()
{
MobileViewModel MV = new MobileViewModel();
MV.MobileList = db.Usp_InsertUpdateDelete(null, "", "", null, "", 4, MergeOption.AppendOnly).ToList();
MV.Vendor = new SelectList(db.Usp_VendorList(), "VendorId", "VendorName");
return View(MV);
}
[HttpPost]
public ActionResult ShowAllMobileDetails(MobileViewModel MV)
{
string strDDLValue = ""; // Here i need the dropdownlist value
return View(MV);
}
View
<table>
<tr>
<td>Mobile Manufacured</td>
<td>#Html.DropDownList("ddlVendor", Model.Vendor, "Select Manufacurer") </td>
</tr>
<tr>
<td>
</td>
<td>
<input id="Submit1" type="submit" value="search" />
</td>
</tr>
</table>
1st Approach (via Request or FormCollection):
You can read it from Request using Request.Form , your dropdown name is ddlVendor so pass ddlVendor key in the formCollection to get its value that is posted by form:
string strDDLValue = Request.Form["ddlVendor"].ToString();
or Use FormCollection:
[HttpPost]
public ActionResult ShowAllMobileDetails(MobileViewModel MV,FormCollection form)
{
string strDDLValue = form["ddlVendor"].ToString();
return View(MV);
}
2nd Approach (Via Model):
If you want with Model binding then add a property in Model:
public class MobileViewModel
{
public List<tbInsertMobile> MobileList;
public SelectList Vendor { get; set; }
public string SelectedVendor {get;set;}
}
and in View:
#Html.DropDownListFor(m=>m.SelectedVendor , Model.Vendor, "Select Manufacurer")
and in Action:
[HttpPost]
public ActionResult ShowAllMobileDetails(MobileViewModel MV)
{
string SelectedValue = MV.SelectedVendor;
return View(MV);
}
UPDATE:
If you want to post the text of selected item as well, you have to add a hidden field and on drop down selection change set selected item text in the hidden field:
public class MobileViewModel
{
public List<tbInsertMobile> MobileList;
public SelectList Vendor { get; set; }
public string SelectVendor {get;set;}
public string SelectedvendorText { get; set; }
}
use jquery to set hidden field:
<script type="text/javascript">
$(function(){
$("#SelectedVendor").on("change", function {
$("#SelectedvendorText").val($(this).text());
});
});
</script>
#Html.DropDownListFor(m=>m.SelectedVendor , Model.Vendor, "Select Manufacurer")
#Html.HiddenFor(m=>m.SelectedvendorText)
Model
Very basic model with Gender field. GetGenderSelectItems() returns select items needed to populate DropDownList.
public enum Gender
{
Male, Female
}
public class MyModel
{
public Gender Gender { get; set; }
public static IEnumerable<SelectListItem> GetGenderSelectItems()
{
yield return new SelectListItem { Text = "Male", Value = "Male" };
yield return new SelectListItem { Text = "Female", Value = "Female" };
}
}
View
Please make sure you wrapped your #Html.DropDownListFor in a form tag.
#model MyModel
#using (Html.BeginForm("MyController", "MyAction", FormMethod.Post)
{
#Html.DropDownListFor(m => m.Gender, MyModel.GetGenderSelectItems())
<input type="submit" value="Send" />
}
Controller
Your .cshtml Razor view name should be the same as controller action name and folder name should match controller name e.g Views\MyController\MyAction.cshtml.
public class MyController : Controller
{
public ActionResult MyAction()
{
// shows your form when you load the page
return View();
}
[HttpPost]
public ActionResult MyAction(MyModel model)
{
// the value is received in the controller.
var selectedGender = model.Gender;
return View(model);
}
}
Going further
Now let's make it strongly-typed and enum independent:
var genderSelectItems = Enum.GetValues(typeof(Gender))
.Cast<string>()
.Select(genderString => new SelectListItem
{
Text = genderString,
Value = genderString,
}).AsEnumerable();
MVC 5/6/Razor Pages
I think the best way is with strongly typed model, because Viewbags are being aboused too much already :)
MVC 5 example
Your Get Action
public async Task<ActionResult> Register()
{
var model = new RegistrationViewModel
{
Roles = GetRoles()
};
return View(model);
}
Your View Model
public class RegistrationViewModel
{
public string Name { get; set; }
public int? RoleId { get; set; }
public List<SelectListItem> Roles { get; set; }
}
Your View
<div class="form-group">
#Html.LabelFor(model => model.RoleId, htmlAttributes: new { #class = "col-form-label" })
<div class="col-form-txt">
#Html.DropDownListFor(model => model.RoleId, Model.Roles, "--Select Role--", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.RoleId, "", new { #class = "text-danger" })
</div>
</div>
Your Post Action
[HttpPost, ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegistrationViewModel model)
{
if (ModelState.IsValid)
{
var _roleId = model.RoleId,
MVC 6 It'll be a little different
Get Action
public async Task<ActionResult> Register()
{
var _roles = new List<SelectListItem>();
_roles.Add(new SelectListItem
{
Text = "Select",
Value = ""
});
foreach (var role in GetRoles())
{
_roles.Add(new SelectListItem
{
Text = z.Name,
Value = z.Id
});
}
var model = new RegistrationViewModel
{
Roles = _roles
};
return View(model);
}
Your View Model will be same as MVC 5
Your View will be like
<select asp-for="RoleId" asp-items="Model.Roles"></select>
Post will also be same
Razor Pages
Your Page Model
[BindProperty]
public int User User { get; set; } = 1;
public List<SelectListItem> Roles { get; set; }
public void OnGet()
{
Roles = new List<SelectListItem> {
new SelectListItem { Value = "1", Text = "X" },
new SelectListItem { Value = "2", Text = "Y" },
new SelectListItem { Value = "3", Text = "Z" },
};
}
<select asp-for="User" asp-items="Model.Roles">
<option value="">Select Role</option>
</select>
I hope it may help someone :)
If you want to use #Html.DropDownList , follow.
Controller:
var categoryList = context.Categories.Select(c => c.CategoryName).ToList();
ViewBag.CategoryList = categoryList;
View:
#Html.DropDownList("Category", new SelectList(ViewBag.CategoryList), "Choose Category", new { #class = "form-control" })
$("#Category").on("change", function () {
var q = $("#Category").val();
console.log("val = " + q);
});
If you're looking for something lightweight, I'd append a parameter to your action.
[HttpPost]
public ActionResult ShowAllMobileDetails(MobileViewModel MV, string ddlVendor)
{
string strDDLValue = ddlVendor; // Of course, this becomes silly.
return View(MV);
}
What's happening in your code now, is you're passing the first string argument of "ddlVendor" to Html.DropDownList, and that's telling the MVC framework to create a <select> element with a name of "ddlVendor." When the user submits the form client-side, then, it will contain a value to that key.
When MVC tries to parse that request into MV, it's going to look for MobileList and Vendor and not find either, so it's not going to be populated. By adding this parameter, or using FormCollection as another answer has suggested, you're asking MVC to specifically look for a form element with that name, so it should then populate the parameter value with the posted value.
Use SelectList to bind #HtmlDropdownListFor and specify selectedValue parameter in it.
http://msdn.microsoft.com/en-us/library/dd492553(v=vs.108).aspx
Example : you can do like this for getting venderid
#Html.DropDownListFor(m => m.VendorId,Model.Vendor)
public class MobileViewModel
{
public List<tbInsertMobile> MobileList;
public SelectList Vendor { get; set; }
public int VenderID{get;set;}
}
[HttpPost]
public ActionResult Action(MobileViewModel model)
{
var Id = model.VenderID;
I was having the same issue in asp.NET razor C#
I had a ComboBox filled with titles from an EventMessage, and I wanted to show the Content of this message with its selected value to show it in a label or TextField or any other Control...
My ComboBox was filled like this:
#Html.DropDownList("EventBerichten", new SelectList(ViewBag.EventBerichten, "EventBerichtenID", "Titel"), new { #class = "form-control", onchange = "$(this.form).submit();" })
In my EventController I had a function to go to the page, in which I wanted to show my ComboBox (which is of a different model type, so I had to use a partial view)?
The function to get from index to page in which to load the partial view:
public ActionResult EventDetail(int id)
{
Event eventOrg = db.Event.Include(s => s.Files).SingleOrDefault(s => s.EventID == id);
// EventOrg eventOrg = db.EventOrgs.Find(id);
if (eventOrg == null)
{
return HttpNotFound();
}
ViewBag.EventBerichten = GetEventBerichtenLijst(id);
ViewBag.eventOrg = eventOrg;
return View(eventOrg);
}
The function for the partial view is here:
public PartialViewResult InhoudByIdPartial(int id)
{
return PartialView(
db.EventBericht.Where(r => r.EventID == id).ToList());
}
The function to fill EventBerichten:
public List<EventBerichten> GetEventBerichtenLijst(int id)
{
var eventLijst = db.EventBericht.ToList();
var berLijst = new List<EventBerichten>();
foreach (var ber in eventLijst)
{
if (ber.EventID == id )
{
berLijst.Add(ber);
}
}
return berLijst;
}
The partialView Model looks like this:
#model IEnumerable<STUVF_back_end.Models.EventBerichten>
<table>
<tr>
<th>
EventID
</th>
<th>
Titel
</th>
<th>
Inhoud
</th>
<th>
BerichtDatum
</th>
<th>
BerichtTijd
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.EventID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Titel)
</td>
<td>
#Html.DisplayFor(modelItem => item.Inhoud)
</td>
<td>
#Html.DisplayFor(modelItem => item.BerichtDatum)
</td>
<td>
#Html.DisplayFor(modelItem => item.BerichtTijd)
</td>
</tr>
}
</table>
VIEUW: This is the script used to get my output in the view
<script type="text/javascript">
$(document).ready(function () {
$("#EventBerichten").change(function () {
$("#log").ajaxError(function (event, jqxhr, settings, exception) {
alert(exception);
});
var BerichtSelected = $("select option:selected").first().text();
$.get('#Url.Action("InhoudByIdPartial")',
{ EventBerichtID: BerichtSelected }, function (data) {
$("#target").html(data);
});
});
});
</script>
#{
Html.RenderAction("InhoudByIdPartial", Model.EventID);
}
<fieldset>
<legend>Berichten over dit Evenement</legend>
<div>
#Html.DropDownList("EventBerichten", new SelectList(ViewBag.EventBerichten, "EventBerichtenID", "Titel"), new { #class = "form-control", onchange = "$(this.form).submit();" })
</div>
<br />
<div id="target">
</div>
<div id="log">
</div>
</fieldset>
Thanks - this helped me to understand better ansd solve a problem I had.
The JQuery provided to get the text of selectedItem did NOT wwork for me
I changed it to
$(function () {
$("#SelectedVender").on("change", function () {
$("#SelectedvendorText").val($(**"#SelectedVender option:selected"**).text());
});
});
Simple solution not sure if this has been suggested or not. This also may not work for some things. That being said this is the simple solution below.
new SelectListItem { Value = "1", Text = "Waiting Invoices", Selected = true}
List<SelectListItem> InvoiceStatusDD = new List<SelectListItem>();
InvoiceStatusDD.Add(new SelectListItem { Value = "0", Text = "All Invoices" });
InvoiceStatusDD.Add(new SelectListItem { Value = "1", Text = "Waiting Invoices", Selected = true});
InvoiceStatusDD.Add(new SelectListItem { Value = "7", Text = "Client Approved Invoices" });
#Html.DropDownList("InvoiceStatus", InvoiceStatusDD)
You can also do something like this for a database driven select list. you will need to set selected in your controller
#Html.DropDownList("ApprovalProfile", (IEnumerable<SelectListItem>)ViewData["ApprovalProfiles"], "All Employees")
Something like this but better solutions exist this is just one method.
foreach (CountryModel item in CountryModel.GetCountryList())
{
if (item.CountryPhoneCode.Trim() != "974")
{
countries.Add(new SelectListItem { Text = item.CountryName + " +(" + item.CountryPhoneCode + ")", Value = item.CountryPhoneCode });
}
else {
countries.Add(new SelectListItem { Text = item.CountryName + " +(" + item.CountryPhoneCode + ")", Value = item.CountryPhoneCode,Selected=true });
}
}
First of all sorry for the super generic title but i have no idea how to ask this question properly.
I am a bit new to Asp net MVC 5 and i am having some issues with passing information from the Controller to the View. The problem is that in the View I need to have 2 search functions, one using a text (with a textbox) and another with listboxes, and I can t seem to get the two working at the same time (they work separately), I suspect it has something to do with my Viewmodel but I have no idea why this is happening.
this is my ViewModel:
public class ViewModel{
public IEnumerable<ABC> xyz { get; set; }
public List<SelectListItem> device { get; set; }
public List<SelectListItem> type { get; set; }
public SelectListItem selectedItem { set; get; }
//these are all the properties that ABC has
public int a { get; set; }
public string Name{ get; set; }
}
These are the controller actions
public ActionResult FillListBoxes()
{
ViewModel myViewModel = new ViewModel();
var tempObjects = db.ABC
//.Where(...)
.Select(v =>
new
{
v.Type,
v.device,
})
.ToList();
myViewModel.device = new List<SelectListItem>();
foreach (var device in tempObjects.Select(obj => obj.device).Distinct().ToList())
{
myViewModel.device.Add(new SelectListItem { Text = device, Value = device });
}
myViewModel.type = new List<SelectListItem>();
foreach (var type in tempObjects.Select(obj => obj.device).Distinct().ToList())
{
myViewModel.type.Add(new SelectListItem { Text = type, Value = type });
}
return View(myViewModel);
}
public ActionResult Search(string searchString)
{
ViewModel myViewModel = new ViewModel();
// FillListBoxes();
var tempObjects = db.ABC.ToList();
if (!String.IsNullOrEmpty(searchString))
{
myViewModel.abc = tempObjects.Where(m => m.Name.Contains(searchString));
return View(myViewModel);
}
else
{
myViewModel.abc = tempObjects;
return View(myViewModel);
}
}
And this is the View
#model project.Models.ViewModel
#{
ViewBag.Title = "Search";
}
#section Styles {
<link href="#Url.Content("~/Content/Search.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/chosen.css")" rel="stylesheet" type="text/css" />
}
#using (Html.BeginForm("Search", "ABC", FormMethod.Get))
{
<p>
Name: #Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" />
</p>
}
#using (Html.BeginForm("FillListBoxes", "ABC", FormMethod.Get))
{
<p>
#Html.DropDownListFor(model => model.selectedItem, Model.device, new { #class = "chosen", multiple = "multiple", style = "width: 350px;" })
</p>
<p>
#Html.DropDownListFor(model => model.selectedItem, Model.type, new { #class = "chosen", multiple = "multiple", style = "width: 350px;" })
</p>
<p>
<input type="submit" value="Filter" />
</p>
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.a)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
#foreach (var item in Model.abc) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.a)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
</tr>
}
</table>
The error i am getting now is that selectedItem should be a IEnumerable but even if i change it get a There is no ViewData item of type 'IEnumerable' that has the key 'selectedItem'. and before this I was facing a:
the model item passed into the dictionary is of type 'system.data.entity.infrastructure.dbquery 1[abc] but this dictionary requires a model item of type ViewModel this is when I changed the Search method in the controller to use the Viewmodel.
If I am missing anything please do say.
I apologize again for the super generic title.
#Edit Added the suggestions made by Stephen
#Edit 2 So here is a brief explanation on how this all works, the texbox is there so the user can filter the ABCs that are presented in that page (based solely on the name attribute). The listboxes are there so if the user can filter the presented ABCs through their type and/or device only.
I hope this clears some things up
There are numerous problems
Firstly, you view includes helpers to generate dropdownlists, for example
#Html.DropDownListFor(model => model.selectedItem, Model.device, ...)
but when you call the Search() method, you do not populate the SelectList's so Model.device is null and throws the exception
There is no ViewData item of type 'IEnumerable' that has the key 'selectedItem
Secondly, <select> elements (and all controls) bind to value types but you are trying to bind to typeof SelectListItem which is a complex object.
Thirdly you have 2 dropdownlist binding to the same property so even if you do change selectedItem to string, it would only ever bind the value of the selected device and the selected type would be ignored.
Finally, you have 2 separate forms so nothing stays in sync. If you post the first form, items would be filtered based on the name (the selected device is ignored) and conversely if you post the second form, the value of name is ignored.
Based on your current approach your view model would need to be
public class ViewModel
{
public IEnumerable<ABC> Items { get; set; }
public string NameFilter { get; set; }
public string DeviceFilter { get; set; }
public string TypeFilter { get; set; }
public SelectList DeviceList { get; set; }
public SelectList TypeList { get; set; }
}
Controller
public ActionResult Search()
{
ViewModel model = new ViewModel();
// populate properties including select lists
return View(model);
}
[HttPost]
public ActionResult Search(ViewModel model)
{
model.Items = // Get the filtered items based on the values of NameFilter, DeviceFilter and TypeFilter
model.DeviceList = // reassign both select lists
model.Typelist = ..
return view(model);
}
View
#model ViewModel
#using(Html.BeginForm())
{
#Html.TextBoxFor(m => m.NameFilter)
#Html.DropDownListFor(m => m.DeviceFilter, Model.DeviceList)
#Html.DropDownListFor(m => m.TypeFilter, Model.TypeList)
<input type="submit" value="Filter" />
}
<table class="table">
.....
<table>
However all this can be done better by using ajax to pass the filter values to a method that returns a partial view containing just the updated table, and replacing the DOM, or even better by rendering each table row with data-* attributes for the device and type values and then just using javascript/jquery to hide/show rows based on the filer values (no need to go back to the server)
Instead of using MultiSelectList you should use List:
public class ViewModel{
public IEnumerable<ABC> xyz { get; set; }
public List<SelectListItem> device { get; set; }
public List<SelectListItem> type { get; set; }
public SelectListItem selectedItem { set; get; }
//these are all the properties that ABC has
public int a { get; set; }
public string Name{ get; set; }
}
and
public ActionResult FillListBoxes()
{
ViewModel myViewModel = new ViewModel();
...
myViewModel.device = new List<SelectListItem>();
foreach (var device in tempObjects.Select(obj => obj.device).Distinct().ToList()) {
myViewModel.device.Add(new SelectListItem { Text = device, Value = device });
// das gleiche für myViewModel.type entsprechend
return View(myViewModel);
}
EDIT: The type for selectedItem should be "SelectListItem" as well and of course I forgot to add .ToList() at the end.
I have the following cshtml form
#using (Html.BeginForm(Html.BeginForm("Create", "UserRole", Model, FormMethod.Post)))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Role</legend>
<div class="editor-label">
#Html.Label(Model.User.UserName)
</div>
<div class="editor-field">
#Html.CheckBoxList(Model.CheckboxList)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
And I wish to get the Model.CheckboxList selected Items in my action.
I have the following Create Action in my Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserRoleViewModel userRoleViewModel)
{
if (ModelState.IsValid)
{
//_context.Role.Add(role);
//_context.SaveChanges();
//return RedirectToAction("Index");
}
return View(viewModel);
}
However the viewModel.CheckboxList is 0.
How can I pass the selected values of the checkboxlist, and also the Model.User to the Controller Action?
My ViewModel looks like this :-
public User User { get; set; }
public IEnumerable<Role> RoleList { get; set; }
public List<UserRoleViewModel> UserList { get; set; }
public IEnumerable<SelectListItem> CheckboxList { get; set; }
public UserRoleViewModel()
{
}
public UserRoleViewModel(User user, IEnumerable<Role> roleList )
{
User = user;
RoleList = roleList;
}
Thanks for your help and time!
UPDATE ----------- After reading this post enter link description here, I tried to adapt my code to follow the example, but I am still finding problems with this updated code.
Now I have the following :-
cshtml :-
#model IEnumerable<MvcMembership.ViewModels.RoleCheckboxListViewModel>
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
Views/Role/EditorTemplates/RoleCheckboxListViewModel.cshtml
#model MvcMembership.ViewModels.RoleCheckboxListViewModel
#Html.HiddenFor(x => x.RoleId)
#Html.HiddenFor(x => x.RoleName)
<div>
#Html.CheckBoxFor(x => x.Checked)
#Html.LabelFor(x => x.Checked, Model.RoleName)
</div>
ViewModels :-
public class RoleCheckboxListViewModel
{
public string RoleId { get; set; }
public string RoleName { get; set; }
public bool Checked { get; set; }
}
and the controller action is as follows :-
public ActionResult Create(int? uid)
{
var checkBoxList = new[]
{
new RoleCheckboxListViewModel() {
RoleId = "1", Checked = true, RoleName = "item 1" },
new RoleCheckboxListViewModel() {
RoleId = "2", Checked = true, RoleName = "item 2" },
new RoleCheckboxListViewModel() {
RoleId = "3", Checked = true, RoleName = "item 3" },
};
return View(checkBoxList);
}
The problem I have now is that on the Create.cshtml. I cannot see the checkboxlist, but only 123 displayed as well as the OK button.
Any help would be very much appreciated cause I am at a dead end at the moment.
I've accomplished this with the following parts:
1) A view model for the child element that adds the bool property that will represent whether or not the checkbox is checked in the View later... ie:
public class CategoryViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public bool Assigned { get; set; }
}
2) A view model for the parent element that adds a collection property for this new child element view model, ie:
public class ManufacturerViewModel
{
public Manufacturer Manufacturer { get; set; }
public IList<CategoryViewModel> Categories { get; set; }
public ManufacturerViewModel()
{
Categories = new List<CategoryViewModel>();
}
}
3) A service layer method for getting a list of all child elements, while also setting the bool property for each ("Assigned" in my example). To be used by your controller.
public IList<CategoryViewModel> GetCategoryAssignments(Manufacturer mfr)
{
var categories = new List<CategoryViewModel>();
foreach (var category in GetCategories())
{
categories.Add(new CategoryViewModel
{
ID = category.ID,
Name = category.Name,
Assigned = mfr.Categories.Select(c => c.ID).Contains(category.ID)
});
}
return categories;
}
4) A method for updating the parent item's collection based on your checkboxlist selections. To be used by your controller.
public void UpdateCategories(string[] selectedCategories, ManufacturerViewModel form)
{
if (selectedCategories == null)
selectedCategories = new string[] { };
var selectedIds = selectedCategories.Select(c => int.Parse(c)).ToList();
var assignedIds = form.Manufacturer.Categories.Select(c => c.ID).ToList();
foreach (var category in GetCategories())
{
if (selectedIds.Contains(category.ID))
{
if (!assignedIds.Contains(category.ID))
form.Manufacturer.Categories.Add(category);
}
else
{
if (assignedIds.Contains(category.ID))
form.Manufacturer.Categories.Remove(category);
}
}
}
5) Modifications to your Create/Edit view. ie:
#Html.EditorFor(model => model.Categories)
You must also add this so that the original assigned values are included in post data. You'll have to add a HiddenFor for each property that you have set as Required through validation.
for (int i = 0; i < Model.Manufacturer.Categories.Count; i++)
{
#Html.HiddenFor(model => model.Manufacturer.Categories[i].ID);
#Html.HiddenFor(model => model.Manufacturer.Categories[i].Name);
}
6) And finally, a new EditorTemplate for your child view model element. ie:
#model YourProject.ViewModels.CategoryViewModel
<li>
<input type="checkbox"
id="#string.Format("cb{0}{1}", #Model.Name, #Model.ID)"
name="selectedCategories" //Notice this name corresponds to string[] selectedCategories so that it can be extracted from the post data
value="#Model.ID"
#(Html.Raw(Model.Assigned ? "checked=\"checked\"" : "")) />
<label for="#string.Format("cb{0}{1}", #Model.Name, #Model.ID)">#Model.Name</label>
#Html.HiddenFor(model => model.ID)
</li>
Hopefully my own application gives you a better idea of how to solve this issue.
Store your selected value into the variable as follows, and pass it to an hidden field, then you can access it easily
var modelSelected = document.getElementById("modelName");
document.getElementById('selectedModel').value =
modelSelected.options[modelSelected.selectedIndex].text;
<input id="selectedModel" name="selectedModel" type="hidden" runat="server" />