I am working on a small project.
The initial select form has N options.
Making a selection will pop up another select form based on what it is.
Example: Choose a pet: dog, cat (Chooses dog), displays types of dogs.
I am doing this using JSON and JS but im not sure I have the correct understanding of how things should be working.
What my thought process is for this, when a selection is made.. send that string to a method and then search the JSON object for that string, pull that data and create the new select.
However, it doesnt appear to be working and I think my lack of knowledge with both is hindering my progress here.
JSON
var obj = {
"option":[
{
"text":"Choose Team",
"value":"choose"
},
{
"text":"Eagles",
"value":"d"
},
{
"text":"Falcons",
"value":"c"
},
{
"text":"Browns",
"value":"b"
}
],
"Eagles":[
{
"text":"Choose Player",
"value":"Choose"
},
{
"text":"Eagles",
"value":"d"
},
{
"text":"Falcons",
"value":"c"
},
{
"text":"Browns",
"value":"b"
}
]
};
And then the JS function that creates a new select box based on the selection string
function changeSelect(select){
var test = select.options[select.selectedIndex].text;
for(var i = 0; i < obj.test.length; i++){
var objOption = document.createElement( 'option' );
objOption.setAttribute( 'value', obj.test[i].value);
objOption.appendChild( document.createTextNode( obj.test[i].text) );
}
}
Is there a reason obj.Eagles[i].text will create my new select form with the correct values but obj.test[i].text doesn't work? (Text is a variable with the String "Eagles" assigned to it)
try this... I had to change the data slightly.
(function(select1, select2) {
select1 = document.getElementById(select1);
select2 = document.getElementById(select2);
var obj = {
"option": [{
"text": "Choose Team",
"value": "choose"
}, {
"text": "Eagles",
"value": "Eagles"
}, {
"text": "Falcons",
"value": "Falcons"
}, {
"text": "Browns",
"value": "Browns"
}],
"Eagles": [{
"text": "Choose Player",
"value": "Choose"
}, {
"text": "Agholor, Nelson",
"value": "d"
}, {
"text": "Ajirotutu, Seyi",
"value": "c"
}, {
"text": "Bradford, Sam",
"value": "b"
}]
};
function populateSelect(select, data) {
for (var i = 0, objOption, element; element = data[i++];) {
objOption = document.createElement('option');
objOption.value = element.value;
objOption.innerHTML = element.text;
select.appendChild(objOption);
}
}
function changeSelect2(event) {
var test = event.target.value,
innerArray = obj[test];
select2.options.length = 0;
if (innerArray) {
populateSelect(select2, innerArray);
}
}
populateSelect(select1, obj.option);
select1.addEventListener("change", changeSelect2, false);
})("select1", "select2");
<select id="select1"></select>
<select id="select2"></select>
Related
I have a b-form-select field and emit my value-field to my parent, but I need the selected text-field too..
Here is the needed code to show what I mean:
In my template:
<b-form-select v-model="selected" :options="getOptions" text-field="Name" value-field="Rank"></b-form-select>
but if I console.log(this.selected), I get of course the value Rank which I have selected. But is it also possible to get the text-field ?
Here is my script to show how my selected works:
computed: {
getOptions() {
const array = [];
const person = this.data.find((i) => i.name === this.name);
for (let key in person.persons) {
array.push(person.persons[key]);
}
return array;
},
}
my json data:
[
{
"name": "XXX",
"persons": {
"1": {
"Name": "Max",
"Rank": "1"
},
"2": {
"Name": "Peter",
"Rank": "2"
},
"3": {
"Name": "Harry",
"Rank": "1"
},
"4": {
"Name": "Jake",
"Rank": "0"
}
}
},
]
As you have the value available, as well as the list of options you can simply add a new computed field to get the selected values text-field
computed: {
getOptions() {
const array = [];
const person = this.data.find((i) => i.name === this.name);
for (let key in person.persons) {
array.push(person.persons[key]);
}
return array;
},
selectedOption() {
if (!this.selected) {
return null;
}
return Object.values(this.getOptions).find((option) => {
return option.Rank === this.selected;
});
}
}
Then access selectedOption.Name or selectedOption.Rank. If you put the Name and Rank into variables / data attributes as well you can also make it more generic.
Update:
Changed to Object.values
I passed a global tree structured JSON string in jquery fancy tree. I can add a new node data to the global object. I am not able to update a specific node of the global JSON string although I can find that specific node.
I have tried the following way of doing what I wanted but at the end the global variable is not changed. I also tried recursive way but not worked too. Also this is my first question at stackoverflow. I simplified the data because real data is so big.
// global json object array
var treeViewData = [
{
"nodeData": {
"physicalid": "A",
"rootToNode": "A-0",
"level": "0",
"attribute": "English-english"
},
"children": [
{
"nodeData": {
"physicalid": "B",
"rootToNode": "A-0:B-1",
"level": "1",
"attribute": "Finish-finish"
},
"children": []
},
{
"nodeData": {
"physicalid": "C",
"rootToNode": "A-0:C-1",
"level": "1",
"attribute": "Arabic-arabic"
},
"children": [
{
"nodeData": {
"physicalid": "D",
"rootToNode": "A-0:C-1:D-2",
"level": "2",
"attribute": "Spanish-spanished"
},
"children": []
}
]
}
]
}
]
Here is the update method. rootToNode is unique.
findAndUpdateNodeIterative: function(selfNodeRootPath, updatedNode) {
console.log("+++++++++ findAndUpdateNodeIterative ++++++++");
var thisContext = this;
var currentNode = thisContext.treeViewData[0];
var i, currentChild, result;
var flag = true;
while (flag) {
if (currentNode.nodeData.rootToNode === selfNodeRootPath) {
currentNode.nodeData.attribute = updatedNode.nodeData.attribute;
flag = false;
} else {
let it = true;
for (i = 0; i < currentNode.children.length && it; i += 1) {
currentChild = currentNode.children[i];
var currentNodeLevel = parseInt(currentChild.nodeData.level);
var targetPhysicalId = selfNodeRootPath.split(':')[currentNodeLevel].split("-")[0];
if (targetPhysicalId === currentChild.nodeData.physicalid) {
// Search in the current child
currentNode = currentChild;
it = false;
}
}
}
}
console.log("---------- findAndUpdateNodeIterative ---------");
},
usage
var updatedNode = {
"nodeData": {
"physicalid": "D",
"rootToNode": "A-0:C-1:D-2",
"level": "2",
"attribute": "Spanish-spanish"
},
"children": []
};
thisContext.findAndUpdateNodeIterative(updatedNode.nodeData.rootToNode, updatedNode);
console.log(thisContext.treeViewData); // **not updated**
RequireJS Code structure,
// about 4000 lines are present in this module
define("CustomModule", ["fewModules"], function(fewModules) {
var widget = {
init: function() {
this.treeViewData = '';
},
// many methods are here
update: function() {
var thisContext = this;
// rest api call brings the data nodesMap
for (let selectedObject of nodesMap.values()) {
// many lines
thisContext.findAndUpdateNodeIterative(updatedNode.nodeData.rootToNode, updatedNode);
console.log(thisContext.treeViewData); // not updated treeViewData
}
}
};
return widget;
}
Array looks like this:
"myTags":
[{
"type":"one",
"value":"Testing",
"note":"Hey"
},{
"type":"two",
"value":"Yg5GE",
"note":"hey2"
}]
I need to convert type:'one' value 'Testing' into lowercase i.e. value = Testing needs to be 'testing'. Is there a way to so this keeping the same structure?
Note: "type":"one","value":"Testing", may not always be included in the array. So I guess in this scenario I first need to do a check if they exist?
I have tried .map, however I am unable to get the result I want. Any help would be appreciated.
Ideal structure:
"myTags":
[{
"type":"one",
"value":"testing",
"note":"hey"
},{
"type":"two",
"value":"Yg5GE",
"note":"hey2"
}]
Iterate over the elements in myTags, check if type is "one" and only then change the content of value to lowercase (if present)
var data = {
"myTags": [{
"type": "one",
"value": "Testing",
"note": "Hey"
}, {
"type": "one",
"note": "Hey"
}, {
"type": "two",
"value": "Yg5GE",
"note": "hey2"
}]
};
data.myTags.forEach(function(tag) {
if (tag.type === "one" && typeof tag.value !== "undefined") {
tag.value = tag.value.toLowerCase();
}
});
console.log(data.myTags);
You may also first filter the content of myTags to get the element(s) with "type": "one" and only iterate over those element(s)
var data = {
"myTags": [{
"type": "one",
"value": "Testing",
"note": "Hey"
}, {
"type": "one",
"note": "Hey"
}, {
"type": "two",
"value": "Yg5GE",
"note": "hey2"
}]
};
data.myTags
.filter(function(tag) {
return tag.type === "one";
})
.forEach(function(tag) {
if (typeof tag.value !== "undefined") {
tag.value = tag.value.toLowerCase();
}
});
console.log(data.myTags);
This one works perfectly
$(document).ready(function(){
var objects ={"myTags":
[{"type":"one","value":"Testing", "note":"Hey"}
,{ "type":"two", "value":"Yg5GE", "note":"hey2"}]};
var obj = objects.myTags.map(function(a) {
a.value = a.value.toLowerCase();
return a;
});
console.log(obj);
});
output:
{type: "one", value: "testing", note: "Hey"}
{type: "two", value: "yg5ge", note: "hey2"}
Thank you
Achieve this very simply by using an arrow function and the map() method of the Array
var words = ['Foo','Bar','Fizz','Buzz'].map(v => v.toLowerCase());
console.log(words);
I have an ASP.NET MVC 4 application where a list of classes, with their full namespaces, are bound to a listbox. This generates HTML as follows:
<select id="myclasses">
<option>Api.Domain.Interfaces.MyClass1</option>
<option>Api.Domain.Interfaces.MyClass2</option>
<option>Api.Domain.Interfaces.MyClass3</option>
<option>Api.Domain.Models.MyModel1</option>
<option>Api.Domain.Models.MyModel2</option>
<option>Api.Infrastructure.Repositories.MyRepo1</option>
<option>Api.Infrastructure.Repositories.MyRepo2</option>
</select>
I would like to use JavaScript/jQuery to generate a JSON representation of this HTML stored in a variable as follows:
var classes =
[{ "text": "Api", "children":
[{ "text": "Domain", "children":
[{ "text": "Interfaces", "children":
[{ "text": "MyClass1" }, { "text": "MyClass2" }, { "text": "MyClass3" }]
},
{ "text": "Models", "children":
[{ "text": "MyModel1" }, { "text": "MyModel2" }]
}]
},
{ "text": "Infrastructure", "children":
[{ "text": "Repositories", "children":
[{ "text": "MyRepo1" }, { "text": "MyRepo2" }]
}]
}]
}];
The fully qualified class names are already in a tree-like structure, so I would imagine that there should be a fairly easy way to achieve what I'm trying to do. Should I be getting the inner HTML of the element using $("#myclasses").html() and then performing string manipulations, or is there a simpler way?
Here is a try with Jquery, though you'll have an empty list of children for the last element. Could be modified if that's a problem.
I added multi selection also to give a shot.
http://jsfiddle.net/c8e7kkhh/1/
$(function() {
$("#button").click(function(){
var output = [];
var input = $( "#myclasses option:selected" );
for (var i = 0; i < input.length; i++) {
var chain = input[i].text.split(".");
var currentNode = output;
for (var j = 0; j < chain.length; j++) {
var wantedNode = chain[j];
var lastNode = currentNode;
for (var k = 0; k < currentNode.length; k++) {
if (currentNode[k].text == wantedNode) {
currentNode = currentNode[k].children;
break;
}
}
// If we couldn't find an item in this list of children
// that has the right name, create one:
if (lastNode == currentNode) {
var newNode = currentNode[k] = {text: wantedNode, children:[]};
currentNode = newNode.children;
}
}
}
$("#result").html(JSON.stringify(output));
});
});
What i would like to happen is when i select an item from the first selection box, the 2nd selection box populates from a parseJSON.
I have 2 selection boxes: #web and #cats
web: has (at the moment) 3 options - All Websites (value=0), Website 1 (value=1) and Website 2 (value=2)
When i select from #web i should only get the categories for that particular website, however in PHP i have already considered "All Websites" and it duplicates the categories into each web object, but i also added "All Websites" to the json array, so that if it is reselected the selection box will repopulate.
This is the PHP Function (To create the JSON):
function catWebMix($user) {
$categories = getCategories($user);
$webAll = array('ID'=>0, 'WebID'=>'All', 'WebName'=>'All Websites');
$webSites = getWebsites($user);
array_unshift($webSites,$webAll);
$output = array();
foreach ($webSites as $k => $v) {
$output[$k] = $v;
foreach ($categories as $key => $value) {
if ($value['WebID'] == '0') {
$value['WebID'] = $v['ID'];
$output[$k]['Category'][] = $value;
} else if ($value['WebID'] == $v['ID']) {
$output[$k]['Category'][] = $value;
}
}
}
return array($output, json_encode($output));
exit;
}
I assign a variable to Smarty.
$webCats = catWebMix($user);
$smarty->assign('webCats', $webCats);
I then call it in JQuery. This is my failed attempt at creating the selection boxes change, im unsure on how to do it.
<script type="text/javascript">
var obj = $.parseJSON({$webCats[1]});
$('#web').on('change', function () {
var web = $(this).val();
$.each(obj, function () {
if (web == obj.ID) {
$.each(obj.Category, function (i,v) {
$('#cats').append("<option>"+v[3]+"</option>");
});
}
});
});
</script>
What i want it to do:
Remove all option attributes in #cats
Repopulate #cats with the data from the parseJson, based on the value from #web. #web value = (first) ID in JSON.
Place Category.ID as value for option, and Category.CatTitle as text
The json array looks like the following:
[
{
"ID": 0,
"WebID": "All",
"WebName": "All Websites",
"Category": [
{
"ID": "1",
"WebID": 0,
"CatTitle": "Category 1"
}
]
},
{
"ID": "1",
"WebID": "web1",
"WebName": "Website 1",
"Category": [
{
"ID": "1",
"WebID": "1",
"CatTitle": "Category 1"
},
{
"ID": "2",
"WebID": "1",
"CatTitle": "Category 2"
}
]
},
{
"ID": "2",
"WebID": "web2",
"WebName": "Website 2",
"Category": [
{
"ID": "1",
"WebID": "2",
"CatTitle": "Category 1"
}
]
}
]
Thanks for any help!
I did it! This was the code i used in case others have issues.
<script type="text/javascript">
var webCats = {$webCats[1]};
$('#web').on('change', function () {
var web = $(this).val();
$.each(webCats, function (k, o) {
if (web == o.ID) {
$('#cats option').remove();
$.each(o.Category, function (i, v) {
$('#cats').append("<option value=\""+v.ID+"\">"+v.CatTitle+"</option>");
});
}
});
});
</script>