I feel that the answer for this has to be out there in several places as variations of this question seem to get asked a lot. Unfortunately I cannot grasp exactly how to do what I am trying to achieve, so your help is greatly appreciated once again.
I have a list of usergroups, which are each assigned to a staff member. This is done by iterating through the list of usergroups and showing a dropdown of available staff members beside each one. It should be possible to not assign a staff member also, so a null value select option should be available.
When a new group is being created, having the null value as the default is fine, but where I am just updating an existing record, I want the dropdown to default to the option with the matching staff member ID.
So I query for available staff members:
var rtrnStaff = (from st in db.PrmTbl_Staffs
join sal in db.PrmTbl_Salutations on st.SalutationID equals sal.ID
where st.Active == true
select new { st.ID, Name = sal.Desc + ". " + st.Name });
To insert a blank value into this array:
List<SelectListItem> staff = new SelectList(rtrnStaff, "ID", "Name").ToList();
staff.Insert(0, (new SelectListItem { Text = "None", Value = "0" })); //can value be = null?
In my view, for the form to create a new user group, I can provide a dropdown like so:
#Html.DropDownList( "staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"])
This provides a dropdown, with the "None" option first, which is fine. However, when I try the same thing for my update form, with the addition of a default value argument, it doesn't work:
#Html.DropDownList( "staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], item.StaffID)
The intention being that when placed within a foreach loop, the option matching the relevant staffID would show as default. Instead, "none" is still the first option.
I did try to just query the table in my controller, not build a selectlist there but pass the results directly via ViewData to the View, and then in the View do the following:
#Html.DropDownList("staffID", new SelectList(
(System.Collections.IEnumerable) ViewData["Staff"], "ID", "Name", item.StaffID),
new { Name = "staffID" })
That works no probs, but without a "none" option. Clearly I need some middle ground! Between DropDownList, DropDownListFor, List, SelectList, etc., I'm confused.
EDIT
(To show current state of code)
Controller:
var rtrnStaff = (from st in db.PrmTbl_Staffs
join sal in db.PrmTbl_Salutations on st.SalutationID equals sal.ID
where st.Active == true
select new { st.ID, Name = sal.Desc + ". " + st.Name });
List<SelectListItem> staff = new SelectList(rtrnStaff, "ID", "Name").ToList();
ViewData["StaffwNull"] = staff;
View:
//show dropdown of all staff,
//defaulting to "None" value (works)
#Html.DropDownList("staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], "None")
//show dropdown of all staff,
//defaulting to value matching item.staffID (doesn't work)
//default selection is first list item
//and list doesnt include "None" option
#foreach (var item in Model)
{
...
var thisStaffID = item.StaffID;
....
#Html.DropDownList( "staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], thisStaffID)
}
There is no overload where you can specify a selected value. MVC searches in the ViewBag object for an item called staffID and use that as selected value. You can use this overload of the DropDownList method which allows you to specify an option label:
#Html.DropDownList("staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], "None")
This renders an extra option to the select list at the top so you don't have to do this manually.
Side note: you should look into MVC model binding.
You can give an ID to the dropdown list (this overload) and then use jQuery to update it.
View
#Html.DropDownList("staffID", (IEnumerable<SelectListItem>)ViewData["StaffwNull"], new { id = "dropdown1" })
jQuery
<script>
$(document).ready(function () {
$('#dropdown1').val('theValueYouWantSelected');
});
</script>
Related
I'm trying to put data form two tabels (AcademicDegrees, Lecturers) conneted by one to many relation into one ViewData to generate options to field (with label and id as value). It shoud be somthing like this where id are used as values nad other field as label.
ViewData["ClassroomsId"] = new SelectList(_context.Classroom, "ClassroomsID", "Number");
When all the date for field was in one table I used getter form field to get it.
[NotMapped]
public string toStringVar => FirstName + " " + LastName;
When I added tabel with academic degrees I moved to different solution.
var lecturers = _context.Lecturer;
var degree = _context.AcademicDegrees;
var lecturersList = new List<SelectListItem>();
foreach (Lecturers l in lecturers)
{
_context.AcademicDegrees.Where(d => d.AcademicDegreeId == l.AcademicDegreesId).Load();
foreach(AcademicDegrees d in degree)
{
lecturersList.Add(new SelectListItem(
$"{d.Name} {l.FirstName} {l.LastName}", l.LecturersID.ToString()
));
}
}
ViewData["LecturersId"] = new SelectList(lecturersList);
The problem is that it isn't interpreted as I want it to be.
I also can't put it directly in to SelectList because it doesn't have empty constructor or add method. Is there any other way to implement a SelectList?
In my opinion, it is like redundant work as you have the IEnumerable<SelectListItem> instance which can be used to build the select option.
And you pass IEnumerable<SelectListItem> instance to create the SelectList instance.
Would suggest to pass IEnumerable<SelectListItem> value to ViewData.
Solution for IEnumerable<SelectListItem>
Controller
ViewData["LecturersId"] = lecturersList;
View
#Html.DropDownListFor(model => model./*YourProperty*/, (IEnumerable<SelectListItem>)ViewData["LecturersId"])
Updated
Since you are using ASP.NET Core MVC, with tag helper:
<select asp-for="/*YourProperty*/"
asp-items="#((IEnumerable<SelectListItem>)ViewData["LecturersId"]))">
</select>
Solution for SelectList
If you are keen on the SelectList, make sure that you have provided the dataValueField and dataTextField according to this constructor
public SelectList (System.Collections.IEnumerable items, string dataValueField, string dataTextField);
as below:
ViewData["LecturersId"] = new SelectList(lecturersList, "Value", "Text");
Besides, the query part would be suggested to optimize by joining both tables as below:
var lecturersList = (from a in _context.Lecturer
join b in _context.AcademicDegrees on a.AcademicDegreeId equals b.AcademicDegreeId
select new SelectListItem($"{b.Name} {a.FirstName} {a.LastName}", a.LecturersID.ToString())
).ToList();
Here I have dropdownlist which contains multiple values. and user can select any no of values by clicking the checkbox infront of the value as shown below.
Following is my c# code.
#Html.DropDownList(m => m.Detail, new SelectList(ViewBag.detailList, "Value", "Text"), new { id = "det" , multiple= "multiple"})
$(document).ready(function() {
$('#det').multiselect();
});
When user click save button I want to get the user selected list. I am using following code to get the values.
$("#det").val()
But the above value is empty. How to get the existing selected value?
And also I want to show the values as selected based on server side values.
I am creating model and set model property with hardcoded values as below.
model.Detail = "Cheese, Tomatoes";
But these values are not getting selected in dropdownlist as well.
Used plugin here - link
Any help?
Thanks.
You need to add multiple= "multiple" in the attributes for multiselect to work.
#Html.DropDownList(m => m.Detail, new SelectList(ViewBag.detailList, "Value", "Text"),
new { id = "det", multiple= "multiple" });
to set the values:
<script>
var selectedValues = #model.Detail;
var dataarray = selectedValues.split(",");
// Set the value
$("#det").val(dataarray);
$("#det").multiselect("refresh");
</script>
First of all, use #Html.ListBoxFor that works best with Multiselect js.
In order to get the values for selected options, I have created the following client side code which returns list of value in form of String arrays
function GetDropDownVal() {
var selectidList = [];
var selectedItem = $("#ListQueCatId").val();
// .multiselect("getChecked") can also be used.
if (selectedItem != null) {
for (var i = 0; i < selectedItem.length; i++) {
selectidList.push(selectedItem[i]);
}
}
return selectidList;
}
This is how I have implemented the code
View Side Code
#Html.ListBoxFor(m => m.ListQueCatId, (SelectList)ViewBag.AllQueCat as MultiSelectList, new { #class = "form-control listQueCatIdDdl" })
Javascript Code
$(".listQueCatIdDdl").multiselect({ noneSelectedText: "--Select Category(s)--" });
Also, make sure to bind a model property of Type List in my case, ListQueCatId is List< Guid>, hence while you post the form, you will get the selected values in your model.
Also, I don't think there is need to add multiple attribute as the plugin is meant for selecting multiple values.
I am trying to add records from table position for positionName(s) to let user select a position for employee when editing.My last attempts is to add a navigation property like field in company model
public virtual ICollection<Position> Mpositions { get; set; }
But all I got so far is null ref exception or no element in viewModel with property "PositionName" ass per viewbag didn't bother using everybody keeps recommending to avoid it so not going to do so either.
public ActionResult Edit([Bind(Include = "CompanyID,CompanyName,EntityForm,Address,Dissolute,CreationDate,FiscaleYear,Description")] Company company)
{
var GlbUpdate = db.Companies.Include(c => c.Members).Include(p => p.Mpositions);
List<Company> mdlCompanies = new List<Company>();
foreach (var item in GlbUpdate)
{
if ((item.Mpositions==null) || (item.Mpositions.Count() == 0))
{
item.Mpositions = (ICollection<Position>)new SelectList(db.Positions.Except((IQueryable<Position>)db.Positions.Select(xk => xk.Members)), "PositionID", "PositionName");
}
mdlCompanies.Add(item);
//I tried first to edit the Mpositions property directly in gblUpdate
//item.Mpositions = (IEnumerable<Position>)db.Positions.Select(p => new SelectListItem { Value = p.PositionID.ToString(), Text = p.PositionName}) ;
//(ICollection<Position>)db.Positions.ToListAsync();
}
In the view I have this
List<SelectListItem> mPositionNames = new List<SelectListItem>();
#*#this yields no results if I try gettign it from the compani record itself it gives a logic error where all id match all positionNames impossible to select an item and only positions already registered are available on the dropDownlist*#
#{foreach (var item in Model.Mpositions)
{
mPositionNames.Add(new SelectListItem() { Text = item.PositionName, Value = item.PositionID.ToString(), Selected = (false) ? true : false });
#*#selected attribute set to false not an issue, no data to select from :p so far*#
}
}
#*#null exception(if i try to midify Mpositions directly in controler) here or empty list if modify it then put it with original query in a new list*#
<div class="SectionContainer R-sectionContainerData" id="MwrapperDataRight">
#Html.DropDownListFor(mpos => item.PositionID, (SelectList)Model.Mpositions)
</div>
All I want to do is pull the positions table to create a drop downList so users can change the position of an employee but since position has a 1>many relation with employee not companies it is not bound automatically by EF nor I seem to be able to use Include() to add it.
Your query for editing positions are complex. This query must edit person's info only. Using Edit action for formalizing position's edit are not correct.It's againts to Single Responsibility Principle. Use ViewComponents for this situation. Load positions separately from person info.
I found a suitable solution using a model that encapsulate the other entities then using Partialviews/RenderAction so each part handles one entity/operation.
I know there's a lot of these kind of post but I wasn't able to find any that suited me. I don't have knowledge of ajax and jquery (in fact I've just started with MVC and ASP.NET) so I need your help in this little thing.
There must be almost everywhere this kind of silly thing, I want to write a city name in a combobox, dropdownlist (or whatever) and using a method that I've already created which returns a list of locations (city, country and state names) that match the entered city. I want it to be dinamyc that's why I thought AJAX would solve this (but any other solution is accepted)
I found this jQuery autocomplete but I don't understand where to implement it. I want the combobox to match the bootstrap theme. Could someone tell me if this is an appropiate solution and if so where do I put the ajax content and else? (by where I mean, is it in the view, or controller or where?)
Or you could give mi a hint here is the method I've created for getting the elements from the database:
public List<LocationsViewModel> GetHeadquarter(string query)
{
var context = new HeadquarterContext();
//var city = context.Cities.Where(p => p.Name == query).Single();
//var province = context.Provinces.Where(p => p.ProvinceID == city.Province).ToList();
//foreach(Province prov in province) {
//}
var hq =
from c in context.Cities
join p in context.Provinces on c.Province equals p.ProvinceID
join co in context.Countries on p.Country equals co.CountryID
where c.Name == query
select new { country = co.Name, province = p.Name, city = c.Name };
List<LocationsViewModel> listLocation = new List<LocationsViewModel>();
foreach (var hqe in hq)
{
LocationsViewModel loc = new LocationsViewModel();
loc.City = hqe.city;
loc.Country = hqe.country;
loc.Province = hqe.province;
listLocation.Add(loc);
}
return listLocation;
}
Lets see if we can get it to work.
View:
This is added in your view, #Url.Action(Action, Controller) is the Action that is the source for the autocomplete function.
<input type="search" class="form-control ui-autocomplete"
data-autocomplete="#Url.Action("Autocomplete", "Home")" />
Controller (Home):
As you can see the Action Autocomplete was used to search for a product. I have an instance of my database entity called '_db' and have select a table called 'product_data' (can also use a Stored Procedure). I'm using LINQ to query the datasource and store it in the variable 'model', so it's querying where the 'term' StartsWith what is typed in the textbox, it takes the top 10 and for each one it add label and product. [{"label":value}]
public ActionResult Autocomplete(string term)
{
try
{
var model = _db.product_data // your data here
.Where(p => p.product.StartsWith(term))
.Take(10)
.Select(p => new
{
// jQuery UI needs the label property to function
label = p.product.Trim()
});
// Json returns [{"label":value}]
return Json(model, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Settings.ReportException(ex);
return Json("{'ex':'Exception'}");
}
}
JavaScript:
This code is when you select a value from the list that is displayed from your search. The 'window.location.href' redirects to a different controller once a value from the autocomplete has been selected.
// submits form upon selecting a value
var submitAutocompleteForm = function (event, ui) {
var $input = $(this); // the HTML element (Textbox)
// selected value
$input.val(ui.item.label); // ui.item.label = the label value (product)
window.location.href = "/Product/Details?id=" + ui.item.label;
};
The next function sets up the autocomplete API. You declare your options, the above is optional and it comes under select, the source is required and it points to the data-attribute on the HTML element.
var createAutocomplete = function () {
var $input = $(this); // the HTML element (Textbox)
var options = {
// selecting the source by finding elements with the 'data-' attribute
source: $input.attr("data-autocomplete"), // Required
select: submitAutocompleteForm // Optional
};
// apply options
$input.autocomplete(options);
};
// targets input elements with the 'data-' attributes and each time the input changes
// it calls the 'createAutocomplete' function
$("input[data-autocomplete]").each(createAutocomplete);
You'll have to reference the jQueryUI file for autocomplete to work.
I would like to send the selected dropdown option into model.Feit
Assuming, i need DropDownListFor, then select table, then the dropdown..?
//here's my drop down menu in my controller
List<SelectListItem> items = new List<SelectListItem>();
items.Add(new SelectListItem { Text = "Owner", Value = "0", Selected = true });
items.Add(new SelectListItem { Text = "Leader", Value = "1" });
ViewBag.items = items;
//this works fine, but the selected option has to be inserted into my database when submitted
//the first line shows the label
<div class="editor-label">#Html.LabelFor(model => model.Feit)</div>
//the second line needs to show as a dropdownlist with the 2 options above here
<div class="editor-field">#Html.DropDownListFor(model => model.Feit, "items")</div>
//when the option is selected, and submit is pressed this has to be sent to the db
// this works for all other fields, but my syntax is wrong at , "items"
Since you've already populated an IEnumerable<SelectListItem> in your viewbag, you just need to access it and cast it to ensure the correct DropDownListFor overload is used:
#Html.DropDownListFor(model => model.Feit, (IEnumerable<SelectListItem>)ViewBag.items)
model.Feit should be of type int or something that can hold the value of the selected item.
Use this
#Html.DropDownListFor(m => m.Feit, new SelectList(ViewBag.items, "Id","Name"),"Select")