Dropdown with database searching dynamic dependence - javascript

Currently, I was trying to make multiple chain dropdown lists.
The data was json format something like.
[{"y":1,"x":1,"name":"5M","value":0},
{"y":1,"x":2,"name":"5L","value":2},
{"y":1,"x":3,"name":"5K","value":16},
{"y":1,"x":4,"name":"5J","value":0},
{"y":1,"x":5,"name":"5H","value":0},
{"y":1,"x":6,"name":"5G","value":1},
{"y":1,"x":7,"name":"5F","value":8},
The dropdown idealized was like the footer filter of this example from datatable.
http://live.datatables.net/gejojiqu/1/edit
All of the dropdown select lists can be dynamic dependent after one or many attributes (column) were selected.
For example like when I select the 1st dropdown list which belongs to the "name" attribute with "Bradley Greer", the "position" dropdown select value will only remain "Software Engineer" and so on the other dropdown select value.
Any idea or guidance that how can I achieve this dropdown?
I search for a lot of related guidance about cascading dropdowns non of their data format was similar to mine.
Any help was appreciated.

I manage to find the solution by myself by using jQuery and struggling for a night:
const my data = [
{
"Data": "aaa",
"Media": "1",
"Row": "1",
"Column": "3",
"Code": "24",
},
{
"Data": "aaa",
"Media": "2",
"Row": "1",
"Column": "1",
"Code": "24",
},
{
"Data": "aba",
"Media": "3",
"Row": "1",
"Column": "3",
"Code": "24",
},
{
"Data": "aab",
"Media": "4",
"Row": "1",
"Column": "2",
"Code": "24",
},
{
"Data": "aab",
"Media": "1",
"Row": "2",
"Column": "1",
"Code": "24",
},
{
"Data": "aab123",
"Media": "1",
"Row": "2",
"Column": "1",
"Code": "23",
},
]
mydata.forEach(function(row,index) {
mydata[index] = Object.values(mydata[index]);
});
function makeDropDown(data,filtersAsArray,targetElement){
const filteredArray = filterArray(data, filtersAsArray);
const uniqueList = getUniqueValues(filteredArray,filtersAsArray.length);
populateDropDown(targetElement,uniqueList);
}
function applyDropDown(){
const selectLevel1Value = document.getElementById("level1").value;
const selectLevel2 = document.getElementById("level2");
makeDropDown(mydata, [selectLevel1Value], selectLevel2);
applyDropDown2();
applyDropDown3();
applyDropDown4();
}
function applyDropDown2(){
const selectLevel1Value = document.getElementById("level1").value;
const selectLevel2Value = document.getElementById("level2").value;
const selectLevel3 = document.getElementById("level3");
makeDropDown(mydata, [selectLevel1Value, selectLevel2Value], selectLevel3);
}
function applyDropDown3(){
const selectLevel1Value = document.getElementById("level1").value;
const selectLevel2Value = document.getElementById("level2").value;
const selectLevel3Value = document.getElementById("level3").value;
const selectLevel4 = document.getElementById("level4");
makeDropDown(mydata, [selectLevel1Value, selectLevel2Value, selectLevel3Value], selectLevel4);
}
function applyDropDown4(){
const selectLevel1Value = document.getElementById("level1").value;
const selectLevel2Value = document.getElementById("level2").value;
const selectLevel3Value = document.getElementById("level3").value;
const selectLevel4Value = document.getElementById("level4").value;
const selectLevel5 = document.getElementById("level5");
makeDropDown(mydata, [selectLevel1Value, selectLevel2Value, selectLevel3Value, selectLevel4Value], selectLevel5);
}
function afterDocumentLoads(){
populateFirstLevelDropDown();
applyDropDown();
}
function getUniqueValues(data,index){
const uniqueOptions = new Set();
data.forEach(r => uniqueOptions.add(r[index]));
return [...uniqueOptions];
}
function populateFirstLevelDropDown(){
const uniqueList = getUniqueValues(mydata,0);
const el = document.getElementById("level1");
populateDropDown(el,uniqueList);
}
function populateDropDown(el,listasArray){
el.innerHTML = "";
listasArray.forEach(item => {
const option = document.createElement("option");
option.textContent = item;
el.appendChild(option);
});
}
function filterArray(data, filtersAsArray){
return data.filter(r => filtersAsArray.every((item,i) => item === r[i]));
}
document.getElementById("level1").addEventListener("change",applyDropDown);
document.getElementById("level2").addEventListener("change",applyDropDown2);
document.addEventListener("DOMContentLoaded", afterDocumentLoads);
$(document).ready(function() {
$('.js-example-basic-single').select2();
});
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js"></script>
</head>
<label>Data</label>
<select class="js-example-basic-single" id="level1" name="level1"></select>
<label>Media</label>
<select class="js-example-basic-single" id="level2" name="level2"></select>
<label>Row</label>
<select class="js-example-basic-single" id="level3" name="level3"></select>
<label>Column</label>
<select class="js-example-basic-single" id="level4" name="level4"></select>
<label>Code</label>
<select class="js-example-basic-single" id="level5" name="level5"></select>
Fiddle

Related

Cannot show the Autocomplete updated source list

I tried to update the source of Autocomplete, but after I update it, it could not show the list of the source? Did I do anything wrong here?
Here is my set up:
let cities = [
{"label":"Alessandria","id":"AL"},
{"label":"Milano","id":"MI"},
{"label":"Pisa","id":"PI"},
{"label":"Pistoia","id":"PT"}
];
test_auto_c(cities); //For the first time, set up autocomplete.
$("#btn1").click(() => {
let arr = [
{"lable": "Changed1-1", "id": "1"},
{"lable": "Changed1-2", "id": "2"},
{"lable": "Changed1-3", "id": "3"}
];
$("#autocomplete-city").autocomplete('option', 'source', arr); //change the source
});
$("#btn2").click(() => {
let arr = [
{"lable": "Changed2-1", "id": "4"},
{"lable": "Changed2-2", "id": "5"},
{"lable": "Changed2-3", "id": "6"}
];
$("#autocomplete-city").autocomplete('option', 'source', arr); //change the source
});
Below is the function of test_auto_c():
function test_auto_c(arr){
$("#autocomplete-city").autocomplete({
source: arr,
minLength: 0,
select: function(event, ui){
if(ui.item){
return ui.item.label;
}
else{}
},
change: function(event, ui){
var searched = this.value;
if(ui.item){
}
else{
var result = arr.filter(function( obj ) {
return obj.label.toLowerCase().indexOf(searched.toLowerCase()) !== -1;
});
if(result.length>0){
$(this).val(result[0].label);
}
else{
//clear the autocomplete
let final_value = arr[0].label;
$(this).val(final_value);
}
}
}
}).focus(function () {
$(this).autocomplete("search");
});
}
finally, it gives me the result of empty list after I tried to change the source.
What I expect is display like below:
And I am using:
<link href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" integrity="sha256-T0Vest3yCU7pafRw9r+settMBX6JkKN06dqBnpQ8d30=" crossorigin="anonymous"></script>
First you have to review the docs:
Multiple types supported:
Array: An array can be used for local data. There are two supported formats:
An array of strings: [ "Choice1", "Choice2" ]
An array of objects with label and value properties: [ { label: "Choice1", value: "value1" }, ... ]
It seems to work and when you then change the source later, it does not work. This is due to a typo, you have "lable" where you need "label".
$(function() {
function test_auto_c(arr) {
$("#autocomplete-city").autocomplete({
source: arr,
minLength: 0
}).focus(function() {
$(this).autocomplete("search");
});
}
let cities = [{
"label": "Alessandria",
"id": "AL"
},
{
"label": "Milano",
"id": "MI"
},
{
"label": "Pisa",
"id": "PI"
},
{
"label": "Pistoia",
"id": "PT"
}
];
test_auto_c(cities);
$("#btn1").click(() => {
let arr = [{
"label": "Changed1-1",
"id": "1"
},
{
"label": "Changed1-2",
"id": "2"
},
{
"label": "Changed1-3",
"id": "3"
}
];
$("#autocomplete-city").autocomplete('option', 'source', arr); //change the source
});
$("#btn2").click(() => {
let arr = [{
"label": "Changed2-1",
"id": "4"
},
{
"label": "Changed2-2",
"id": "5"
},
{
"label": "Changed2-3",
"id": "6"
}
];
$("#autocomplete-city").autocomplete('option', 'source', arr); //change the source
});
});
<link href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js" integrity="sha256-T0Vest3yCU7pafRw9r+settMBX6JkKN06dqBnpQ8d30=" crossorigin="anonymous"></script>
<div>
<input type="text" id="autocomplete-city">
<button id="btn1">Btn 1</button>
<button id="btn2">Btn 2</button>
</div>

How to parse FractalTransformer with normalizr

I'm trying to use paularmstrong/normalizr on JSON that comes from FractalTransformer and whose nested childs have "data" attribute. Example of JSON:
{
"data": {
"object": "Offer",
"id": "5g6aqocew4qjzl40",
"real_id": 26,
"name": "Random Name",
"created_at": {
"date": "2019-06-18 11:13:08.000000",
"timezone_type": 3,
"timezone": "UTC"
},
"readable_created_at": "1 year ago",
"site": {
"data": {
"object": "Site",
"id": "65zody8vj29vlegd",
"name": "Test Site",
"real_id": 1
}
},
"countries": {
"data": [
{
"object": "Country",
"code": "US",
"name": "United States"
},
{
"object": "Country",
"code": "DE",
"name": "Germany"
}
]
}
},
"meta": {
"include": [
"site",
"countries"
],
"custom": []
}
}
Schemas I use:
export const offerSchema = new schema.Entity('offers')
export const siteSchema = new schema.Entity('sites', {}, {
processStrategy: (value) => {
return { ...value.data }
},
idAttribute: (value) => {
return value.data.id
},
})
export const countrySchema = new schema.Entity('countries')
offerSchema.define({
site: siteSchema,
countries: [countrySchema],
})
Now the issue is that I remove 'data' from the site since it's just one object successfully, but I can't do it in the country case. Whatever I tried with custom processStrategy fails, as country is object that has data which is array (I assume this is where the issue is, going from Entity to Array). And in idAttribute function I always get complete array so can't determine the ID of single entry. So the end result is that the ID of countries is undefined. Any ides?
I actually managed with another approach. I added processStrategy on the parent, 'Offer' in this case, so all 'data' parts get stripped before they reach other child schemas.
const normalizrStripDataOptions = {
processStrategy: (value) => {
const ret = { ...value }
Object.keys(ret).forEach((key) => {
if (ret[key] !== null) {
if (ret[key].data && Array.isArray(ret[key].data)) {
ret[key] = [...ret[key].data]
}
if (ret[key].data && typeof ret[key].data === 'object') {
ret[key] = { ...ret[key].data }
}
}
})
return ret
},
}
export const offerSchema = new schema.Entity('offers', {}, normalizrStripDataOptions)
export const siteSchema = new schema.Entity('sites')
export const countrySchema = new schema.Entity('countries')
offerSchema.define({
site: siteSchema,
countries: [countrySchema],
})

lodash filter by single value and value in array

I have a quick and easy function that I need to use lodash for.
let obj =
{
"AttributeID": "1",
"KeyID": "0",
"Value": "Undefined",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
},
{
"AttributeID": "1",
"KeyID": "1",
"Value": "Tier 1",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}, {
"AttributeID": "1",
"KeyID": "2",
"Value": "Tier 2",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}, {
"AttributeID": "1",
"KeyID": "3",
"Value": "Tier 3",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}, {
"AttributeID": "1",
"KeyID": "4",
"Value": "Tier 4",
"MetaInsertUtc": "2017-09-13T01:52:22.280"
}
let parent = 1;
let children = ['1', '2', '3', '4'];
let test = _.filter(obj, function(item) {
return parseInt(item.AttributeID) === parent && parseInt(item.KeyID) IN[Children];
})
I am trying to filter my objects by a specific parent ID and within those results, find all those that have KeyID that are in our children array.
Update:
Here is my end result based on the selected answer. If there is a more shorthand way to do this by chaining some of these lodash methods together, let me know.
let valueObj = {
"id" : "1",
"name": "Joe"
},
{
"id" : "2",
"name": "Bob"
}
let selectedValues = _.map(valueObj, 'id');
let result = _.filter(obj, function(item) {
return item.AttributeID === attributeID && _.includes(selectedValues, item.KeyID);
});
Use lodash#includes method. If children array contains string values, you shouldn't convert item.KeyID to a number, just compare two strings:
let test = _.filter(obj, function(item) {
let attrId = parseInt(item.AttributeID);
return attrId === parent && _.includes(children, item.KeyID);
});
Assuming your obj is actually an array.
object.filter(item => {
return parseInt(item['AttributeID']) === parent && children.indexOf(parseInt(item['AttributeID'])) > -1;
});
You can do this simple filtering in regular JS.

option selects from json object on categories

Hi (sorry for my english), I have this script:
<script type="text/javascript">
$(document).ready(function() {
var idPlato = decodeURI(getUrlVars()["idPl"]);
var url = "http://localhost/plato-datos.php?idPla="+idPlato+"";
});
};
</script>
It brings me this json from my database:
[{"category":"first","name":"green","idP":"1", "count":3},
{"category":"first","name":"blue","idP":"2","count":5},
{"category":"sec","name":"peter","idP":"3", "count":3},
{"category":"sec","name":"james","idP":"4", "count":2,},
{"category":"third","name":"dog","idP":"5", "count":4}]
I need to create one radiobuton for every name and group by categores
I create a solution. Kinda ugly but it will work:
var data = [{
"category": "first",
"name": "green",
"idP": "1",
"count": 3
}, {
"category": "first",
"name": "blue",
"idP": "2",
"count": 5
}, {
"category": "sec",
"name": "peter",
"idP": "3",
"count": 3
}, {
"category": "sec",
"name": "james",
"idP": "4",
"count": 2,
}, {
"category": "third",
"name": "dog",
"idP": "5",
"count": 4
}];
var result = {};
data.map(a => {
if (result[a.category]) {
result[a.category].push(a.name);
} else {
result[a.category] = [a.name];
}
});
Object.keys(result).map(category => {
var select = document.createElement('select');
result[category].map(name => {
var option = document.createElement('option');
option.value = name;
option.text = name;
select.appendChild(option);
});
document.body.appendChild(select);
});
Im working with jquery mobile then i used autodividersSelector function for group by the category JSON object, and build a radiobuton for every name
<script type="text/javascript">
//catch the JSON from my database
$(document).ready(function() {
var idPla = decodeURI(getUrlVars()["idPl"]);
var urlAder =
"http://localhost/lista-adereso.php?idPla=" + idPla + "";
//print the radiobutons
$.getJSON(urlAder, function(resultado) {
var allfiles = '';
for (var i = 0, aderesos = null; i <
resultado.length; i++) {
aderesos = resultado[i];
allfiles +='<li><label><input type="radio" data-
status="' + aderesos.aderesoCatNom +'"
name="name" id="id" value="' +
aderesos.aderNombre +'">'+
aderesos.aderNombre + '</label></li>'; }
//Group by categories
$('#linkList')
.empty()
.append(allfiles)
.listview({
autodividers:true,
autodividersSelector: function ( li ) {
var out = li.find('input').data("status");
return out;
}
})
.listview("refresh");
});
});
</script>

