Json cascading dropdown - javascript

I'm trying to set up a cascading dropdown using JSON data. I have it working somewhat but need some assistance getting the 2nd tier to work as intended. Currently it seems to be grabbing the number in the array.
Ideally for my 2nd tier I want to show the text in the dropdown as the option text, and I'd like to use the id field in the json as the value of the option.
var data = {
"Crime":[
{"id":"1","text":"Number of police"},
{ "id":"2","text":"Number of crimes"}
],
"Health":[
{"id":"3","text":"Number of doctors"},
{"id":"4","text":"Number of hospital visits"},
{"id":"5","text":"Number of nurses"}
],
}
I have a jsfiddle showing what I have so far.
Happy to use whatever combination of javascript/jquery works best.

The way you have used for..in seems to be incorrect. The question variable will not contain the entire value if the pointed collection (data[this.value], in this case) is not a simple array. Rather, it would contain the index of the first row, the second row and so on. I request you to read this for a more in-depth understanding :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
This line here
questionSel.options[questionSel.options.length] = new Option(question, question);
Must read this way
questionSel.options[questionSel.options.length] = new Option(
data[this.value][question].text,
data[this.value][question].id);
Here's an updated fiddle after this change has been made:
http://jsfiddle.net/tc1f3kup/2/

please try this
var data = {
"Crime":[
{"id":"1","text":"Number of police"},
{ "id":"2","text":"Number of crimes"}
],
"Health":[
{"id":"3","text":"Number of doctors"},
{"id":"4","text":"Number of hospital visits"},
{"id":"5","text":"Number of nurses"}
],
}
window.onload = function () {
var themeSel = document.getElementById("theme"),
questionSel = document.getElementById("questions");
for (var theme in data) {
themeSel.options[themeSel.options.length] = new Option(theme, theme);
}
themeSel.onchange = function () {
questionSel.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
for(var i=0;i<data[this.value].length;i++)
{
questionSel.options[questionSel.options.length] = new Option(data[this.value][i].text, data[this.value][i].id);
}
}
}
working fiddle
http://jsfiddle.net/tc1f3kup/3/

Related

Can I use two parameter event for one function?

What I want to do is change the url.
Replace the Object word with an event parameter called e1.
Replace the word field with the event parameter e2.
I know this code is not working.
But I don't know how to do it.
The following is my code that I just wrote.
function getAllFieldValue(e1,e2) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var url = 'test123.my.salesforce.com/services/data/v44.0/queryAll?q=SELECT Field FROM Object';
var url = url.replace('Object',e1);
var url = url.replace('Field',e2);
var response = UrlFetchApp.fetch(url,getUrlFetchOptions());
var json = response.getContentText();
var data = JSON.parse(json);
var fieldValues = data.records;
for(var i=0;i<fieldValues.length;i++){
var fieldValue = fieldValues[i].e;
ss.getRange(i+1,1).setValue(fieldValue);
}
}
I want to take the data from another database through this code and put it in the Google spreadsheet.
For e1, it means the object value selected in the dropbox.
For e2, it means the field of the object selected in the drop box.
Is there a way to use two event parameters for one function?
I look forward to hearing from you.
====================
Please understand that I am using a translator because I am not good at English.
Checking fieldValues[i] in Logger.log returns the following values:
[{
attributes={
type=Account,
url=/services/data/v44.0/sobjects/Account/0015i00000BS03VAAT
},
Name=University of Arizona
},
{
attributes={
type=Account,
url=/services/data/v44.0/sobjects/Account/0015i00000BS03TAAT
},
Name=United Oil & Gas Corp.
},
{
attributes={
type=Account,
url=/services/data/v44.0/sobjects/Account/0015i00000BS03ZAAT
},
Name=sForce
}]
The issues I am currently experiencing are as follows.
If I select 'Name' from the drop-down list, ec2 becomes 'Name'.
As far as I'm concerned,
var fieldName = fieldValues[i].e2 is
var fieldName = fieldValues[i].Name
It means that.
I think fieldValues[i].e2 should return the values of University of Arizona, United Oil & Gas Corp, sForce.
But in reality nothing is returned.
var fieldName = fieldValues[i].Name works properly.
I think there is a problem with fieldValues[i].e2
This is the problem I'm currently experiencing.
There was no problem with the parameters e1, e2, which I thought was a problem. The reason why the code did not work is because of the for loop var fieldValue = fieldValues[i].e; Because it didn't work properly.
var fieldName = fieldValues[i].e2
to
var fieldName = fieldValues[i][e2]
After modifying it like this, the code works properly.

Dynamiccaly accessing array inside objects inside arrays

