Populate provinces for selected country on dynamically added elements - javascript

Contacts are created dynamically (added or deleted). For each contact created, a country must be selected and the provinces for that country must be loaded via ajax.
Parent element
#contacts
Child elements
#contacts_0_country
#contacts_0_provinces
#contacts_1_country
#contacts_1_provinces
etc
Everything works perfectly except that i have to switch the country selection twice for the ajax to take charge and change the provinces for the country selected
This problem is due to below js but i cant find it:
(function ( $ ) {
'use strict';
$(document).ready(function() {
$('#contacts').on("change", [$('select')],function() {
$("select[id^='contacts'][id$='_country']").each(function() {
var id = parseInt(this.id.match(/\d+/), 10);
var $country = $("#contacts_" + id + "_country");
var $province = $("#contacts_" + id + "_provinces");
// When country gets selected ...
$country.on('change',["#contacts_" + id + "_country"], function () {
// ... retrieve the corresponding form
var $form = $(this).closest('form');
// Simulate form data, but only include the selected value
var data = {};
data[$country.attr('name')] = $country.val();
// Submit data via AJAX to the form's action path
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current province field ...
$("#contacts_" + id + "_provinces").replaceWith(
// ... with the returned one from the AJAX response
$(html).find("#contacts_" + id + "_provinces")
);
// Province field now displays the appropriate provinces
}
});
});
});
});
});
})( jQuery );

I found an answer to my own question. Below is now working perfectly. Provinces are populated for the relevant country selected and this also works on new contacts added dynamically on the collection
(function ( $ ) {
'use strict';
$(window).load(function() {
$('#contacts').on("click", [$('select')], function(event) {
var $id = event.target.id;
var id = parseInt($id.match(/\d+/), 10);
var $country = ('#' + $id);
var $country = $($country);
var $form = $country.closest('form');
// Simulate form data, but only include the selected value
var data = {};
data[$country.attr('name')] = $country.val();
// Submit data via AJAX to the form's action path
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current province field ...
$("#contacts" + id + "_provinces").replaceWith(
// ... with the returned one from the AJAX response
$(html).find("#contacts" + id + "_provinces")
);
// Province field now displays the appropriate provinces
}
});
//});
});
});
})( jQuery );
I hope it helps someone!

Related

Amend existing jQuery ajax function to retrieve latest inserted value from json and mark as selected