angularjs parse json with "\"

I have the following json (which exists in $scope.projectData).
[{
"\"Space\"": "\"L1 (1 floor)\"",
"\"Subject\"": "\"Corridor Distance\"",
"\"Label\"": "\"Corridor Distance\"",
"\"Color\"": "\"#33CCCC\"",
"\"Length\"": "\"193.55\"",
"\"Count\"": "\"0\"",
"\"Multiplier\"": "\"1\"",
"\"TotalFt\"": "\"193.55\"",
"\"TotalCounts\"": "\"\"",
"\"Notes\"": "\"\""},
{
"\"Space\"": "\"L1 (1 floor)\"",
"\"Subject\"": "\"Corridor Distance\"",
"\"Label\"": "\"Corridor Distance\"",
"\"Color\"": "\"#33CCCC\"",
"\"Length\"": "\"210.36\"",
"\"Count\"": "\"0\"",
"\"Multiplier\"": "\"1\"",
"\"TotalFt\"": "\"210.36\"",
"\"TotalCounts\"": "\"\"",
"\"Notes\"": "\"\"" }]
this is my controller
$scope.csvParse = function(item) {
var array = JSON.parse(item);
console.log(item);
};
and my html
{{ csvParse(projectData) }}
my code is not working. any suggestions?
Why not just do the following?
$scope.projectData = [{
"Space": "L1 (1 floor)",
"Subject": "Corridor Distance",
"Label": "Corridor Distance",
"Color": "#33CCCC",
"Length": "193.55",
"Count": "0",
"Multiplier": "1",
"TotalFt": "193.55",
"TotalCounts": "",
"Notes": ""},
{
"Space": "L1 (1 floor)",
"Subject": "Corridor Distance",
"Label": "Corridor Distance",
"Color": "#33CCCC",
"Length": "210.36",
"Count": "0",
"Multiplier": "1",
"TotalFt": "210.36",
"TotalCounts": "",
"Notes": "" }];
and
{{ projectData }}
EDIT: Alternatively, you can fix your projectData by changing your csvParse as follows:
function clean(str) {
return str.replace(/\"/g, "")
}
$scope.csvParse = function(objs) {
var newObjs = [];
objs.forEach(function(obj) {
var newObj = {};
for(var key in obj) {
val = obj[key];
newObj[clean(key)] = clean(val);
}
newObjs.push(newObj);
});
return newObjs;
};

Categories

Resources