First of all, i am relatively new to javascript so go easy on me :)
Here is my problem. I need to be able to dynamically navigate a multidimensionnal array that look like such :
Categories:[
{id:cat1,
name:cat1,
childrens:[
{id:cat1-subcat1,
name:cat1-subcat1,
childrens:[
{id:cat1-subcat1-subcat1,
name:cat1-subcat1-subcat1,
childrens:[
etc...
The idea is as follow : the client can create categories and nest subcategories under them but also put sub categories inside subcategories.
So i can add a subcategorie to a categorie by doing :
categories[position].children.push(newcat)
Now my problem is how to do the same with a sub categorie.
categories[position].children[x].children.push(newcat)
getting the x value and storing it in the new created categorie could be possible and i guess i could work my way around 1 layer of subcatgories but the idea is that it is supposed to be able to create as many nested sub categories as necessaries. so it could look like :
categories[position].children[x].children[y].children[z].children.push(newcat)
So i need a dynamic way to access those places. not sur how to do it.
Can i access those nested object via their id ? like with map in a regular array.
How would i access cat1-subcat1-subcat1 with only knowing the id for exemple ???
I hope it make sens, i am availbale of course for more explanations
Thanks, Esteban
So i have been trying to work on that piece of code.
To break down a simple array into a multidimensionnal one.
Each categorie store a level and parentid value.
Here is the code i am trying to work on,
Hope it makes sens to you guys. Again sorry for my poor javascript skill, that code very likely can be optimized.
Right now i would just like it to work :)
buildTreeview2(){
var catdb = this.$catdb
var lvl=0
var temparray=[]
var temparray2=[]
var tempactif=1
//var init = true
var j
var u
var i
//console.log({catdb})
// count how many lvls max
for(i=0;i<catdb.length;i++){
if (catdb[i].level>lvl){lvl=catdb[i].level}
}
if(lvl==0){
this.categories=this.$catdb
}
else{
for(u=lvl;u>=0;u--){
//console.log(u)
//put the items with the current lvl in an array
for(i=0;i<catdb.length;i++){
//console.log(catdb[i].level)
if(tempactif==1){
if(catdb[i].level==lvl){
temparray.push(catdb[i])
}
}else{
if(catdb[i].level==lvl){
temparray2.push(catdb[i])
}
}
}
//check if first round with init value
// if(init==true){
// tempactif=2
// init=false
// continue}
// else{
// add item from supperior lvl array to lower one
if(tempactif==1){
for(i=0;i<temparray.length;i++){
for(j=0;j<temparray2.length;j++){
if(temparray[i].id==temparray2[j].parentid){
temparray[i].children.push(temparray2[j])
}
}
}
}else{
for(i=0;i<temparray2.length;i++){
console.log(temparray2[i])
for(j=0;j<temparray.length;j++){
console.log(temparray[j])
if(temparray2[i].id==temparray[j].parentid){
temparray2[i].children.push(temparray[j])
}
}
}
}
//Switch tampactif value and clean temp array
if(tempactif==1){
//console.log(temparray)
temparray2=[]
tempactif=2
}else{
// console.log(temparray2)
temparray=[]
tempactif=1
}
// }//en of else
}//end of lvl loop
console.log('count')
if(tempactif==1){
this.categories=temparray2
}else{
this.categories=temparray
}
}
},
Thanks !!!
Ok, i found a way arround, so here it is if anyone has the same issue :
buildTreeview3(){
var catdb=JSON.parse(JSON.stringify(this.$catdb))
var lvl = 0
var tempcat={}
var u
var i
var parentid
// count how many lvls max
for(i=0;i<catdb.length;i++){
if (catdb[i].level>lvl){lvl=catdb[i].level}
}
console.log('lvl : ',lvl)
// if only base lvl, no need to build treeview
if(lvl==0){
this.categories=this.$catdb
}
else{
for(u=lvl;u>0;u--){
//for each lvl starting from highest, go through the temp database catdb
for(i=0;i<catdb.length;i++){
if(catdb[i].level==u){
//When found a categorie from current lvl, found the position of its parent and add it to its child
parentid = catdb[i].parentid
let parentpos = catdb.map(function (e) {
return e.id;
}).indexOf(parentid);
tempcat=catdb[parentpos]
tempcat.children.push(catdb[i])
//remove the cat that has been added to childs from the temp db
//replace the parent by the parent with child
catdb.splice(i,1)
catdb.splice(parentpos,1,tempcat)
i=0
}
}
}
}//end of all (else if not just base lvl)
this.categories=catdb
},

Vaadin Combo-Box: Using value property to pass the index of a selected item

I am trying to discern the index # of the pattern selected in the Combo-box. I need to pass this index value in order for another function to read from a file at the correct location. Essentially, selecting the a pattern in the combobox will let me do a lookup for specifications associated with the selected pattern based on the index. To the best of my knowledge the Vaadin Combobox does not have an index associated with the combobox items, but you are able to pass a different value than the displayed label: https://vaadin.com/docs/-/part/elements/vaadin-combo-box/vaadin-combo-box-basic.html (see: Using Objects as Items). This is solution I am trying to implement, however it gets tricky because I am dynamically populating the combobox items from a JSON file.
The code to dynamically populate the items:
paver = document.querySelector('#paver');
//alert('script executed');
patterns = [];
familyind=y;
$.getJSON('menu.json').done(function(data){
//alert('getJSON request succeeded!');
family = (data.gui[x].family[y].display);
for(ind = 0; ind < data.gui[x].family[y].pattern.length; ind++){
var patternLbl = data.gui[x].family[y].pattern[ind].name;
var patternObj = '{ pattern: { label: "' + patternLbl + '", value: ' + ind + ' } }';
patterns[ind] = patternObj;
}
document.getElementById("cb1").items=patterns;
})
.fail(function(jqXHR, textStatus, errorThrown)
{
alert('getJSON request failed! ' + textStatus);
})
.always(function() { }};
HTML for the ComboBox
<div id="patternSelect">
<template is="dom-bind" id="paver">
<div class="fieldset">
class="patterns" items="[[patterns]]" item-label-path="pattern.label" item-value-path="pattern.value"></vaadin-combo-box>
</div>
</template>
</div>
The output I get when I try to execute this is that the entire constructed string gets assembled into my selection choices. Theoretically, this should not have happened because the item-value-path and item-label-path were specified when declaring the combobox.
Screenshot of Output
It says: { pattern: { label: "A-3 Piece Random", value: 0 } }
WORKING TOWARDS A SOLUTION SECTION:
___________(April 27, 7:00pm)___________
Suggested solution to use,
var patternObj = { pattern: { label: patternLbl, value: ind } };
works fine in displaying labels:
However, I am using a trigger to detect when the value in the combo-box is changed and return the new value. Here is the code for the trigger:
// select template
var paver = document.querySelector('#paver');
// define the ready function callback
paver.ready = function () {
// use the async method to make sure you can access parent/siblings
this.async(function() {
// access sibling or parent elements here
var combobox = document.querySelector('#cb1')
combobox.addEventListener('value-changed', function(event) {
// FOR REFERENCE LOG ERRORS, THIS COMMENT IS ON HTML:215
console.log(event.detail.value);
patval = event.detail.value;
console.log(patval)
// Do stuff with fetched value
});
});
};
I have made the suggested change to using a 'value-changed' trigger. It works very well with two slight issues. First, it returns each of the console log calls twice (not sure why twice). Second, when I select the first combo-box item it returns my values but does not set the label as selected. This is not an issue with the other combo-box items, but the first item needs to be selected twice to have the label set. Please watch this short video for a demonstration: https://youtu.be/yIFc9SiSOUM. This graphical glitch would confuse the user as they would think they did not select a pattern when they know they had. Looking for a solution to make sure the label is set when the first item is selected.
You are setting a currently a String to patternObj while you should be setting an Object.
Try using either var patternObj = JSON.parse('{ pattern: { label: "' + patternLbl + '", value: ' + ind + ' } }'; or even simpler:
var patternObj = { pattern: { label: patternLbl, value: ind } };
Also, I would recommend initializing the patterns = [] inside the done callback to make sure you're not leaving any old items in the patterns when the data changes.

Parse.com issues while querying array of pointers, .include not getting nested pointer data in cloud code

I am having trouble getting data from the nested pointers in my array of pointers from a query. I have an array of pointers like so: [{"__type":"Pointer","className":"QuizData","objectId":"rmwJrV55c7"},{"__type":"Pointer","className":"QuizData","objectId":"2132q8i9np”}, etc…]
That QuizData class also has a column named “ad” which is a Pointer to the “Ads” class. I can get the QuizData in a query using the following include statements on my query like so:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include("quizAdArr”);
__quizAdQueueQuery.include(["quizAdArr.QuizData"]);
BUT Neither of these or both combined don’t work as when I try to get column data from the ad it’s always undefined:
__quizAdQueueQuery.include(["quizAdArr.QuizData.ad"]);
__quizAdQueueQuery.include(["quizAdArr.QuizData.Ads"]);
This is my return from that query, where the column data "mediaType" that I am trying to access is always undefined:
return __quizAdQueueQuery.first().then(function(__resultsObj)
{
__quizQueueObj = __resultsObj;
__userQuizQueueArr = __quizQueueObj.get("quizAdArr");
var __quiz;
var __ad;
var __seenAd;
var __lengthInt = __userQuizQueueArr.length;
var __mediaTypeStr = __request.params.mediaType;
var __matchedQuizzesArr = [];
for (var __i = 1; __i < __lengthInt; __i++)
{
__quiz = __userQuizQueueArr[__i];
// console.log('__quiz.get("name") = '+__quiz.get("name"));
__ad = __quiz.get("ad");
// console.log("__ad.id = "+__ad.id);
//THE MEDIA TYPE IS ALWAYS RETURNING UNDEFINED HERE!!!
console.log('__ad.get("mediaType") = '+__ad.get("mediaType")+', __mediaTypeStr = '+__mediaTypeStr);
if (__ad.get("mediaType") == __mediaTypeStr)
{
//put all matches in array to be sorted
__matchedQuizzesArr.push(__userQuizQueueArr[__i]);
console.log("__matchedQuizzesArr.length = "+__matchedQuizzesArr.length);
}
}
return __matchedQuizzesArr;
});
Thanks for any help you can give! I also posted this as a bug in the Parse/Facebook issue reporter but was redirected here, so if this is a bug I can reopen it: https://developers.facebook.com/bugs/923988310993165/
EDIT Here is the updated, working query with nested includes for clarity:
var __quizAdQueueQuery = new Parse.Query(QuizAdQueue);
__quizAdQueueQuery.equalTo("user", __request.user);
__quizAdQueueQuery.include('quizAdArr');
__quizAdQueueQuery.include('quizAdArr.ad');
This should work (you only need to list the column names):
query.include('quizAdArr.ad');
Here's why:
You're querying QuizAdQueue so you don't need to list that
The QuizAdQueue class has an array in quizAdArr so you include it: query.include('quizAdArr');
Each quizAdArr element is a QuizData with an ad so you include it: query.include('quizAdArr.ad');
The issue was that you were including QuizData which is the name of a class and not a column name

How to get handson table data in json format with column header as key

I have handsontable and I want to get data enter on handsontable cell into server side. I have tried to ran below code but data is not in expected format. I was expecting to get the data in pure json format as column header as key.
Html code
<div class="handsontable" id="example"></div>
<input type="button" name="submit" value="submit" onclick="submitForm()" />
code for creating the handsontable
$(document).ready(function () {
$('#example').handsontable({
startRows: 2,
startCols: 2,
rowHeaders: true,
colHeaders: true,
contextMenu: true,
});
});
code for extracting the information from handsontable
function submitForm(){
var $container = $('#example');
var htContents = JSON.stringify($container.handsontable('getData'));
alert(htContents);
}
Currently handsontable has 2 rows and 2 column. Now if I press the button with cell value (1,1)=11,(1,2)=12,(2,1)=21 and (2,2)=22, result I am getting is in alert window
[["11","12"],["21","22"]]
But result I am expecting is
[{"A":"11","B":"12"},{"A":"21","B":"22"}]
where A and B is column header.
For others who didn't discover the answer immediately, see #hakuna1811's comment above that since version 0.20.0 of Handsontable the .getSourceData() call should be used instead if you want to get your data back in the same format as you provided it - for example as an array of objects. It is not clear why the .getData() call's behavior was modified and it is not explained in the related GitHub issue noted in #hakuna1811's comment, but at least we have a working solution - thanks again to #hakuna1811 for the answer - it saved a lot of hunting around!
That's great that you're expecting that, but that's just not how that function works :P
Here's what you actually want:
For starters, you don't show us where you set the data option. If you look at this fiddle, I use the different notation to generate a Handsontable object which allows me to specify the format of data.
If data is given how I show it, as an array of row Objects, where each Object is in the format you describe, then the hot1.getData() method returns what you expect.
As it stands, I have no idea what data format you're using so either adopt this way of instantiating HOT or show us how you're doing it.
Good luck!
You need mapping the result. let's assume htContents is variable which contains [["11","12"],["21","22"]]
function buildObject(data) {
return {
'A': data[0],
'B': data[1]
};
}
var newResult = htContents.map(buildObject); // newResult must be expected data
The getSourceData() method returns the desired format, but will not reflect the correct row and column order as seen on screen. The following typescript code works for me:
protected getVisualTableData(): object[] {
const tableData = [];
for (let i = 0; i < this.hot.countRows(); i++) {
tableData.push(this.visualObjectRow(i));
}
return tableData;
}
protected visualObjectRow(row: number): object {
const obj = {};
for (let i = 0; i < this.hot.countCols(); i++) {
obj[this.hot.colToProp(i)] = this.hot.getDataAtCell(row, i);
}
return obj;
}

Categories