I have input fields, which are created based on my arrays in my JSON file.
However, when I insert something in my input fields, it goes right until I start inserting stuff in the input fields that aren't part of the other input fields. Don't worry, more explaining to come.
This is how my JSON looks like:
{
"main_object": {
"id": "5",
"getExerciseTitle": "TestFor",
"language": "nl_NL",
"application": "lettergrepen",
"main_object": {
"title": "TestFor",
"language": "nl_NL",
"exercises": [{
"word": "test",
"syllables": [
"test01",
"test02",
"test03",
""
]
},
{
"word": "tesst",
"syllables": [
"test11",
"test12",
"",
""
]
}
]
},
"dataType": "json"
}
}
As you can see I have multiple arrays called syllables. What I am trying to do is: Create the push until it reaches the matched array in JSON, it should then change the input fields to buttons. However, when I go over to the next input fields that are linked to the second array, instead of starting the push from 0 it keeps on going.
A picture for you to see what I mean (note the console.log() too).
So: Instead of having the push start over it keeps on adding it to the already existing array. I want this NOT to happen so I can later on make a check that checks whether the push equals the array and then assign all the desired input fields to green buttons.
This is how my code looks like right now:
var x = [];
function prepareCheck() {
$.getJSON('json_files/jsonData_' + ID + '.json', function(json) {
$(document).on('change', '.syl-input', function() {
var rowCounter = $(this).parent().parent().parent().parent().attr('id');
var inputCounter = $(this).attr('id');
var jsyl = json.main_object.main_object.exercises[rowCounter].syllables[inputCounter];
var jsylall = json.main_object.main_object.exercises[rowCounter].syllables;
var valueInput = $(this).val();
console.log(jsylall);
if (valueInput == jsyl) {
var correctInput = $('<input/>', {
'class': 'form-control',
'type': 'text',
'id': 'button' + CBC++,
'value': valueInput
});
console.log(jsyl);
x.push(valueInput);
if (valueInput == '') {
x.remove($(this).val());
};
console.log(x);
$(this).replaceWith(correctInput);
S.playRight();
S.addRight();
} else if ($.inArray(valueInput, jsylall) >= -1) {
$(this).css({
'color': '#e00413'
});
S.playWrong();
S.addWrong();
}
});
});
}
Question: How can I reset x.push again? so I can keep on checking whether the input fields have the desired words/length to change them to green buttons?
Related
I am using the following to check for duplicate values in an array before I add a value:
vm.onGridItemChanged = function (resource) {
if (vm.modifiedItems.indexOf(resource) === -1) {
vm.modifiedItems.push(resource);
}
};
This works great and gives me behaviour I want. However I now have need to add EnglishValue also, so I have changed to:
vm.onGridItemChanged = function (resource, englishText) {
var modifiedItem = {Resource: resource, EnglishValue: englishText};
if (vm.modifiedItems.indexOf(modifiedItem) === -1) {
vm.modifiedItems.push(modifiedItem);
}
};
However this breaks the functionality and I am now getting duplicate values? Why would this be the case?
Edit - my josn includes $$hashKey values that is still causing duplicate issues:
[
{
"Resource": {
"ResourceId": "Account_AccountVerified_Success_Title",
"LocaleId": "de",
"ResourceSet": "/WebResources",
"Value": "Erfolg55",
"Comment": "Success",
"Editing": false,
"$$hashKey": "object:3861"
},
"EnglishValue": "Success",
"$$hashKey": "object:40483"
},
{
"Resource": {
"ResourceId": "Account_AccountVerified_Success_Title",
"LocaleId": "de",
"ResourceSet": "/WebResources",
"Value": "Erfolg55",
"Comment": "Success",
"Editing": false,
"$$hashKey": "object:3861"
},
"EnglishValue": "Success",
"$$hashKey": "object:40488"
}
]
You have to convert the JSON object to string and check its index. Since, you have $$hashkey in your object, you first need to remove that by angular.toJson
vm.onGridItemChanged = function (resource, englishText) {
var modifiedItem = {Resource: resource, EnglishValue: englishText};
var modifiedItems = angular.toJson(vm.modifiedItems);
if (JSON.stringify(modifiedItems).indexOf(JSON.stringify(modifiedItem)) === -1) {
vm.modifiedItems.push(modifiedItem);
}
};
var a = [{'d':'dasdasd','e':'dasdasda'}, {'d':'dasdasd','e':'dada'}];
var b = {'d':'dasdasd','e':'dasdasda'};
var index = JSON.stringify(a).indexOf(JSON.stringify(b));
console.log(index);
See that we get the index of the JSON object that exist in the string. Likewise, index will be -1 if not present on the JSON array.
I am trying to find a way to populate form with multitiude of option types, selects , radios, texareas, checkboxes. I found few scripts like jQuery populate plugin or suggestions here Using jQuery and JSON to populate forms? and many more stack posts but none of them handle the multidimensional JSON data properly. This is the small sample of JSON data I am dealing with ,
var jsonData = {
"get_template": "clean",
"site_width": "1200px",
"layout_type": "full",
"main_contained": {
"picked": "contained",
"notcontained": {
"container_contained": "contained"
}
},
"container_spacing": "25",
"columns_spacing": "25",
"sidebars_spacing": {
"horizontal": "50",
"vertical": "50"
},
"headers": "menuright",
"menu_template": "menuinheader",
"toplevel_font": {
"font": "Open Sans|600|latin|uppercase|default",
"size": "12",
"letterspacing": "0",
"css": "font-family:'Open Sans',sans-serif;font-weight:600;font-style:normal;font-size:12px;text-transform:uppercase;",
"google_font_link": "Open Sans:600&subset=latin"
},
"sublevel_font": {
"font": "Open Sans|regular|latin|none|default",
"size": "14",
"letterspacing": "0",
"css": "font-family:'Open Sans',sans-serif;font-weight:normal;font-style:normal;font-size:14px;",
"google_font_link": "Open Sans:regular&subset=latin"
},
"footer_switch": 1,
"show_button": {
"picked": "hide",
"show": {
"button": {
"button_text": "Load more",
"html": "<div class=\"btn-container grid-item-more\"><a class=\"button btn-small radius-4 btn-border-1 align-center btn-trans\" href=\"#\"><span class=\"btn-text fs-13 fw-600\">more</span></a></div>",
"json": "{\"createButton\":\"on\",\"buttonTransition\":\"on\",\"buttonAnimation\":false}"
}
}
},
"img-smaller": {
"max-width": "260",
"max-height": "145"
},
"img-xsmall": {
"max-width": "120",
"max-height": "65"
},
"img-related": {
"max-width": "350",
"max-height": "350"
},
"custom_css": 0,
"disable_admin_bar": false,
"footer_section": {
"json": "[{\"type\":\"section\",\"shortcode\":\"section_e603095\",\"width\":\"\",\"_items\":[{\"type\":\"columns\",\"shortcode\":\"columns_a9ae4ee\",\"width\":\"1_3\",\"options\":{\"widget_name\":\"Widget 1\",\"widget_in_boxstyle\":{\"padding\":{\"top\":\"0\",\"right\":\"0\",\"bottom\":\"0\",\"left\":\"0\"}]"
}
};
and as you can see the form can have text , json, booleans, and so on as values.
Form input names are prefixed like this fw_options[link_color] or fw_options[main_contained][picked]
If I could ad least find a way to properly loop trough this json to rebuild the input names in the right way I might get a way with just checking the input type and setting its value.
Any help is appreciated.
Unfortunately, the code will be a mess, buts here's what you need to do.
Figure out how to loop for all of them, unfortunately I can only suggest that somewhere you call itself with a child such the below code using mock variables:
function jsonloop(looper){ //pass in object/array to loop through
if(lastchild){ //if last child of the lower part
upperchild++; //go to next child of upper part
jsonloop(upperchild);
}
}
Use instanceof to check the type:
if(json instanceof Array){
for(var item in json){
var jsonarray = json[item];
//do stuff
}
} else if(json instance of Object){
for(var item in json){
var jsonobject = json[item];
//do different stuff like below
for(var name in jsonobject){ //loop through object properties
//do other stuff
}
}
}
This is all mock code!
Do not use as it is, it will not end well. Note: The end result will likely be semi-massive due to stuff like, "json": [{}] where is both an object and an array, and you're code will bomb. Here are some good resources:
JSON name iteration
Convert to array (may or may not be useful).
Find if json array (also works with object, just replace with Object).
Good luck. I'm sorry, I couldn't build more.
I have JSON data and that JSON data has parent child relation . I Want to create tree structure from it. i found many plugins and libraries but i can't found my requirement . I am getting this JSON data using PHP script.
Here is image that has tree structure that i want to create . i'm stuck at it.I know JSON is not as displayed in image but i only want to show you what a tree should look like .How to create tree like in image.All i want is javascript code to handle and create this type of structure of tree . Working example is must & much appreciated.
You can use JSON format as you like and tree should be collapsible.Also provide required JSON format for it.
and my JSON data as follows :
{
"2":
{
"5": "Wrist Watch"
},
"5":
{
"9": "Men's"
},
"18":
{
"3": "Clothing"
},
"28":
{
"1": "Perfumes"
},
"29":
{
"7": "Laptop",
"10": "Tablets"
},
"30":
{
"8": "Mobile"
},
"31":
{
"2": "Books"
},
"33":
{
"6": "Electronics"
},
"34":
{
"4": "Home & Kitchen\n"
}
}
If you want to roll your own, the keyword in "trees" is recursion. It needs to support any depth of data and the code and data should both support recursion.
This means your JSON data should be a recursive structure, where each node looks the same (and looks something like this):
{
id: 1, // data id
title: "title", // display title
children: [ // list of children, each with this same structure
// list of child nodes
]
}
Note: I have changed the sample data to contain more depth as 2 levels never shows up recursion problems.
e.g.:
{
id: 0,
title: "root - not displayed",
children: [{
id: 1,
title: "Option 1",
children: [{
id: 11,
title: "Option 11",
children: [{
id: 111,
title: "Option 111"
}, {
id: 112,
title: "Option 112"
}]
}, {
id: 12,
title: "Option 12"
}]
}, {
id: 2,
title: "Option 2",
children: [{
id: 21,
title: "Option 21"
}, {
id: 22,
title: "Option 22"
}]
}, {
id: 3,
title: "Option 3",
children: [{
id: 31,
title: "Option 31"
}, {
id: 32,
title: "Option 32"
}]
}]
}
The recursive function looks like this:
function addItem(parentUL, branch) {
for (var key in branch.children) {
var item = branch.children[key];
$item = $('<li>', {
id: "item" + item.id
});
$item.append($('<input>', {
type: "checkbox",
name: "item" + item.id
}));
$item.append($('<label>', {
for: "item" + item.id,
text: item.title
}));
parentUL.append($item);
if (item.children) {
var $ul = $('<ul>').appendTo($item);
addItem($ul, item);
}
}
}
JSFiddle: http://jsfiddle.net/0s0p3716/188/
The code recurses the structure, adding new ULs and LIs (with checkbox etc ) as it goes. The top level call just provides the initial root starting points of both the display and the data.
addItem($('#root'), data);
The end result looks like this:
If you want to toggle visibility, based on the checked state, use this:
$(':checkbox').change(function () {
$(this).closest('li').children('ul').slideToggle();
});
If you also want the labels to toggle the checkboxes, use this:
$('label').click(function(){
$(this).closest('li').find(':checkbox').trigger('click');
});
Note: I have only provided the most basic of styling as that will typically be "to taste". Examples in links were shown in another answer.
-- updated:
amended: possible wrong ids for items 31 & 32?
function for better selection and deselection(for parents cascading into child nodes):
$(function () {
addItem($('#root'), data);
$(':checkbox').click(function () {
$(this).find(':checkbox').trigger('click');
var matchingId = $(this).attr('id');
if ($(this).attr('checked'))
{
$('input[id*=' + matchingId +']').each(function() {
$(this).removeAttr('checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
else {
$('input[id*=' + matchingId +']').each(function() {
$(this).attr('checked', 'checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
});
$('label').click(function(){
$(this).closest('li').children('ul').slideToggle();
});
-- Update the fiddle with this as shown here(JsFiddle) and it will work better and also will allow you to click the text to expand without selecting at the same time - I know I find this far more useful. It will help (and this is personal preference) you to see what values and options are available without having to select the first.
The thing with programming is: existing libraries and tools rarely do exactly what you need. It's always up to you to convert the input data into exactly the format they expect and then the output data into the format you need. Occasionally this conversion requires more effort than writing your own code instead of a library function - this seems to be one of those occasions.
As #philosophocat already noted, the best way to present such a tree in HTML markup would be nested lists. All you need is iterate through the JSON data recursively and create the corresponding elements:
function createList(data)
{
var result = document.createElement("ul");
for (var key in data)
{
if (!data.hasOwnProperty(key) || key == "_title")
continue;
var value = data[key];
var item = createItem(key, typeof value == "string" ? value : value._title);
if (typeof value == "object")
item.appendChild(createList(value));
result.appendChild(item);
}
return result;
}
function createItem(value, title)
{
var result = document.createElement("li");
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("name", "selection");
checkbox.setAttribute("value", value);
result.appendChild(checkbox);
result.appendChild(document.createTextNode(title));
return result;
}
document.body.appendChild(createList(jsonData));
Note that the order in which the items appear is "random" here, as object keys are generally unordered. You can change the code above to sort the keys somehow, or you can change the data to use arrays and define an order. I also added a "_title" property to the data to make sure the categories are labeled - your data doesn't have any labels at all for the categories.
Now you need to style the lists in such a way that they look like a tree. The obvious solution is using the list-style-image CSS property to replace the usual bullet points by a grid lines image. However, that doesn't work for nested lists - there you need to show multiple images, vertical lines from the higher-level lists as well as the image actually belonging to the current list item.
This can be solved by using background images for the list items instead, these background images will be shown next to sublists as well then. Here are the example styles I've got:
ul
{
padding: 0;
list-style-type: none;
font-size: 14px;
}
li
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAABkCAYAAABdELruAAAAP0lEQVR42u3PQQoAIAgEQP3/o6t7JAhdolkQD4sMZuwZazKKlGXniHRDOu6HfyKRSCQSiUQikUgkEolEIv0rTc/fNmQ78+lPAAAAAElFTkSuQmCC);
background-repeat: no-repeat;
padding-left: 13px;
}
li:last-child
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAHUlEQVR42mNkwAT/gZiRAQ/AK0mKplGbqGETThoACFgJCVdBEqAAAAAASUVORK5CYII=);
}
li > ul
{
margin-left: 5px;
}
Note that this will still get ugly if the sublist is too high - the height of the background image I used is merely 100px. This can be solved by using a larger background image of course. A cleaner alternative would be using border-image-slice CSS property but that one is currently only supported in Firefox.
Fiddle for this code
Edit: This article goes into more detail on styling nested lists like a tree. While the approach is similar, it manages to avoid the image size issues I mentioned above by using a separate image for the vertical line which can be repeated vertically. On the downside, that approach looks like it might only work with solid lines and produce artifacts if applied to dotted lines.
Use http://www.jstree.com/. This library provides each function I ever need when working with trees and javascript.
You simple have to change your json-response according to the given format (http://www.jstree.com/docs/json/):
{
id : "string" // will be autogenerated if omitted
text : "string" // node text
icon : "string" // string for custom
state : {
opened : boolean // is the node open
disabled : boolean // is the node disabled
selected : boolean // is the node selected
},
children : [] // array of strings or objects
li_attr : {} // attributes for the generated LI node
a_attr : {} // attributes for the generated A node
}
Set up the javascript and include all required files and there you go.
I just skip repeating the documentation by referring to it: http://www.jstree.com/
I'm using DynaTree for an internal site at work and it works fantastic.
Download DynaTree
Format your JSON as such (taking your screenshot as an example):
{
"title": "Sports & Outdoors",
"isFolder": true,
"key": "0",
"children": [
{
"title": "Fitness Accessories",
"key": "1",
"isFolder": true,
"children": [
{
"title": "Fitness Accessories",
"key": "2",
"isFolder": true,
"children": [
{
"title": "Pedometer & Watches",
"key": "3"
}
]
}
]
}
]
}
Run this JS on page load:
$("#buildTree").dynatree({
onActivate: function (node) {
// A DynaTreeNode object is passed to the activation handler
// Note: we also get this event, if persistence is on, and the page is reloaded.
leftActiveNodeKey = node.data.key;
},
persist: false,
checkbox: true,
selectMode: 3,
children: $.parseJSON(response.d)
});
To get the selected nodes you can use:
var selectedNodes = $("#buildTree").dynatree("getTree").getSelectedNodes();
Dynatree is pretty customization, both in look and function. Read through the documentation for the settings you need.
Check these sites.Hope this helps.
http://www.jstree.com/docs/json/
http://www.jeasyui.com/documentation/tree.php
http://jqwidgets.com/jquery-widgets-demo/demos/jqxtree/index.htm#demos/jqxtree/checkboxes.htm
#Gone Coding's example is excellent, but the child check boxes will not show as 'uncheked' even though the checked attribute is removed, as rendered in Chrome.
If you add,
$(this).prop('checked', false);
to the code, so it reads as
$(function () {
addItem($('#root'), data);
$(':checkbox').click(function () {
var matchingId = $(this).attr('id');
if ($(this).attr('checked'))
{
$('input[id*=' + matchingId +']').each(function() {
$(this).removeAttr('checked');
$(this).prop('checked', false);
$(this).prop('checked', $(this).attr('checked'));
return;
});
}
else {
$('input[id*=' + matchingId +']').each(function() {
$(this).attr('checked', 'checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
});
$('label').click(function(){
$(this).closest('li').children('ul').slideToggle();
});
});
the child check boxes will fill or clear when the user makes a change.
I'm trying to build a nested array in jQuery based on a user's selection from a drop down menu. This will be used in a JSON request at a later date.
So far my code does produce (almost) the required result, however no matter order i select the options from my drop down menu, the output (which i log in the console at the end) is always the same.
$('#comboGenre').change(function () {
var values = $('#comboGenre').val();
var parsedJSON = JSON.parse($data); //Data returned from ajax request
for (var i = 0; i < values.length; i += 1) {
$genreList = parsedJSON.genre[i];
console.log($genreList);
}
});
So if i select RPG and Action from my drop down, the output gives me RPG and Driving. If i selected RPG, Driving and Action (in that order), i get what i would expect RPG, Driving and Action.
So it's just iterating through my JSON, when really it should be returning the 'selected' option.
How can i achieve this?
My JSON looks like this if it's useful:
{"genres": [{
"genre": "RPG",
"publishers": [{
"publisher": "Square",
"games": [{
"game": "FFX",
"rating": [
12, 15
]
}]
}]
},
{
"genre": "Driving",
"publishers": [{
"publisher": "Turn10",
"games": [{
"game": "Forza",
"rating": [
5
]
}]
}]
},
{
"genre": "Action",
"publishers": [{
"publisher": "EA",
"games": [{
"game": "COD",
"rating": [
18, 20
]
}]
}]
}
]}
EDIT:
I've also tried this:
$('#comboGenre').change(function () {
var parsedJSON = JSON.parse($data);
$genreList = "";
$.each(parsedJSON.genres, function(index, value){
$genreList = parsedJSON.genres[index];
console.log($genreList);
});
});
And i end up getting ALL the objects in my JSON, so from here, i'm only wanting to add the selected object to the $genreList variable.
If you broke out some of the logic and created a genre finding function and used the selected string to find the proper object you could then put the object into the variable you will use later. I do some checking to ensure that the genre that has been selected isn't already in my array which is because I am using the multiple select
JSFiddle: http://jsfiddle.net/vkTFq/
Code:
$(function(){
var selectedGenres = [];
var genres =[{"genre":"RPG","publishers":[{"publisher":"Square","games":[{"game":"FFX","rating":[12,15]}]}]},{"genre":"Driving","publishers":[{"publisher":"Turn10","games":[{"game":"Forza","rating":[5]}]}]},{"genre":"Action","publishers":[{"publisher":"EA","games":[{"game":"COD","rating":[18,20]}]}]}]
$('#comboGenre').change(function() {
$(this).find(":selected").each(function() {
var selectedGenre = findGenre($(this).val())
if (!genreAlreadySelected(selectedGenre.genre)) {
selectedGenres.push(selectedGenre);
};
});
console.log (JSON.stringify(selectedGenres));
});
function genreAlreadySelected(genre){
for(var i = 0; i < selectedGenres.length; i++){
if (genre == selectedGenres[i].genre) {
return true;
};
return false;
}
}
function findGenre(genre){
for(var i = 0; i < genres.length; i ++){
console.log(genre)
if(genre == genres[i].genre){
return genres[i];
}
}
};
});
I'm working with a response from the Webtrends API in Google apps script and I have a JSON/JS object that looks like this:
"data": [
{
"period": "Month",
"start_date": "2013-12",
"end_date": "2013-12",
"attributes": {},
"measures": {
"Visits": 500
},
"SubRows": [
{
"facebook.com": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"google.co.uk": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"newsnow.co.uk": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"No Referrer": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
},
"t.co": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
}
}
]
}
]
What I need to access is the names i.e facebook.com etc... and visit numbers for each of the SubRows.
I'm able to get the visit numbers, but I can't work out how to get the names. Please note the names will change constantly as different sites will send different amounts of traffic each day.
Section of my code at the moment where I get the visit numbers:
for(i in dObj){
var data = dObj[i].SubRows;
var sd = dObj[i].start_date;
var ed = dObj[i].end_date;
if(sd == ed){
var timep = ""+ sd;
}
else{
var timep = ""+ sd + "-" + ed;
}
var subRows = data[0];
Logger.log(subRows);
for(i in subRows){
var row = subRows[i];
var rmeasures = row.measures;
var rvis = rmeasures.Visits;
values = [timep,"",rvis]; //Blank string for where the name of the site would go
}
}
I've tried the following links, but none of them seem to have the answer:
Getting JavaScript object key list
How to access object using dynamic key?
How to access key itself using javascript
How do I access properties of a javascript object if I don't know the names?
I'm just using vanilla google apps script as I don't have any experience with Jquery etc...
Any help would be much appreciated!
I usually use a little helper function that looks like this:
var keyVal = function(o) {
var key = Object.keys(o)[0];
return {"key": key, "val":o[key]};
} ;
This will map an object with a variable key to a key/value object {key:...., val:{}}, which is usually convenient enough to work with.
describe.only ("stack overflow answer", function(){
it ("is should create a key/value pair" , function(){
var res = keyVal( {
"facebook.com": {
"attributes": {},
"measures": {
"Visits": 100
},
"SubRows": null
}});
res.key.should.equal('facebook.com');
res.val.attributes.should.deep.equal({});
});
Within the loop, the variable i contains the current key. Replacing the empty string with i should give you what you need.
You might also want to look at some of the more functional tools built into Javascript. Some more concise code might also be more explicit:
data.map(function(datum) {
var timep = datum.start_date == datum.end_date ? datum.end_date :
(data.start_date + "-" + datum.end_date);
return datum.SubRows.map(function(subRow) {
return Object.keys(subRow).map(function(key) {
return [timep, key, subRow[key].measures.Visits];
});
});
});
would return an object something like this:
[
[
[
["2013-12", "facebook.com", 100],
["2013-12", "google.co.uk", 100],
["2013-12", "newsnow.co.uk", 100],
["2013-12", "No Referrer", 100],
["2013-12", "t.co", 100 ]
]
]
]
This just uses map and Object.keys to simplify some of what you're doing with explicit loops.