I have a dropdown who populate depending of selected radio button:
JS
$(function getJsonProveedores() {
var items = "";
$('input[type=radio][name=editList]').change(function () {
if (this.value == 'Proveedor') {
$.getJSON("#Url.Action("GetProveedores", "Agenda")", function (data) {
$.each(data, function (index, item) {
items += "<option value='" + item.ID + "'>" + item.NombreComercial + "</option>";
});
$("#lstProveedor").html(items);
});
}
else if (this.value == 'Sucursal') {
$.getJSON("#Url.Action("GetUnidades", "Agenda")", function (data) {
$.each(data, function (index, item) {
items += "<option value='" + item.ID + "'>" + item.Nombre + "</option>";
});
$("#lstProveedor").html(items);
});
} else if (this.value == 'Usuario') {
$.getJSON("#Url.Action("GetUsuario", "Agenda")", function (data) {
$.each(data, function (index, item) {
items += "<option value='" + item.ID + "'>" + item.Nombre + "</option>";
});
$("#lstProveedor").html(items);
});
}
});
});
It load correctly all JSON, but I have an issue removing last query, for example if i click Proveedor radio, it load:
$.getJSON("#Url.Action("GetProveedores", "Agenda")"
and next if I click Sucursal radio, it load
$.getJSON("#Url.Action("GetUnidades", "Agenda")"
The problem is I keep seeing first query result of
$.getJSON("#Url.Action("GetProveedores", "Agenda")"
instead getting only second one:
$.getJSON("#Url.Action("GetUnidades", "Agenda")"
Controller:
public ActionResult GetProveedores()
{
var listaProveedores = db.Proveedores.ToList();
return Json(listaProveedores, JsonRequestBehavior.AllowGet);
}
public ActionResult GetUnidades()
{
var listaUnidades = db.Unidades.ToList();
return Json(listaUnidades, JsonRequestBehavior.AllowGet);
}
public ActionResult GetUsuario()
{
var listaUsuarios = db.Usuarios.ToList();
return Json(listaUsuarios, JsonRequestBehavior.AllowGet);
}
What can be the problem there? Regards
The way the functions/variables are structured, items never falls out of scope. So it never gets reset. Each subsequent AJAX call is simply appending to it.
Instead, get rid of the items variable from its current scope and use one local to each scope where you need it:
$(function getJsonProveedores() {
$('input[type=radio][name=editList]').change(function () {
if (this.value == 'Proveedor') {
$.getJSON("#Url.Action("GetProveedores", "Agenda")", function (data) {
var items = ""; // <--- declare it here
$.each(data, function (index, item) {
items += "<option value='" + item.ID + "'>" + item.NombreComercial + "</option>";
});
$("#lstProveedor").html(items);
});
}
else if (this.value == 'Sucursal') {
// ... and so on, declaring an "items" in each scope where you need it
Related
I've got a form that has a few select elements populated by JSON. It looks something like below.
{
"suppliers":
{"1":"Amazon","2":"Apple"},
"manufacturers":
{"1":"Apple","2":"Lenovo"},
"categories":
{"2":"Tablet","3":"Laptop","4":"Desktop"},
"status":
{"1":"Ready to Deploy","2":"Deployed","3":"Damaged","4":"Destroyed"}
}
How can I sort by value (name) instead of the key (id)? I've tried everything I can think of and I've searched every phrase I can think of, but it's still not sorting alphabetically like I need. Note the orderBy below will sort it in the correct order if viewing the JSON directly in the browser, but in the form my select elements are still ordered by key.
public function getFormData()
{
$suppliers = DB::table('supplier')->orderBy('sup_name','asc')->pluck('sup_name','id');
$manufacturers = DB::table('manufacturer')->orderBy('man_name','asc')->pluck('man_name','id');
$categories = DB::table('category')->where('parent_id', 1)->orderBy('cat_name','asc')->pluck('cat_name', 'id');
$status = DB::table('status')->orderBy('status','asc')->pluck('status', 'id');
return json_encode(compact('suppliers', 'manufacturers', 'categories', 'status'));
}
Edit:
Using the following syntax from #Snapey I was able to get the sort order correct
public function getFormData()
{
$suppliers = DB::table('supplier')->orderBy('sup_name','asc')->get(['sup_name','id']);
$manufacturers = DB::table('manufacturer')->orderBy('man_name','asc')->get(['man_name','id']);
$categories = DB::table('category')->where('parent_id', 1)->orderBy('cat_name','asc')->get(['cat_name', 'id']);
$status = DB::table('status')->orderBy('status','asc')->get(['status', 'id']);
return json_encode(compact('suppliers', 'manufacturers', 'categories', 'status'));
}
New output:
{
"suppliers":
[{"sup_name":"Amazon","id":1},{"sup_name":"Apple","id":2}],
"manufacturers":
[{"man_name":"Apple","id":1},{"man_name":"Lenovo","id":2}],
"categories":
[{"cat_name":"Desktop","id":4},{"cat_name":"Laptop","id":3},{"cat_name":"Tablet","id":2}],
"status":
[{"status":"Damaged","id":3},{"status":"Deployed","id":2},{"status":"Destroyed","id":4},{"status":"Ready to Deploy","id":1}]
}
Unfortunately, now I get "object Object" in my select elements and the values are off.
Here's the function that builds my select elements:
function refreshData(newId, modalId) { //refreshes select elements on update
$.ajax({
url: '/json/collection.json',
type: 'GET',
dataType: 'json',
success: function(data) {
if(modalId){
switch(modalId){
case "supplierModal":
refreshSelect('inputSupplier', data.suppliers, newId);
break;
case "manufacturerModal":
refreshSelect('inputManufacturer', data.manufacturers, newId);
refreshSelect('inputManufacturerModel', data.manufacturers, newId); //modal window select
break;
case "statusModal":
refreshSelect('inputStatus', data.status, newId);
break;
case "categoryModal":
refreshSelect('inputCategory', data.categories, newId);
break;
}
}else{
refreshSelect('inputSupplier', data.suppliers);
refreshSelect('inputManufacturer', data.manufacturers);
refreshSelect('inputStatus', data.status);
refreshSelect('inputCategory', data.categories);
refreshSelect('inputManufacturerModel', data.manufacturers); //refresh modal window select element
}
}
});
}
function refreshSelect(name, data, newId) {
// Select by id
let $elem = $('#' + name);
// Get current value
let oldValue = $elem.val();
// Get option 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) {
if(oldValue === key || newId === key){
$elem.append('<option value="' + key + '" selected="selected">' + value + '</option>');
}else{
$elem.append('<option value="' + key + '">' + value + '</option>');
}
});
if(newId){
$elem.val(newId);
}else{
$elem.val(oldValue);
}
}
Include the id as a named element rather that using it as the array index. For instance;
$suppliers = DB::table('supplier')->orderBy('sup_name','asc')->get(['sup_name','id']);
then in the json you will have an id attribute
Edit: for your additional question
something like
$.each(data, function(key, value) {
if(oldValue === value.id || newId === value.id){
$elem.append('<option value="' + value.id + '" selected="selected">' + value.sup_name + '</option>');
}else{
$elem.append('<option value="' + value.id + '">' + value.sup_name + '</option>'); } });
because now, each item in the array is an object with sup_name and id as attributes
The following will strip the key numbers out, and just leave you with an array that has your new ordering:
public function getFormData()
{
$suppliers = DB::table('supplier')->orderBy('sup_name','asc')->pluck('sup_name','id');
$suppliers = array_values($suppliers);
$manufacturers = DB::table('manufacturer')->orderBy('man_name','asc')->pluck('man_name','id');
$manufacturers = array_values($manufacturers);
$categories = DB::table('category')->where('parent_id', 1)->orderBy('cat_name','asc')->pluck('cat_name', 'id');
$categories = array_values($categories);
$status = DB::table('status')->orderBy('status','asc')->pluck('status', 'id');
$status = array_values($status);
return json_encode(compact('suppliers', 'manufacturers', 'categories', 'status'));
}
I have a library which looks like the following
(function (bindDropdownAndSetValue) {
function allFunction() {
function bindDropDownValue(response, dropdownObject) {
$.each(response, function (i, e) {
$('#' + dropdownObject.id).append('<option value=' + e[dropdownObject.value] + '>' + e[dropdownObject.text] + '</option>');
});
}
function dropdownValues(id, value, text) {
this.id = id;
this.value = value;
this.text = text;
}
}
bindDropdownAndSetValue.allFunction = allFunction;
} (bindDropdownAndSetValue));
in the above example when I call bindDropdownAndSetValue.allFunction I want to excess the functions inside allFunction but it didn't appear to work
and when I changed the library to like the following
(function (bindDropdownAndSetValue) {
function bindDropDownValue(response, dropdownObject) {
$.each(response, function (i, e) {
$('#' + dropdownObject.id).append('<option value=' + e[dropdownObject.value] + '>' + e[dropdownObject.text] + '</option>');
});
}
function dropdownValues(id, value, text) {
this.id = id;
this.value = value;
this.text = text;
}
bindDropdownAndSetValue.bindDropDownValue = bindDropDownValue;
bindDropdownAndSetValue.dropdownValues = dropdownValues;
} (bindDropdownAndSetValue));
this works fine, but the problem here is that I need to right extra line of code, to assign function one by one to bindDropdownAndSetValue.
Is there any other better way to right this code?
Keep it short and simple:
bindDropdownAndSetValue.bindDropDownValue = function(response, dropdownObject) {
$.each(response, function (i, e) {
$('#' + dropdownObject.id).append('<option value=' + e[dropdownObject.value] + '>' + e[dropdownObject.text] + '</option>');
});
};
bindDropdownAndSetValue.dropdownValues = function(id, value, text) {
this.id = id;
this.value = value;
this.text = text;
};
(function (bindDropdownAndSetValue) {
function bindDropDownValue(response, dropdownObject) {
$.each(response, function (i, e) {
$('#' + dropdownObject.id).append('<option value=' + e[dropdownObject.value] + '>' + e[dropdownObject.text] + '</option>');
});
}
function dropdownValues(id, value, text) {
this.id = id;
this.value = value;
this.text = text;
}
Object.assign(bindDropdownAndSetValue, {bindDropDownValue, dropdownValues });
} (bindDropdownAndSetValue));
I've a form when I click one radio button to load a subform.
Ok this work perfectly, but has 3 selectors that I need external data when only this subform loaded.
So, I did in this way:
$(document).on('focus', '#reemb', function () {
$.getJSON("/banks.php", function (json) {
$('#bank').empty();
$.each(json, function (i, obj) {
$('#bank').append($('<option>').text(obj.name).attr('value', obj.code));
});
});
$.getJSON('/statecity.json', function (data) {
var items = [];
var options = '<option value="">State</option>';
$.each(data, function (key, val) {
options += '<option value="' + val.name + '">' + val.name + '</option>';
});
$("#state").html(options);
$("#state").change(function () {
var options_city = '';
var str = "";
$("#state option:selected").each(function () {
str += $(this).text();
});
$.each(data, function (key, val) {
if (val.name == str) {
$.each(val.city, function (key_city, val_city) {
options_city += '<option value="' + val_city + '">' + val_city + '</option>';
});
}
});
$("#city ").html(options_city);
}).change();
});
});
This work fine, but everytime that I need to change one date the selectors clear and load again.
I tried to add tag onload to start the function to load selectors in this subform, but don't works. Also tried change events to .on, but also don't work.
How I need to do this?
Thx!!
Not knowing what #reemb is, I would empty the relevant sub selects:
If the container holding the selects is ALSO emptied, you need to delegate all even handlers of objects inside too - like $(document).on("change","#bank", function() {
$(document).on('click', '#reemb', function() {
$.getJSON("/banks.php", function(json) {
$('#bank').empty();
$.each(json, function(i, obj) {
$('#bank').append($('<option>').text(obj.name).attr('value', obj.code)).change();
});
});
$('#bank').on("change", function() {
$('#city').empty();
$.getJSON('/statecity.json', function(data) {
var items = [];
var options = '<option value="">State</option>';
$.each(data, function(key, val) {
options += '<option value="' + val.name + '">' + val.name + '</option>';
});
$("#state").html(options).change(); // if needed
});
$("#state").on("change", function() {
var options_city = '';
var str = "";
$("#state option:selected").each(function() {
str += $(this).text();
});
$.each(data, function(key, val) {
if (val.name == str) {
$.each(val.city, function(key_city, val_city) {
options_city += '<option value="' + val_city + '">' + val_city + '</option>';
});
}
});
$("#city ").html(options_city).change(); // if needed
});
});
});
I am extremely new at writing ajax and working with a restful api... so, bear with me.
I have a Laravel 5.2 RESTful API that I am using on the backend, and I'm attempting to simply load a list of categories using Jquery / Ajax. As you click through the categories, each child category loads fine, but I cannot seem to get the "back" button to work (by this, I mean the LI I am generating, not the browser back button). When you click it, it shows the alert - and the data is correct, but that's it. The list doesn't refresh and populate with the appropriate items.
EDIT
There are no errors being thrown to the javascript console either. It just won't populate from the ajax call.
EDIT
I removed the request.abort() right after I made the original post.
EDIT
Here is the JSON returned from the URL api/categories/4 - as an example.
[{"id":6,"parent":4,"name":"sub_subcat4_1","slug":"sub_subcat4_1","description":null,"created_at":null,"updated_at":null},{"id":7,"parent":4,"name":"sub_subcat4_2","slug":"sub_subcat4_2","description":null,"created_at":null,"updated_at":null}]
EDIT
Here is the HTML for the #categories
<div class="row">
<div class="col-sm-12">
<ul id="categories">
</ul>
</div>
The Javascript
<script>
/*
* This loads the default / root categories.
*/
function getRootCategories() {
$.getJSON("api/categories", function(data) {
var categories = [];
$("#categories").html("");
$.each(data, function(key, val) {
$("#categories").append("<li class='subcat' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>');
});
});
}
/*
* This loads the sub categories if there's any data returned. Otherwise, just leave the user where they are.
*/
function getSubcats(cat) {
var dataID = cat.getAttribute("data-id");
alert(dataID);
if(dataID == "null") {
getRootCategories();
}
else {
$.getJSON("api/categories/" + dataID, function (data) {
if (data.length != 0) {
$("#categories").html("");
var newCats = '';
var parent = '';
$.each(data, function (key, val) {
parent = "<li class='subcat' data-id='" + val.parent + "' onClick='getSubcats(this);'>Back</li>";
newCats += "<li class='subcat' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>';
});
$("#categories").append(parent + newCats);
}
});
}
}
$(document).ready(function() {
$.ajaxSetup({ cache:false });
getRootCategories();
});
</script>
Ok, I just had my variables all mixed up. I wasn't setting the correct parent id.
The new script looks like this -
<script>
var previous = null;
/*
* This loads the default / root categories.
*/
function getRootCategories() {
$.getJSON("api/categories", function(data) {
var categories = [];
$("#categories").html("");
$.each(data, function(key, val) {
$("#categories").append("<li class='subcat' data-parent='" + val.parent + "' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>');
previous = val.parent;
});
});
}
/*
* This loads the sub categories if there's any data returned. Otherwise, just leave the user where they are.
*/
function getSubcats(cat) {
var dataID = cat.getAttribute("data-id");
previous = cat.getAttribute("data-parent");
if(dataID == "null") {
getRootCategories();
}
else {
$.getJSON("api/categories/" + dataID, function (data) {
if (data.length != 0) {
$("#categories").html("");
var newCats = '';
var parent = '';
$.each(data, function (key, val) {
parent = "<li class='subcat' data-id='" + previous + "' onClick='getSubcats(this);'>Back</li>";
newCats += "<li class='subcat' data-parent='" + val.parent + "' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>';
});
$("#categories").append(parent + newCats);
}
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + " - " + error);
});
}
}
$(document).ready(function() {
$.ajaxSetup({ cache:false });
getRootCategories();
});
</script>
I'm making an ajax call to retrieve some JSON objects. I get them right. but the problem is when I want to create a select element from returned JSON, it doesn't create one or seemed to be.
My JavaScript so far:
jQuery("#make").change(function () {
var value = $(this).val();
jQuery.getJSON("<?php echo site_url('ajax/get/models'); ?>", {
makeId: value
},
function (data) {
if (data != "false") {
var modelsSelect = jQuery.createElement('select');
var modelsOptions = "";
var id;
var model
jQuery.each(data, function () {
jQuery.each(this, function (key, value) {
if (key == "id") {
id = value;
} else {
model = value;
}
});
modelsOptions += "<option value=" + id + ">" + model + "</option>"
});
modelsSelect.innerHTML = modelsOptions;
jQuery("#model").html = modelsSelect;
} else {
alert("false");
}
});
});
my returned JSON Format:
Object { id="28", model="test model"}
There could be n number of JSON objects in returned response from ajax call.
There is no createElement method in jQuery
jQuery.createElement should be document.createElement
Also no need to loop over the objects' properties, you can access them by the key directly
jQuery.each(data, function (index, item) {
modelsOptions += "<option value=" + item.id + ">" + item.model + "</option>"
});
Change this
jQuery("#model").html = modelsSelect;
to
jQuery("#model").html(modelsSelect);
Reference
.html()