Here's the workflow of my form:
Display form with input and select elements >> all of the select elements have a button to add new data via a modal window that performs a database insert via ajax and closes the modal window >> on modal close, I fire the refreshData() function which pulls in the new data from json into the select elements of the form.
All of the above is working great, but how do I mark the correct option (last added via modal window) in the refreshSelect() function below? For example: I add a new supplier to my database via modal window, it inserts correctly to the DB, but how do I mark that new supplier as selected after modal window close?
Here's a sample of the json data I'm working with:
{"suppliers":{"1":"Amazon","2":"Lenovo"},"manufacturers":{"1":"Apple","2":"Lenovo"},"categories":{"2":"Tablet"},"status":{"1":"Ready to Deploy","2":"Deployed","3":"Damaged"}}
jQuery function that will pull data from json via ajax and refresh the select elements on the page:
$(document).ready(function() {
// Initial load
refreshData();
});
function refreshData(newId) {
$.ajax({
url: '/json/collection.json',
type: 'GET',
dataType: 'json',
success: function(data) {
refreshSelect('inputSupplier', data.suppliers, newId);
refreshSelect('inputManufacturer', data.manufacturers, newId);
refreshSelect('inputStatus', data.status, newId);
refreshSelect('inputCategory', data.categories);
refreshSelect('inputManufacturerModel', data.manufacturers, newId); //modal window select
}
});
}
function refreshSelect(name, data, newId) {
// Select by id
let $elem = $('#' + name);
// Get current value
let oldValue = $elem.val();
// Get "template" value with value 0, which is the first element
let emptyOption = $elem.children('option').first();
// Empty the element and add the option. We are back to initial state
$elem.html(emptyOption);
// Append elements retrieved from backend
$.each(data, function(key, value) {
$elem.append('<option value="' + key + '">' + value + '</option>');
});
if(newId){
$elem.val(newId);
}else{
$elem.val(oldValue);
}
}
Function that will insert new values to the database via ajax from the modal window (Very basic):
$(document).ready(function ()
{
$('.modal-submit').on('submit', function(e){
e.preventDefault(); //prevent default form submit action
$(".backend-error").html(''); //clear out previous error messages
$('input').removeClass('input-error'); //clear error border class
var data = $(this).serialize();
var type = $(this).find('input[name="type"]').val();
switch(type){
case "supplier":
var url = '{{ action('AddAssetController#addDescriptor', ['type' => 'supplier']) }}';
var modalName = '#supplierModal';
var modalInput = '#inputSupplierNew';
break;
case "manufacturer":
var url = '{{ action('AddAssetController#addDescriptor', ['type' => 'manufacturer']) }}';
var modalName = '#manufacturerModal';
var modalInput = '#inputManufacturerNew';
break;
case "model":
var url = '{{ action('AddAssetController#addDescriptor', ['type' => 'model']) }}';
var modalName = '#modelModal';
var modalInput = '#inputModelNew';
break;
case "status":
var url = '{{ action('AddAssetController#addDescriptor', ['type' => 'status']) }}';
var modalName = '#statusModal';
var modalInput = '#inputStatusNew';
break;
case "category":
var url = '{{ action('AddAssetController#addDescriptor', ['type' => 'category']) }}';
var modalName = '#categoryModal';
var modalInput = '#inputCategoryNew';
break;
}
$.ajax({
url:url,
method:'POST',
data:data,
success:function(response){
refreshData(newId = response.id); // set newId to the id of the newly inserted item
$(modalName).modal('hide'); //hide modal
$(modalInput).val(''); //clear input value
},
error:function(e){
//console.log(error.responseJSON.error)
//console.warn(error.responseJSON.error);
$.each(e.responseJSON.error, function (i, error) {
$(modalInput).addClass('input-error');
$(modalName + ' .backend-error').html(error[0]); //return error from backend
});
}
});
});
});
Edit: Revised code added
You can pass the required new value to be set to select box from your ajax POST's success handler to your refreshData() call and ultimately to your refreshSelect() function as follows:
Save Data Call:
var data = $(this).serialize();
console.log(data);
/*TODO*/
var newSupplierId = <logic to get ID/Name of newly added supplier>;
var url = '{{ action('AddAssetController#addAttribute', ['type' => 'supplier']) }}';
$.ajax({
url:url,
method:'POST',
data:data,
success:function(response){
if(response.success){
refreshData(newSupplierId); //passing newSupplierId to refreshData function
$('#supplierModal').modal('hide');
$('#inputSupplierNew').val('');
console.log(response);
}else{
alert('There was an error inserting data. Please try again.')
}
},
error:function(error){
console.log(error)
}
});
Other modified code:
function refreshData(newSupplierId) {
$.ajax({
url: '/json/collection.json',
type: 'GET',
dataType: 'json',
success: function(data) {
refreshSelect('inputSupplier', data.suppliers, newSupplierId);
refreshSelect('inputManufacturer', data.manufacturers);
refreshSelect('inputStatus', data.status);
refreshSelect('inputCategory', data.categories);
refreshSelect('inputManufacturerModel', data.manufacturers); //modal window select
}
});
}
function refreshSelect(name, data, newSupplierId) {
// Select by id
let $elem = $('#' + name);
// Get current value
let oldValue = $elem.val();
// Get "template" value with value 0, which is the first element
let emptyOption = $elem.children('option').first();
// Empty the element and add the option. We are back to initial state
$elem.html(emptyOption);
// Append elements retrieved from backend
$.each(data, function(key, value) {
$elem.append('<option value="' + key + '">' + value + '</option>');
});
if(newSupplierId) // check whether newSupplierId is null or not
{
//if newSupplierId is not null means select newly added supplier
$elem.val(newSupplierId);
}
else{
// Restore selection
$elem.val(oldValue);
}
}
Hope this will help you.

