I've got a cascading drop-drown using mvc. Something like, if you select a country in the first-dropdown, the states of that country in the second one should be populated accordingly.
At the moment, all seems fine and I'm getting Json response (saw it using F12 tools), and it looks something like [{ "stateId":"01", "StateName": "arizona" } , { "stateId" : "02", "StateName":"California" }, etc..] ..
I'd like to know how to populate my second-dropdown with this data. My second drop-down's id is "StateID". Any help would be greatly appreciated.
Below is the code used to produce the JSON Response from the server:
[HttpPost]
public JsonResult GetStates(string CountryID)
{
using (mdb)
{
var statesResults = from q in mdb.GetStates(CountryID)
select new Models.StatesDTO
{
StateID = q.StateID,
StateName = q.StateName
};
locations.statesList = stateResults.ToList();
}
JsonResult result = new JsonResult();
result.Data = locations.statesList;
return result;
}
Below is the client-side HTML, my razor-code and my script. I want to write some code inside "success:" so that it populates the States dropdown with the JSON data.
<script type="text/javascript">
$(function () {
$("select#CountryID").change(function (evt) {
if ($("select#CountryID").val() != "-1") {
$.ajax({
url: "/Home/GetStates",
type: 'POST',
data: { CountryID: $("select#CountryID").val() },
success: function () { alert("Data retrieval successful"); },
error: function (xhr) { alert("Something seems Wrong"); }
});
}
});
});
</script>
To begin with, inside a jQuery event handler function this refers to the element that triggered the event, so you can replace the additional calls to $("select#CountryID") with $(this). Though where possible you should access element properties directly, rather than using the jQuery functions, so you could simply do this.value rather than $(this).val() or $("select#CountryID").val().
Then, inside your AJAX calls success function, you need to create a series of <option> elements. That can be done using the base jQuery() function (or $() for short). That would look something like this:
$.ajax({
success: function(states) {
// states is your JSON array
var $select = $('#StateID');
$.each(states, function(i, state) {
$('<option>', {
value: state.stateId
}).html(state.StateName).appendTo($select);
});
}
});
Here's a jsFiddle demo.
Relevant jQuery docs:
jQuery.each()
jQuery()
In my project i am doing like this it's below
iN MY Controller
public JsonResult State(int countryId)
{
var stateList = CityRepository.GetList(countryId);
return Json(stateList, JsonRequestBehavior.AllowGet);
}
In Model
public IQueryable<Models.State> GetList(int CountryID)
{
var statelist = db.States.Where(x => x.CountryID == CountryID).ToList().Select(item => new State
{
ID = item.ID,
StateName = item.StateName
}).AsQueryable();
return statelist;
}
In view
<script type="text/javascript">
function cascadingdropdown() {
$("#stateID").empty();
$("#stateID").append("<option value='0'>--Select State--</option>");
var countryID = $('#countryID').val();
var Url="#Url.Content("~/City/State")";
$.ajax({
url:Url,
dataType: 'json',
data: { countryId: countryID },
success: function (data) {
$("#stateID").empty();
$("#stateID").append("<option value='0'>--Select State--</option>");
$.each(data, function (index, optiondata) {
$("#stateID").append("<option value='" + optiondata.ID + "'>" + optiondata.StateName + "</option>");
});
}
});
}
</script>
i think this will help you......
Step 1:
At very first, we need a model class that defines properties for storing data.
public class ApplicationForm
{
public string Name { get; set; }
public string State { get; set; }
public string District { get; set; }
}
Step 2:
Now, we need an initial controller that will return an Index view by packing list of states in ViewBag.StateName.
public ActionResult Index()
{
List<SelectListItem> state = new List<SelectListItem>();
state.Add(new SelectListItem { Text = "Bihar", Value = "Bihar" });
state.Add(new SelectListItem { Text = "Jharkhand", Value = "Jharkhand" });
ViewBag.StateName = new SelectList(state, "Value", "Text");
return View();
}
In above controller we have a List containing states attached to ViewBag.StateName. We could get list of states form database using Linq query or something and pack it to ViewBag.StateName, well let’s go with in-memory data.
Step 3:
Once we have controller we can add its view and start creating a Razor form.
#Html.ValidationSummary("Please correct the errors and try again.")
#using (Html.BeginForm())
{
<fieldset>
<legend>DropDownList</legend>
#Html.Label("Name")
#Html.TextBox("Name")
#Html.ValidationMessage("Name", "*")
#Html.Label("State")
#Html.DropDownList("State", ViewBag.StateName as SelectList, "Select a State", new { id = "State" })
#Html.ValidationMessage("State", "*")
#Html.Label("District")
<select id="District" name="District"></select>
#Html.ValidationMessage("District", "*")
<p>
<input type="submit" value="Create" id="SubmitId" />
</p>
</fieldset>
}
You can see I have added proper labels and validation fields with each input controls (two DropDownList and one TextBox) and also a validation summery at the top. Notice, I have used which is HTML instead of Razor helper this is because when we make JSON call using jQuery will return HTML markup of pre-populated option tag. Now, let’s add jQuery code in the above view page.
Step 4:
Here is the jQuery code making JSON call to DDL named controller’s DistrictList method with a parameter (which is selected state name). DistrictList method will returns JSON data. With the returned JSON data we are building tag HTML markup and attaching this HTML markup to ‘District’ which is DOM control.
#Scripts.Render("~/bundles/jquery")
<script type="text/jscript">
$(function () {
$('#State').change(function () {
$.getJSON('/DDL/DistrictList/' + $('#State').val(), function (data) {
var items = '<option>Select a District</option>';
$.each(data, function (i, district) {
items += "<option value='" + district.Value + "'>" + district.Text + "</option>";
});
$('#District').html(items);
});
});
});
</script>
Please make sure you are using jQuery library references before the tag.
Step 5:
In above jQuery code we are making a JSON call to DDL named controller’s DistrictList method with a parameter. Here is the DistrictList method code which will return JSON data.
public JsonResult DistrictList(string Id)
{
var district = from s in District.GetDistrict()
where s.StateName == Id
select s;
return Json(new SelectList(district.ToArray(), "StateName", "DistrictName"), JsonRequestBehavior.AllowGet);
}
Please note, DistrictList method will accept an ‘Id’ (it should be 'Id' always) parameter of string type sent by the jQuery JSON call. Inside the method, I am using ‘Id’ parameter in linq query to get list of matching districts and conceptually, in the list of district data there should be a state field. Also note, in the linq query I am making a method call District.GetDistrict().
Step 6:
In above District.GetDistrict() method call, District is a model which has a GetDistrict() method. And I am using GetDistrict() method in linq query, so this method should be of type IQueryable. Here is the model code.
public class District
{
public string StateName { get; set; }
public string DistrictName { get; set; }
public static IQueryable<District> GetDistrict()
{
return new List<District>
{
new District { StateName = "Bihar", DistrictName = "Motihari" },
new District { StateName = "Bihar", DistrictName = "Muzaffarpur" },
new District { StateName = "Bihar", DistrictName = "Patna" },
new District { StateName = "Jharkhand", DistrictName = "Bokaro" },
new District { StateName = "Jharkhand", DistrictName = "Ranchi" },
}.AsQueryable();
}
}
Step 7:
You can run the application here because cascading dropdownlist is ready now. I am going to do some validation works when user clicks the submit button. So, I will add another action result of POST version.
[HttpPost]
public ActionResult Index(ApplicationForm formdata)
{
if (formdata.Name == null)
{
ModelState.AddModelError("Name", "Name is required field.");
}
if (formdata.State == null)
{
ModelState.AddModelError("State", "State is required field.");
}
if (formdata.District == null)
{
ModelState.AddModelError("District", "District is required field.");
}
if (!ModelState.IsValid)
{
//Populate the list again
List<SelectListItem> state = new List<SelectListItem>();
state.Add(new SelectListItem { Text = "Bihar", Value = "Bihar" });
state.Add(new SelectListItem { Text = "Jharkhand", Value = "Jharkhand" });
ViewBag.StateName = new SelectList(state, "Value", "Text");
return View("Index");
}
//TODO: Database Insertion
return RedirectToAction("Index", "Home");
}
Try this inside the ajax call:
$.ajax({
url: "/Home/GetStates",
type: 'POST',
data: {
CountryID: $("select#CountryID").val()
},
success: function (data) {
alert("Data retrieval successful");
var items = "";
$.each(data, function (i, val) {
items += "<option value='" + val.stateId + "'>" + val.StateName + "</option>";
});
$("select#StateID").empty().html(items);
},
error: function (xhr) {
alert("Something seems Wrong");
}
});
EDIT 1
success: function (data) {
$.each(data, function (i, val) {
$('select#StateID').append(
$("<option></option>")
.attr("value", val.stateId)
.text(val.StateName));
});
},
I know this post is a year old but I found it and so might you. I use the following solution and it works very well. Strong typed without the need to write a single line of Javascript.
mvc4ajaxdropdownlist.codeplex.com
You can download it via Visual Studio as a NuGet package.
You should consider using some client-side view engine that binds a model (in your case JSON returned from API) to template (HTML code for SELECT). Angular and React might be to complex for this use case, but JQuery view engine enables you to easily load JSON model into template using MVC-like approach:
<script type="text/javascript">
$(function () {
$("select#CountryID").change(function (evt) {
if ($("select#CountryID").val() != "-1") {
$.ajax({
url: "/Home/GetStates",
type: 'POST',
data: { CountryID: $("select#CountryID").val() },
success: function (response) {
$("#stateID").empty();
$("#stateID").view(response);
},
error: function (xhr) { alert("Something seems Wrong"); }
});
}
});
});
</script>
It is much cleaner that generating raw HTML in JavaScript. See details here: https://jocapc.github.io/jquery-view-engine/docs/ajax-dropdown
Try this:
public JsonResult getdist(int stateid)
{
var res = objdal.getddl(7, stateid).Select(m => new SelectListItem { Text = m.Name, Value = m.Id.ToString() });
return Json(res,JsonRequestBehavior.AllowGet);
}
<script type="text/javascript">
$(document).ready(function () {
$("#ddlStateId").change(function () {
var url = '#Url.Content("~/")' + "Home/Cities_SelectedState";
var ddlsource = "#ddlStateId";
var ddltarget = "#ddlCityId";
$.getJSON(url, { Sel_StateName: $(ddlsource).val() }, function (data) {
$(ddltarget).empty();
$.each(data, function (index, optionData) {
$(ddltarget).append("<option value='" + optionData.Text + "'>" + optionData.Value + "</option>");
});
});
});
});
</script>
Related
I have difficulties to refresh an Html.DropDownGroupList.
I have two dropdowns which depends on each other: Makes and Models. The Models dropdown should be grouped, as you can see in the attached screenshot.
When I enter in the page the Models dropdown is filled with data and it is grouped correctly, but when I change the first dropdown, the Model is not refreshing correctly.
In the controller I have this code:
public ActionResult GetModels(string id)
{
if (!string.IsNullOrEmpty(id))
{
int number;
bool result = Int32.TryParse(id, out number);
if (!result)
return Json(null);
var selectedMake = makeRepository.GetMakeByID(number);
var list1 = db.Models.Where(m => m.MakeID == selectedMake.ID).ToList();
List<GroupedSelectListItem> models = new List<GroupedSelectListItem>();
foreach (var items in list1)
{
models.Add(new GroupedSelectListItem
{
Text = items.Name,
Value = items.ID.ToString(),
GroupName = items.GroupName,
GroupKey = items.GroupName
});
}
ViewBag.Alma = models;
return Json(models, JsonRequestBehavior.AllowGet);
}
return Json(null);
}
and in the View :
#Html.DropDownGroupList("models", ViewBag.Alma as List<GroupedSelectListItem>, "Select Model", new
{
#class = "dropdown-toggle col-md-9 form-control"
})
This is the code where I try to refresh the dropdown:
$.ajax({
type: 'POST',
url: '#Url.Action("GetModels")',
dataType: 'json',
data: { id: $("#makes").val() },
success: function (models) {
if (window.console) {
console.log(JSON.stringify(models))
}
$.each(models, function (i, model) {
$("#models").append
('<optgroup label="'+ model.GroupName + '"><option value="' + model.Value + '">' +
model.Text + '</option></optgroup>'
);
});
}
});
This is the way the dropdown looks after the refresh
The grouping is not working anymore. I know that this is the problem:
$("#models").append('<optgroup label="'+ model.GroupName + '"><option value="' + model.Value + '">' + model.Text + '</option></optgroup>');
but how to do this ajax call to group my dropdown? I don't have so much experience with ajax, javascript.
Can you please advise how to refresh the Model dropdown?
Your GetModels() method is returning List<GroupedSelectListItem> which is a special class used by the DropDownGroupList() method and is not suitable for building your html (at least without a lot of extra code to group data in the script).
Start by creating view models to represent the hierarchical data you need
public class GroupVM
{
public string Name { get; set; }
public IEnumerable<OptionVM> Options { get; set; }
}
public class OptionVM
{
public int Value { get; set; }
public string Text { get; set; }
}
Then modify the controller to group your data and project the results to the view model
public ActionResult GetModels(int? id)
{
if (!id.HasValue)
{
return Json(null);
}
var data = db.Models.Where(x => x.MakeID == id.Value).GroupBy(x => x.GroupName).Select(x => new GroupVM()
{
Name = x.Key,
Options = x.Select(y => new OptionVM()
{
Value = y.ID,
Text= y.Name
})
});
return Json(data);
}
And modify your script to
var models = $('#models'); // cache it
$('#makes').change(function () {
var id = $(this).val();
$.ajax({
type: 'POST',
url: '#Url.Action("GetModels")',
dataType: 'json',
data: { id: id },
success: function (data) {
models.empty(); // clear existing options
$.each(data, function (index, group) {
var optGroup = $('<optgroup></optgroup>').attr('label', group.Name);
$.each(group.Options, function (index, option) {
var option = $('<option></option>').val(option.Value).text(option.Text);
optGroup.append(option);
});
models.append(optGroup);
});
}
});
})
I am using a multi select dropdown for a particular entry, which is retrieved from a table. If I am trying to edit this entry the selected dropdown is not showing.
This is my script.
<script type="text/javascript">
$(document).ready(function () {
//$('#Supplier').click(function () {
var sku = $("#SKU").val();
alert(sku);
//var pay = null;
//alert(suppid);
$.ajax({
url: '/SKUMasterSetup/supplierlist',
type: 'POST',
dataType: 'json',
data: { id: sku },
success: function (Supplierdata) {
alert("hi");
alert(Supplierdata);
var x = Supplierdata.length();
alert(x);
//<option value="{$T.data.Value}">{$T.data.Text}</option>
//for (var i = 0; i < Supplierdata.length; i++) {
// $("#supplier").append("Selected", Supplierdata[i], "selected").attr('selected', true);
for (var i in Supplierdata) {
var optionVal = Supplierdata[i];
$("#supplier").find("option[value=" + optionVal + "]").prop("selected", "selected");
}
// $('.class1').append("<option>" + "Please select" + "</option>");
},
//error : function (Supplier) { alert("Error !"); };
});
});
</script>
And my controller code is:
[HttpPost]
public JsonResult supplierlist(int id)
{
var Supplierdata = (from item in db.SupplierSKUMaps
where item.SKU == id
select item.SupplierMaster.SupplierName).ToList();
return Json(Supplierdata, JsonRequestBehavior.AllowGet);
}
And my dropdownlist is:
#Html.DropDownList("Supplier", ViewBag.Supplier as MultiSelectList, new { #class = "chosen", #id="supplier", #multiple = "multiple" })
you could always use #Value = #Html.Action(getMyFields) and within your controller, place an action method that returns Content result(MyData.ToList()).
More information on creating dropdowns can be found here: http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx
I have a json string like [{Name:"Russia",Value:6},{Name:"USA",Value:"8"}]
in controller how can i convert this list to select list item to bind to a dropdownlist?
and i have to populate state list depending upon the selected country using ajax post back?
anybody give some sample on this
Below is example for bind dropdown from your json object. In this example GetCountry is function from controller which is return json object and below script is iterate json object and bind the dropdown.
Script:-
$(document).ready(function () {
$.getJSON('#Url.Action("GetCountry", "Dropdown")', function (result) {
var ddlCountryId = $('#CountryId');
ddlCountryId.empty();
$(result).each(function () {
ddlCountryId.append(
$('<option/>', {
value: this.Id
}).html(this.Nome)
);
});
});
});
View syntax:-
#Html.DropDownListFor(x => x.CountryId, new SelectList(Enumerable.Empty<SelectListItem>()))
Controller Function:-
public ActionResult GetCountry()
{
var sites = new[]
{
new { Id = "6", Nome = "Russia" },
new { Id = "8", Nome = "USA" }
};
return Json(sites, JsonRequestBehavior.AllowGet);
}
I have an entity Location and I am using the Kendu UI Grid with InLine edit mode.
The entity owns a property DisplayName, which is required and must not exist twice in the database.
At the moment, it works to display the Required Validation message:
And it also works to build up a method CustomValidateModel called in the LocationController Ajax InLine Create method, that checks if the Name is already existing in the database and adds then a ModelError. I catch this error then in the .Events(events => events.Error("onError")) via javascript and show then the message via javascript popup.
ModelState.AddModelError("DisplayName", "Name already exists.");
And this is the crux of the matter: I don't want to have this javascript popup message. I want to have also this information below the field, like this "Field required!" message.
I have searched plenty of time, but the most people suggest only this Validation and output via javascript as it works in the moment.
Additionally, the actual problem besides the popup, is, that the record, which the user wants to create in the Grid, is then disappearing after confirming the javascript popup.
But for usability, I want that the new line and the input persists. The users should be able to edit the given Name, he wanted to save. And NOT should enter the complete line again. Only the Validation message "Name already existing." should prompt for information.
Code:
Location entity:
public class LocationDto
{
public Guid? ID { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Field required!")]
public string DisplayName { get; set; }
// other properties
}
LocationController Action method:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateInline([DataSourceRequest] DataSourceRequest request, LocationDto model)
{
CustomValidateModel(model); // checks if the DisplayName is already existing in the DB
if (model != null && ModelState.IsValid)
{
// Create and Save the Model into database
}
return Json(ModelState.ToDataSourceResult());
}
javascript function:
function onError(e, status) {
if (e.errors) {
var message = "Error:\n";
$.each(e.errors, function (key, value) {
if (value.errors) {
message += value.errors.join("\n");
}
});
this.cancelChanges();
alert(message);
}
}
I hope there is a possibility to get this working in the same way. It would be fine according congruent visualization and an enhancement of usability.
We accomplished this in a Grid just like you did on the controller side by adding our custom error to the model state and passing that back to the view. And then in the onError javascript event we built the validation message ourselves and placed it in the grid.
Javascript onError:
function onError(e, status) {
if (e.errors) {
var message = "Error:\n";
var grid = $('#gridID').data('kendoGrid');
var gridElement = grid.editable.element;
$.each(e.errors, function (key, value) {
if (value.errors) {
gridElement.find("[data-valmsg-for=" + key + "],[data-val-msg-for=" + key + "]")
.replaceWith(validationMessageTmpl({ field: key, message: value.errors[0] }));
gridElement.find("input[name=" + key + "]").focus()
}
});
}
}
Then create a validationMessageTmpl (or whatever you want to call it):
var validationMessageTmpl = kendo.template($("#message").html());
<script type="text/kendo-template" id="message">
<div class="k-widget k-tooltip k-tooltip-validation k-invalid-msg field-validation-error" style="margin: 0.5em; display: block; " data-for="#=field#" data-valmsg-for="#=field#" id="#=field#_validationMessage">
<span class="k-icon k-warning">
</span>
#=message#
<div class="k-callout k-callout-n">
</div>
</div>
</script>
As far as why user input is disappearing, I assume that:
this.cancelChanges();
may have something to do with it. I believe this does just what it says and cancels all changes. Which would reset your grid and remove all user input.
One thing to note: The code in the ModelState (also the key in your $.each) must be the same name as the view model property being used for the column you want to display the error on.
With modifying of another answer and trying around, I constructed a working solution:
Location Edit.cshtml Grid Razor:
.DataSource(ds => ds
.Ajax()
.Events(e => e.Error("onError"))
.Model(m =>
{
m.Id(e => e.ID);
...
})
.Create(create => create.Action("CreateInLine", "Location"))
.Read(...)
.Update(update => update.Action("UpdateInLine", "Location"))
.Destroy(...)
)
Location Edit.cshtml js:
<script type="text/javascript">
function onError(e, status) {
if (e.errors) {
var message = "Error:\n";
var grid = $('#locationGrid').data('kendoGrid');
var gridElement = grid.editable.element;
var validationMessageTemplate = kendo.template(
"<div id='#=field#_validationMessage' " +
"class='k-widget k-tooltip k-tooltip-validation " +
"k-invalid-msg field-validation-error' " +
"style='margin: 0.5em;' data-for='#=field#' " +
"data-val-msg-for='#=field#' role='alert'>" +
"<span class='k-icon k-warning'></span>" +
"#=message#" +
"<div class='k-callout k-callout-n'></div>" +
"</div>");
$.each(e.errors, function (key, value) {
if (value.errors) {
gridElement.find("[data-valmsg-for=" + key + "],[data-val-msg-for=" + key + "]")
.replaceWith(validationMessageTemplate({ field: key, message: value.errors[0] }));
gridElement.find("input[name=" + key + "]").focus();
}
});
grid.one("dataBinding", function (e) {
e.preventDefault(); // cancel grid rebind
});
}
}
</script>
LocationController.cs
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateInLine([DataSourceRequest] DataSourceRequest request, LocationViewModel model)
{
CustomValidateModel(model);
if (model != null && ModelState.IsValid)
{
var location = _repository.CreateNewInstance<Location>();
location.ID = Guid.NewGuid();
location.DisplayName = model.DisplayName;
...
_repository.SaveChanges();
model = MapToViewModel(location);
}
return Json(new[] { model }.ToDataSourceResult(request, ModelState));
}
private void CustomValidateModel(LocationViewModel model)
{
var existingEntity = _repository.GetAll<Location>()
.Where(o => o.ID != model.ID)
.Where(o => o.DisplayName.Equals(model.DisplayName))
.FirstOrDefault();
if (existingEntity != null)
{
if (existingEntity.Deleted == false)
ModelState.AddModelError("DisplayName", "Name already exists.");
else
ModelState.AddModelError("DisplayName", "Name '" + existingEntity.DisplayName + "' already exists in DB, but deleted.");
}
}
Result:
You can try this;
DisplayName: {
validation: {
required: true,
DisplayNameValidation: function (input) {
var exists = CheckName(input.val());
if (exists && input.is("[name='DisplayName']") && input.val() != "") {
input.attr("data-DisplayNameValidation-msg", "Name already exists.");
return false;
}
}
return true;
}
}
And
function CheckName(Name) {
var exists = false;
$.ajax
({
type: "POST",
url: "CheckName",
data: "{Name:'" + Name + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false,
error: function (msg) {
},
success: function (response) {
exists = response;
}
});
return exists;
}
For further documentation check kendo demo site for custom validation.
I need help writing the jquery/ajax to fill a Select2 dropdown box.
For those who don't know what Select2 is, it is a javascript extension to provide Twitter Bootstrap looks and search / type-ahead functionality to an html select list dropdown box. For more information look at the examples here: Select2 Github page
UPDATED - Solved!
So I finally put this all together, and the solution to my problems was that I was missing functions to format the results and the list selection. The code below produces a functioning Select2 dropbox with type-ahead perfectly.
Json Method on Controller:
public JsonResult FetchItems(string query)
{
DatabaseContext dbContext = new DatabaseContext(); //init dbContext
List<Item> itemsList = dbContext.Items.ToList(); //fetch list of items from db table
List<Item> resultsList = new List<Item>; //create empty results list
foreach(var item in itemsList)
{
//if any item contains the query string
if (item.ItemName.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
{
resultsList.Add(item); //then add item to the results list
}
}
resultsList.Sort(delegate(Item c1, Item c2) { return c1.ItemName.CompareTo(c2.ItemName); }); //sort the results list alphabetically by ItemName
var serialisedJson = from result in resultsList //serialise the results list into json
select new
{
name = result.ItemName, //each json object will have
id = result.ItemID //these two variables [name, id]
};
return Json(serialisedJson , JsonRequestBehavior.AllowGet); //return the serialised results list
}
The Json controller method above returns a list of serialised Json objects, whose ItemName contains the string 'query' provided (this 'query' comes from the search box in the Select2 drop box).
The code below is the Javascript in the view(or layout if you prefer) to power the Select2 drop box.
Javascript:
$("#hiddenHtmlInput").select2({
initSelection: function (element, callback) {
var elementText = "#ViewBag.currentItemName";
callback({ "name": elementText });
},
placeholder: "Select an Item",
allowClear: true,
style: "display: inline-block",
minimumInputLength: 2, //you can specify a min. query length to return results
ajax:{
cache: false,
dataType: "json",
type: "GET",
url: "#Url.Action("JsonControllerMethod", "ControllerName")",
data: function (searchTerm) {
return { query: searchTerm };
},
results: function (data) {
return {results: data};
}
},
formatResult: itemFormatResult,
formatSelection: function(item){
return item.name;
}
escapeMarkup: function (m) { return m; }
});
Then in the body of the view you need a hidden Input element, which Select2 will render the dropbox to.
Html:
<input id="hiddenHtmlInput" type="hidden" class="bigdrop" style="width: 30%" value=""/>
Or attach a MVC Razor html.hidden element to your view model to enable you to post the picked item Id back to the server.
Html (MVC Razor):
#Html.HiddenFor(m => m.ItemModel.ItemId, new { id = "hiddenHtmlInput", #class = "bigdrop", style = "width: 30%", placeholder = "Select an Item" })
Solved! Finally.
The full jquery is below, what was needed were two functions to format the returned results from the controller. This is because the dropbox needs some html markup to be wrapped around the results in order to be able to display them.
Also contractID was needed as an attribute in the controller as without it results were shown in the dropdown, but they could not be selected.
$("#contractName").select2({
placeholder: "Type to find a Contract",
allowClear: true,
minimumInputLength: 2,
ajax: {
cache: false,
dataType: "json",
type: "GET",
url: "#Url.Action("FetchContracts", "Leads")",
data: function(searchTerm){
return { query: searchTerm };
},
results: function(data){
return { results: data };
}
},
formatResult: contractFormatResult,
formatSelection: contractFormatSelection,
escapeMarkup: function (m) { return m; }
});
function contractFormatResult(contract) {
var markup = "<table class='contract-result'><tr>";
if (contract.name !== undefined) {
markup += "<div class='contract-name'>" + contract.name + "</div>";
}
markup += "</td></tr></table>"
return markup;
}
function contractFormatSelection(contract) {
return contract.name;
}
The problem is that you are returning a List<Contract> from that controller method, but the MVC runtime doesn't know how to hand that off to the browser. You need to return a JsonResult instead:
public JsonResult FetchContracts()
{
TelemarketingContext teleContext = new TelemarketingContext();
var contracts = teleContext.Contracts.ToList();
var json = from contract in contracts
select new {
name = contract.ContractName,
id = contract.ContactID,
};
return Json(json, JsonRequestBehavior.AllowGet);
}
Now, the data param of the AJAX : Success function will be the JSON from the controller. I'm not familiar with how this plugin works, but you should be able to loop through the json in data manually if you need to.
Select 2 seems to be a standard select with jquery attached so this should work:
Model:
public class vmDropDown
{
public IEnumerable<SelectListItem> DeviceList { get; set; }
[Required(ErrorMessage = "Please select at least one item")]
public IEnumerable<int> SelectedItems { get; set; }
}
Controller:
[HttpGet]
public ActionResult Assign(int id)
{
return View(CreateUnassignedModel(id));
}
[HttpPost]
public ActionResult Assign(vmDeviceAssign model)
{
if (ModelState.IsValid)
{
_deviceLogic.Assign(model.GroupId, model.SelectedItems);
return View("ConfirmDevice");
}
else // Validation error, so redisplay data entry form
{
return View(CreateUnassignedModel(model.GroupId));
}
}
private vmDeviceAssign CreateUnassignedModel(int id)
{
return new vmDeviceAssign
{
DeviceList = _deviceLogic.GetUnassigned(),
SelectedItems = null
};
}
View:
<div class="editor-field">
#Html.ListBoxFor(model => model.SelectedItems, new SelectList(Model.DeviceList, "Value", "Text"))
#Html.ValidationMessageFor(model => model.SelectedItems)
</div>
Cant give explanation as am at work but if you leave a message ill pick it up tonight