I'm working on creating two dropdown lists for a form. The first is a list of Areas and the second needs to filter to the Job Types based on the selected Area.
I'm basing the majority of my code on this answer, but am having trouble getting the Job Types list to show in the View. I can see the correct options being appended when debugging, but am stuck on why they are not populating the Job Type dropdown list.
The View
<!--Area Dropdown-->
#Html.DropDownList("areas", null , new { #class = "col s12 m6 l3" })
<!--Job Type Dropdown-->
#Html.DropDownList("jobType", Enumerable.Empty<SelectListItem>(), "Job Type", new { #class = "col s12 m6 l3" })
The controller code, which is populating my first dropdown box (Area)
var jobArea = (from a in db.tblJobTypes
where a.Active == true
select a.Department).Distinct().ToList();
ViewData["areas"] = new SelectList(jobArea);
The POST action within the controller
[HttpPost]
public ActionResult JobTypeByArea(string area)
{
var test = (from a in db.tblJobTypes
where a.Active == true && a.Department == area
select new
{
id = a.JobTypeID,
job = a.JobType
}).ToList();
return Json(test, JsonRequestBehavior.AllowGet);
}
And finally, the JQuery
$(document).ready(function () {
$('#areas').change(function () {
$.ajax({
url: '/Home/JobTypeByArea',
type: 'POST',
data: { area: $(this).val() },
datatype: 'json',
success: function (data) {
var options = '';
var category = $('#jobType');
$.each(data, function () {
options += '<option value="' + this.id + '">' + this.job + '</option>';
});
$('#jobType').append(options);
},
});
});
});
Related
I very new to MVC and I have an issue that was real easy in webforms. I have a drop down list on a form. I have a button that loads a modal form that allows the user to add an item to the DB on the fly. I then need to update the dropdown list with the new contents of the table. I realize I need ajax to do this but I am very confused on how to initiate the update!
I have the form with the following dropdown.
<div class="form-group form-group-sm required">
#Html.LabelFor(m => m.ListingData.Transmission, new { #class = "col-md-4 control-label" })
<div class="col-md-8">
#Html.DropDownListFor(m => m.ListingData.Transmission, (SelectList)ViewBag.TransmissionList, new { #class = "form-control"} )
#Html.ValidationMessageFor(m => m.ListingData.Transmission, "", new { #class = "text-danger" })
<p class="form-text"><a data-modal='' href='#Url.Action("QATransmission", "Admin", new { ListingId = Model.ListingData.ListingId}))' id=''>Quick Add Manufacturer</a></p>
</div>
</div>
I use this ajax in the main page to call the load the list code in the controller.
$(function () {
$.ajax({
type: "GET",
url: "Admin/LoadTransmissionList",
data: JSON,
cache: false,
success: function (data) {
$.each(data, function (index, value) {
$('#Transmission').append('<option value="' + value.TransmissionText + '">' + value.TransmissionText + '</option>');
});
}
});
});
This is my controller code for the list:
[HttpPost]
public JsonResult LoadTransmissionList()
{
var lstTrans = db.Transmissions.ToList();
List<SelectListItem> list = new List<SelectListItem>();
foreach (Transmission p in lstTrans)
{
list.Add(new SelectListItem() { Value = p.TransmissionText.ToString(), Text = p.TransmissionText.ToString() });
}
return Json(list, JsonRequestBehavior.AllowGet);
}
I have a modal form and it has a text box for entering a new list item. I need to save to the DB, which works but then! I cant come up with the reload the listbox contents part. Any help!
Thanks!
1)Make your code changes like this
success: function (data) {
$('#ListingData_Transmission').html("")
$.each(data, function (index, value) {
$('#ListingData_Transmission').append('<option value="' + value.TransmissionText + '">' + value.TransmissionText + '</option>');
});
}
hope this should work now
2) Make your form as a partial view and reload it whenever your saving something to DB.
Let me know if any issues
I have a partial view which looks like this:
#model Whatever.Models.Jobs
#using (Html.BeginCollectionItem("JobRecords"))
{
<tr id="jobRow">
#Html.HiddenFor(m => m.Id)
<th width="40%">
#Html.EditorFor(m => m.Project, new { htmlAttributes = new { #class = "form-control", id = "project", list = "projectResults" } })
<datalist id="projectResults"></datalist>
#Html.ValidationMessageFor(m => m.Project, "", new { #class = "text-danger" })
</th>
</tr>
}
This is embedded in the parent view like:
#if (Model.JobRecords != null)
{
foreach (var item in Model.JobRecords)
{
Html.RenderPartial("_JobEditorRow", item);
}
}
It all works, but as you can see from the partial view I want to add a searchable box using data-list, so I add a method in my controller:
[HttpGet]
public JsonResult GetProjects(string query)
{
var list = unitOfWork.ProjectRepository.Get(c => c.Name.contains(query));
var serialized = list.Select(p => new { p.ProjectCode, p.Name});
return Json(serialized, JsonRequestBehavior.AllowGet);
}
And then add some javascript which uses AJAX to populate this data-list:
$(document).ready(function () {
var delay = 1000;
var globalTimeout = null;
function contractsCall() {
console.log("called");
$("#projectResults").empty();
$.ajax({
cache: false,
type: "GET",
contentType: "application/json;charset=utf-8",
url: "/MyController/GetProjects?query=" + $("#project").val()
})
.done(function (data) {
if (data[0] !== undefined) {
for (var i = 0; i < data.length; i++) {
$("#projectResults").append(
"<option value=" + data[i]["ProjectCode"] + ">" + data[i]["Name"] + " - " + data[i]["ProjectCode"] + "</option>"
);
}
} else {
$("#projectResults").empty();
}
});
}
$("#project").keyup(function (event) {
console.log("keyup");
if (globalTimeout !== null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function () {
globalTimeout = null;
contractsCall();
}, delay);
});
});
This javascript is included in the parent view which is also embedding the partial view. But I add a job record and type something in the input box, it doesn't do anything despite it having the id of project.
My question is, how can I register events that occur in partial views from a parent view; or if I could embed by javascript file in the partialview to fix this? And the more difficult question is, how can I prevent the duplication of ids when adding a job with BeginCollectionItem? Because adding multiple rows would add multiple project id input boxes.
Update
#Stephen helped me greatly to fix this issue, I removed the <datalist> tag from the partial view and placed it in the main view, and used class instead of id. Then I changed my JS to something like this:
$("body").on("keyup", ".projectField", function () {
var self = $(this);
if (globalTimeout !== null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function () {
globalTimeout = null;
contractsCall(self.val());
}, delay);
});
This way I can search using my AJAX call for $(this) input box. The other issue I had was seeing which input box was clicked so I can update some other things, for this I used:
document.querySelectorAll('input[list="projectResults"]').forEach(function (element) {
element.addEventListener('input', onInput);
});
Which calls:
function onInput(e) {
var input = e.target,
val = input.value;
list = input.getAttribute('list'),
options = document.getElementById(list).childNodes;
var row = $(this).closest("tr");
var p = row.find(".projDescription");
for (var i = 0; i < options.length; i++) {
if (options[i].value === val) {
$.ajax({
cache: false,
type: "GET",
contentType: "application/json;charset=utf-8",
url: "/ContractProject/GetProjects?query=" + val;
})
.done(function (data) {
if (data[0] !== undefined) {
console.log(data[0]["WorksDescription"]);
p.text(data[0]["WorksDescription"]);
}
});
break;
}
}
}
It's a little bit counter intuitive because I am making 2 AJAX calls but the second one isn't going to be heavy as it's asking for a specific element.
I'm busy with 2 drop downs. The first one is country and loads fine, then on country change I call ajax to populate the province drop down.
The code works fine and when I put an alert in my ajax call it shows the correct data being created but it doesn't append it the drop down so the values aren't available.
Drop Down
<div class="form-group">
<label class="col-md-3 col-xs-5 control-label">Country:</label>
<div class="col-md-9 col-xs-7">
#Html.DropDownListFor(x => x.CountryId, (IEnumerable<SelectListItem>)ViewBag.CountryItems, "Please Select", new { #id = "ddlCountry", #class = "form-control select" })
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-5 control-label">Province:</label>
<div class="col-md-9 col-xs-7">
#Html.DropDownListFor(x => x.ProvinceId, Enumerable.Empty<SelectListItem>(), "Please Select", new { #id = "ddlProvince", #class = "form-control select" })
</div>
</div>
The Ajax
<script>
$('#ddlCountry').change(function () {
var countries = document.getElementById("ddlCountry");
var countryId = countries.options[countries.selectedIndex].value;
$.ajax({
url: "/Master/GetProvinces",
data: { countryId: countryId },
dataType: "json",
type: "GET",
error: function () {
alert(" An error occurred.");
},
success: function (data) {
$.each(data, function (i) {
var optionhtml = '<option value="' + data[i].Value + '">' + data[i].Text + '</option>';
$("#ddlProvince").append(optionhtml);
});
}
});
});
</script>
The code behind
public ActionResult GetProvinces(string countryId)
{
IEnumerable<SelectListItem> ProvinceItems = null;
if (!string.IsNullOrEmpty(countryId))
{
ProvinceItems = BusinessAPI.ProvinceManager.GetAllProvincesByCountryId(Convert.ToInt32(countryId)).Select(ci => new SelectListItem
{
Value = ci.Id.ToString(),
Text = ci.Name
});
}
return Json(ProvinceItems, JsonRequestBehavior.AllowGet);
}
I found the problem.
I have a javascript file in there thats causing some issues.
<script type="text/javascript" src="../../Scripts/js/plugins/bootstrap/bootstrap-select.js"></script>
This came with the template I bought and it helps with the way the dropdowns and stuff works.
With that javascript file you have to add .selectpicker('refresh'); to the append to load it properly like this
$("#ddlProvince").append(optionshtml).selectpicker('refresh');
That might be slow when loading a large amount of data so just refreshing the dropdown once after everything done works well. Here is the code that works well for me now
$('#ddlCountry').change(function () {
var countries = document.getElementById("ddlCountry");
var countryId = countries.options[countries.selectedIndex].value;
$.ajax({
url: "/Master/GetProvinces",
data: { countryId: countryId },
dataType: "json",
async: true,
type: "GET",
error: function () {
alert(" An error occurred.");
},
success: function (data) {
("#ddlProvince").empty();
$.each(data, function (i) {
var optionshtml = '<option value="' + data[i].Value + '">' + data[i].Text + '</option>';
$("#ddlProvince").append(optionshtml);
});
$("#ddlProvince").selectpicker('refresh');
}
});
});
I'm testing MVC for a demo and I managed to scrap together some pieces but now I am having trouble with an Html.ActionLink. The intent is to present the user with a series of dropdownlists that they must select before the ActionLink is shown. To do that I've copied some JQuery to hide/show my dropdownlists (as selections are made) and the ActionLink. I added an alert to my JQuery to check my values and via the alert it all looks good. But if I debug the controller the parm values are defaulted to 0. I'm not sure what code to include but I will try to include the relevant parts. I think it's something basic.
Here are the dropdown lists and ActionLink.
#Html.DropDownListFor(m => m.selected_env_ID, new SelectList(Model.Environments, "env_ID", "env_DESC"), "*Select an environment")
#Html.DropDownListFor(m => m.selected_app_ID, new SelectList(Model.Applications, "app_ID", "app_DESC"), "*Select an application",new { #hidden = "hidden" })
#Html.DropDownListFor(m => m.selected_job_ID, Enumerable.Empty<SelectListItem>(), "*Select a job", new { #hidden = "hidden" })
#Html.ActionLink("Submit", "Submit", new { id = Model.selected_job_ID, envid = Model.selected_env_ID }, new {id = "lnkSubmit" })
Here is the convoluted JQuery to hide/show and fill the cascading dropdowns.
<script>
$(document).ready(function ()
{
//Dropdownlist Selectedchange event
$("#selected_app_ID").change(function () {
var id = $('#selected_app_ID').val(); // id value
if (id == 0) {
$('#selected_job_ID').hide();
} else {
$('#selected_job_ID').show();
$("#selected_job_ID").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("SelectJobs")',
dataType: 'json',
data: { id: $("#selected_app_ID").val() },
success: function (jobs) {
// jobs contains the JSON formatted list of jobs passed from the controller
$("#selected_job_ID").append('<option value=0>*Select a job</option>');
$.each(jobs, function (i, job) {
$("#selected_job_ID").append('<option value="'
+ job.job_ID + '">'
+ job.job_DESC + '</option>');
});
},
error: function (ex) {
alert('Failed to retrieve jobs.' + ex);
}
});
}
return false;
});
//ddl select change
$("#selected_env_ID").change(function () {
var name = $('#selected_env_ID option:selected').text(); //Item1
var id = $('#selected_env_ID').val(); // id value
if (id == 0) {
$('#divSubmit').hide();
$('#selected_app_ID').hide();
$('#selected_job_ID').hide();
} else {
$('#selected_app_ID').show();
}
});
//ddl select change
$("#selected_job_ID").change(function () {
var name = $('#selected_job_ID option:selected').text(); //Item1
var id = $('#selected_job_ID').val(); // id value
var envid = $('#selected_env_ID').val(); // id value
if (id == 0) {
$('#divSubmit').hide();
} else {
$('#divSubmit').show();
alert("envid=" + envid + " jobid=" + id);
}
});
}); // end document ready
</script>
My controller has this and id and envid end up being 0:
public ActionResult Submit(int id = 0,int envid = 0) {
If I need to include something else just let me know.
Here is the method that fills the job dropdown list. This works without issues. It's the Html.ActionLink call to Submit that fails to include the parameters.
public JsonResult SelectJobs(int id)
{
db.Configuration.ProxyCreationEnabled = false;
IEnumerable<t_job> jobs = db.t_job.Where(j => j.app_ID == id).ToList();
return Json(jobs);
}
Your link
#Html.ActionLink("Submit", "Submit", new { id = Model.selected_job_ID, envid = Model.selected_env_ID }, new {id = "lnkSubmit" })
is rendered on the server side before you make any selection in the dropdowns. If the initial values of selected_job_ID and selected_env_ID are zero or null, then those values will be passed to the controller (have a look at the rendered html).
If you want to pass the values selected in you drop downs, you could either modify the links href attribute in the drop down change events, or create a button instead of a link, and do a redirect in the buttons click event based on the dropdown values.
You need to use JSON.stringify():
data: JSON.stringify({ id: $("#selected_app_ID").val() }),
I have been trying to cascade dropdown lists. For this purpose I am using javascript in .cshtml page . Don't know what is the reason , I'm not able to even call Js method , leave alone the controller method which later needs to be called from within the Js method. Dropdowns are fetching the state and city data but I'm not getting the city according to the state selected.
<div class="editor-label">
#Html.LabelFor(model => model.State_Id)
</div>
<div class="editor-field">
#Html.DropDownList("State",null,"Select State", new {#class="span4", id="State"})
#Html.ValidationMessageFor(model => model.State_Id)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CityId)
</div>
<div class="editor-field">
#Html.DropDownList("City",null,"Select City", new {#class="span4", id="City"})
#Html.ValidationMessageFor(model => model.CityId)
</div>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript" >
$(document).ready(function(e) {
$("#State").change(function (e) {
var selectedValue = $(this).val();
if(selectedValue != "Select") {
$.ajax({
url: '#Url.Action("GetCities","Employer")',
type: 'Post',
//data: { "selectedValue": selectedValue},
data: {id: $("#State").val()},
dataType: 'json',
success: function(response) {
var items = "";
$.each(response, function(i, city) {
$("#City").append('<option value="' + city.Value + '">' + city.Text + '</option>');
});
},
error: function (ex) {
alert("Failed To Receive States" + ex);
}
});
}
});
});
</script>
#Html.DropDownListFor(x => x.LeagueId, Model.LeagueSL, "--Select League--", new { id = "ddlLeague"})
#Html.DropDownListFor(x => x.LeagueId, Model.DivisionSL, "--Select Division--", new { id = "ddlDivision"})
The Second DropDownList is empty, all it has is the option Label --Select Division--
On change event of the 1st dropdown make an AjaxRequest that fills the Second One.
var value = $("#DropDown1").val();
var ddlDivision = $("#DropDownDivision");
ddlDivision.html('');//clear current contents;
$.ajax({
url: "/Home/GetDivisions",
type: "GET",
data: { leagueId: value },
success: function (data) {
$.each(data, function (index, item) {
//item = this
//populate ddl
ddlDivision.append($('<option></option>')
.val(item.PropTwo)
.html(item.PropOne));
});
});
public JsonResult GetDivisions(int leagueId)
{
using (BaseballEntities context = new BaseballEntities())
{
var divisions = (from x in context.Table
where x.LeagueID == leagueId
select new
{
PropOne = x.DivisionName,
PropTwo = x.DivisionId
}).ToList();
return Json(divisions, JsonRequestBehavior.AllowGet);
}
}
Edit: As a Side Note it is better to use your Model to fill your dropdownList.
Give your model a SelectList property
public List<SelectListItem> LeagueSL { get; set; }//you will need to initialize in constructor
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
using (MyEntities context = new MyEntities())
{
var leagueList = context.League.ToList();
foreach (var item in leagueList)
{
model.LeagueSL.Add(new SelectListItem() { Text = item.LeagueName, Value = item.LeagueId.ToString() });
}
}
return View(model);
}
Drop down lists are their own beast. You probably need to create the new OPTIONs using standard DOM methods inside the loop rather than jQuery's append method:
success: function(response) {
var items = "", option, $city = $("#City");
$.each(response, function(i, city) {
option = document.createElement("option");
option.value = city.Value;
option.innerHTML = city.Text;
$city.append(option);
});
},