jquery multilevel select list

i have problem with my multilevel dependent select lists, i have six select lists dependent on each other and i have write a code to create dynamic lists using jquery. selects named as district, tehsil, project, center, school and user. it is working fine when i choose all options in a sequence, district-> tehsil-> project -> center -> school -> user, and when i change sequence at any level like district -> tehsil -> district( here district is parent of tehsil) after clicking on parent child tehsil not refreshed, and this problem exist in all hierarchy.... this jquery code calls 6 controller and models. those are not include here due to length of question. what should i do ?
this is my jquery code
$('#districts_id,#tehsils_id,#projects_id,#centers_id,#schools_id').on('change', function() {
//alert($("#districts_id option:selected").attr("title"));
//var parameters = {};
var parameters;
var url;
if($('#schools_id').val())
{
$("#users_id").removeAttr('disabled');
//parameters = JSON.stringify({schools_centers_id:$('#centers_id').val()});
parameters = {"users_schools_id": $('#schools_id').val(), users_gender: $('#gender').val()};
url = "<?php echo base_url();?>/BtaAdministratorUnionMembers/get_teachers_users_by_school_id";
}
else if($('#centers_id').val())
{
$("#schools_id").removeAttr('disabled');
//parameters = JSON.stringify({schools_centers_id:$('#centers_id').val()});
parameters = {"schools_centers_id": $('#centers_id').val()};
url = "<?php echo base_url();?>/BtaAdministratorUsers/get_schools_by_center_id";
}
else if($('#projects_id').val())
{
$("#centers_id").removeAttr('disabled');
//parameters = JSON.stringify({centers_probject_id:$('#projects_id').val()});
parameters = {"centers_probject_id": $('#projects_id').val()};
url = "<?php echo base_url();?>/BtaAdministratorUsers/get_centers_by_project_id";
}
else if($("#tehsils_id option:selected").attr("title") == 'tehsils_id')//($('#tehsils_id').val())
{
$("#projects_id").removeAttr('disabled');
//parameters = JSON.stringify({projects_tehsil_id:$('#tehsils_id').val()});
parameters = {"projects_tehsil_id": $('#tehsils_id').val()};
url = "<?php echo base_url();?>/BtaAdministratorUsers/get_projects_by_tehsil_id";
//alert(parameters + ' '+ url);
}
else if($("#districts_id option:selected").attr("title") == 'districts_id')//($('#districts_id').val())
{
$("#tehsils_id").removeAttr('disabled');
//$("#tehsils_id").empty();
//parameters = JSON.stringify({tehsils_districts_id:$('#districts_id').val()});
parameters = {"tehsils_districts_id": $('#districts_id').val()};
url = "<?php echo base_url();?>/BtaAdministratorUsers/get_tehsils_by_districts_id";
//alert(parameters + ' '+ url);
}
$.ajax({
type: "GET",
url: url,
data:parameters,
//contentType: "application/json;charset=utf-8",
dataType: 'json',
success: function(data){
//alert(data);
//alert(JSON.stringify(data));
if($('#schools_id').val())
{
//alert(JSON.stringify(data));
$('#users_id').empty();
$('#users_id').append("<option value=''>Select Teacher....</option>");
$.each(data,function(key,value){
$('#users_id').append('<option value="'+value.users_id+'">'+value.users_firstname_users_lastname+'</option>');
});
}
else if($('#centers_id').val())
{
//alert(JSON.stringify(data));
$('#schools_id').empty();
$('#schools_id').append("<option value=''>Select School....</option>");
$.each(data,function(key,value){
$('#schools_id').append('<option value="'+value.schools_id+'">'+value.schools_name+'</option>');
});
}
else if($('#projects_id').val())
{
//alert(JSON.stringify(data));
$('#centers_id').empty();
$('#centers_id').append("<option value=''>Select Center....</option>");
$.each(data,function(key,value){
$('#centers_id').append('<option value="'+value.centers_id+'">'+value.centers_schoolName+'</option>');
});
}
else if($("#tehsils_id option:selected").attr("title") == 'tehsils_id')//($('#tehsils_id').val())
{
//alert(JSON.stringify(data));
$('#projects_id').empty();
$('#projects_id').append("<option value=''>Select Project....</option>");
$.each(data,function(key,value){
$('#projects_id').append('<option value="'+value.projects_id+'">'+value.projects_name+'</option>');
});
}
else if($("#districts_id option:selected").attr("title") == 'districts_id')//($('#districts_id').val())
{
//clearDropDown($('select'), 5);
$('#tehsils_id').empty();
$('#tehsils_id').append("<option value='' title=tehsils_id>Select Tehsils....</option>");
$.each(data,function(key,value){
$('#tehsils_id').append('<option value="'+value.tehsils_id+'" title=tehsils_id>'+value.tehsils_name+'</option>');
});
}
},
error: function(data){
alert(JSON.stringify(data));
//console.log(data);
}
});
});
In each level you have to remove all next options when a top level option is changed and the set the next level again e.g in school level:
$('#schools_id').nextAll("select").each(function(){
$(this).find('option').remove();
})
// Then set again the next level
I used nextAll assuming that selects are siblings. elsewhere you have to use propper selector
With all of your if else statements organized from the most specific to least specific, fiddling with a parent input triggers the event handler but is caught by the else statement for its child.
Use separate event handlers for all six inputs based on the one you are interacting with rather than checking for values alone, and your logic will work morelike you planned.
You'll even be able to more easily handle the case where the user is jumping back a few levels and you should reset/disable a few selects.

On page load call change of events for both dropdown

On first time page load, help text and announcements are displayed, on refresh after validation the help text and announcement don't show again on the view. I think I need to on page load call change event for both drop down, I'm not quiet sure how to do this. The first dropdown Div id is #profession and the second drop down is div id is #enquirytype.
$('#profession').on('change', function (e) { //Gets the ID of profession drop down list
var selectedVal = $(this).val(); //Variable selectedVal this . value
$.ajax({ //Ajax declared
type: 'GET', //Its a get
url: "#Url.Action("GetenquiryTypes", "UnauthEnquiry")", //It goes to the enquiry controller method GetenquiryTypes
dataType: 'json', //Datatypes JSON
data: { SelectedProfession: selectedVal }, //data is SelectedProfession: selectedVal
success: function (json) { //Jquery Parse Json data from server on ajax success
if (json.helptext != undefined && json.helptext != '')
{
$('#ProfHelp').html(json.helptext)
$('#ProfHelpAlert').show(); ///////
}
else
$('#ProfHelpAlert').hide(); ///////
var targetDropdown = $('#enquirytype') //Var targetDropDropdown goes to dropdown ID enquiry type
targetDropdown.empty(); //target empty dropdown
$("<option />", {
val: "",
text: "Please select enquiry type" //Select enquiry type
}).appendTo(targetDropdown); //add to the target dd
if (json.enquiryTypes.length > 0) { //if JASON data from server greater then 0
for (var EnquiryType in json.enquiryTypes) { //go through each EnquiryType in JSON
$("<option />", {
val: json.enquiryTypes[EnquiryType].EnquiryId, //mapping
text: json.enquiryTypes[EnquiryType].Enquiryname //mapping
}).appendTo(targetDropdown); //add to drop down
};
}
targetDropdown.change();
}
});
});
$('#enquirytype').on('change', function (e) { //onlick of professions DD
var selectedVal = $(this).val(); //Variable selectedVal this .value
$('#enquiryTypeHelpAlert').hide(); ///////
$('#EnquiryTypeAnnouncements').empty();
if (selectedVal != undefined && selectedVal != '') {
$.ajax({
type: 'GET', //Get
url: "#Url.Action("GetEnquiryTypeAndAnnoncements", "UnauthEnquiry")", //It goes to the enquiry controller method GetenquiryTypes
dataType: 'json', //Datatypes JSON
data: { SelectedEnquiryType: selectedVal }, //data is SelectedProfession: selectedVal
success: function (json) { //Jquery Parse Json data from server on ajax success
if (json.helptext != undefined && json.helptext != '') {
$('#enquiryTypeHelp').html(json.helptext)
$('#enquiryTypeHelpAlert').show(); ///////
}
else
$('#enquiryTypeHelpAlert').hide(); ///////
var announcement = $('.EnquiryTypeAnnouncement:first').clone();
$('#EnquiryTypeAnnouncements').empty();
$('#enquiryTypeHelp').html(json.helptext);
for (var i in json.announcements) {
var announcementCopy = announcement.clone();
announcementCopy.find(".notification").html(json.announcements[i]);
$(announcementCopy).appendTo($('#EnquiryTypeAnnouncements')).show();
$('#EnquiryTypeAnnouncements').show();
}
}
});
}
});
That seems correct as on change will keep your DD help text loaded.
$(document).ready(function () {
$('#profession').change(); //Keeps profession dropdown list help text displayed
});
As its not in the Jquery you have to get it from the model.
var EnquiryType ='#Model.EnquiryType
Then get it in the change event.
In the beginning of ypur script call your Professions dropdown in a function such as
$(document).ready(function () {
$('#profession').change(); //Keeps profession dropdown list help text displayed
});
Next as the enquiry type is not available in Jquery. you have get that from Model. By using
var EnquiryType ='#Model.EnquiryType
Then get it in the change event.

Filtering Selection from AJAX Call

What I want to do is, I want to display the selection that registered under accType=Acc1 in Selection. The AccInfo function is my ajax call. I would like to pass the parameter in data. The Acc_response function is a function to operate the option value. I would like to show the branchCode,accType,Code, that is registered under Acc1. How can I do that?
function AccInfo(Acc1){
$.ajax({
type:"POST",
datatype:"json",
async:true,
data:{A:Acc1},
url:AccInfo_url,
success: function(data){
Acc_response(data);
},
error: function(jqXHR, textStatus){
errorHandling(textStatus);
}
})
}
function Acc_response(data){
console.log(data);
for (var i=0;i<data.ClientInfo.length;i++)
{
var $option=$('<option />');
$option.attr('value', data.ClientInfo[i].branchCode+"|"+data.ClientInfo[i].Code+"|"+data.ClientInfo[i].accType);
$option.text(data.ClientInfo[i].accType+" (" + data.ClientInfo[i].Code+"-"+data.ClientInfo[i].branchCode+") ";
$('#Selection').append($option);
}
}
This is more usefull;
var selectedAccType = 'your account type';
//you can set this at post action to
function Acc_response(data){
data.ClientInfo.forEach(function(client) {
if(client.accType==selectedAccType){
var optionValue = client.branchCode+'|'+client.Code+'|'+client.accType;
var optionText = client.accType+'('client.Code+'-'+client.branchCode+')';
var option = '<option value="'+optionValue+'">'+optionText+'</option>';
$('#Selection').append(option);
}
});
}
This works for if you have one <select>. If you have more selects send us your html code.

jQuery UI token

I have followed this tutorial which uses jQuery UI to generate Facebook tokens like:
http://net.tutsplus.com/tutorials/javascript-ajax/how-to-use-the-jquery-ui-autocomplete-widget/
My problem is I need to pass two values thru JSON: the ID and the NAME.
the server side script looks like this:
header('Content-Type: text/html; charset=iso-8859-1', true);
include($_SERVER['DOCUMENT_ROOT'].'/inrees/inrees/communaute/includes/_db.php');
$param = $_GET["term"];
$query = mysql_query("SELECT * FROM comm_carnet, in_emails
WHERE carnet_iduser=emails_id
AND emails_id!='".$_COOKIE['INREES_ID']."'
AND emails_nom REGEXP '^$param'");
//build array of results
for ($x = 0, $numrows = mysql_num_rows($query); $x < $numrows; $x++) {
$row = mysql_fetch_assoc($query);
$friends[$x] = array("name" = > $row["emails_nom"], "id" = > $row["emails_id"]);
}
//echo JSON to page
$response = $_GET["callback"]."(".json_encode($friends).")";
echo $response;
the echo from the server side script is:
([{"name":"dupont","id":"34998"},{"name":"castro","id":"34996"},{"name":"castelbajac","id":"34995"}])
(which is exactly what I need)
I am passing the the "name" array but not the "id" which needs to be a hidden input with the corresponding id from the database, the html page where the call to the php is done looks like this:
//attach autocomplete
$("#to").autocomplete({
//define callback to format results
source: function (req, add) {
//pass request to server
$.getJSON("messages_ajax.php?callback=?", req, function (data) {
//create array for response objects
var suggestions = [];
//process response
$.each(data, function (i, val) {
suggestions.push(val.name);
});
//pass array to callback
add(suggestions);
});
},
//define select handler
select: function (e, ui) {
//create formatted friend
var friend = ui.item.value,
span = $("<span>").text(friend),
a = $("<a>").addClass("remove").attr({
href: "javascript:",
title: "Remove " + friend
}).text("x").appendTo(span);
$("<input />", {
value: "id",
type: "hidden",
name: "id"
}).appendTo(span);
//add friend to friend div
span.insertBefore("#to");
},
//define select handler
change: function () {
//prevent 'to' field being updated and correct position
$("#to").val("").css("top", 2);
}
});
//add click handler to friends div
$("#friends").click(function () {
//focus 'to' field
$("#to").focus();
});
//add live handler for clicks on remove links
$(".remove", document.getElementById("friends")).live("click", function () {
//remove current friend
$(this).parent().remove();
//correct 'to' field position
if ($("#friends span").length === 0) {
$("#to").css("top", 0);
}
});
so is basically where you see the comment: "//define select handler" that something needs to be done but I can't do it!
I added the line:
$("<input />", {value:"id", type:"hidden", name:"id"}).appendTo(span);
but it does not fetch my array "id".
your code should be:
UPDATE With DEMO
$(function() {
$("#to").autocomplete({
//define callback to format results
source: function(req, add) {
//pass request to server
$.getJSON("json.json", req,
function(data) {
add($.map(data,
function(item) {
return {
id: item.id,
label: item.name,
value: item.name
}
}));
});
},
//define select handler
select: function(e, ui) {
$('<a class="del_friend" href="#' + ui.item.id + '" title="remove">' + ui.item.label + '<span>x</span>' +
'<input name="friend[]" type="hidden" id="friend_' + ui.item.id + '" value="' + ui.item.id + '" /></a>').insertBefore('#to');
},
//define select handler
change: function() {
$("#to").val("");
}
});
//delete friends
$('a.del_friend').live('click', function(e) {
e.preventDefault();
var friend_id = this.hash.split('#')[1];
alert(friend_id); //AJAX Call and delete item by it's ID
$(this).fadeOut(500).remove()
});
});
NOTE: this assuming your json code look like:
[{"name":"dupont","id":"34998"},{"name":"castro","id":"34996"},{"name":"castelbajac","id":"34995"}]
USEFULL READS: http://jqueryui.com/demos/autocomplete/#remote-jsonp
So, it looks like you're adding only the names to the suggestions list, not the entire data object which would contain the name and id members. Instead of doing this:
suggestions.push(val.name)
try pushing the entire data object onto the list you're passing to your callback:
suggestions.push(val)
Then, in your callback, ui.item.value will contain the full data member, so you'll need to change your code around a bit. To access the name and id values separately, you could presumably do something like this:
var friendName = ui.item.value.name;
var friendID = ui.item.value.id;
Then, you can use those variables where you need to (friend becomes friendID, and instead of passing {value:"id" ...} to the hidden input, you could do {value:friendID ...}

Categories