Convert UL into JSON object - javascript

I need to convert an entire UL and it's children elements into a JSON object.
This is what we did:
function getData(el) {
el.find('li').each(function () {
data.push({ "nome": $(this).find('span').html(), "cargo": $(this).find('strong').html() });
});
}
JS Fiddle: https://jsfiddle.net/cbzo0ef2/2/
But all elements are in the same level. In this case, all levels need to be kept.

$(this).parents("ul").length would be trick for you:
function getData(el) {
el.find('li').each(function () {
data.push({ "nome": $(this).find('span').html(), "cargo": $(this).find('strong').html(), "dept": $(this).parents("ul").length })
});
}
You need extra work to render dept to your json structure
see fiddle

This solution will retain the levels in your HTML:
(function($) {
function getData(el) {
var data = [];
el.children('li').each(function () {
var currentElement = $(this);
var nomeElement = currentElement.children('span')[0];
var cargoElement = currentElement.children('strong')[0];
var item = {};
if (nomeElement && cargoElement) {
item.nome = $(nomeElement).html();
item.cargo = $(cargoElement).html();
}
data.push(item);
var child = currentElement.children('ul')[0];
if (child != null) {
item.children = getData($(child));
}
});
return data;
}
var data = getData($('.root'));
console.log(data);
})(jQuery);
See fiddle: https://jsfiddle.net/52t58551/

Using jQuery Children and some recursion you can get every node.
(function($) {
function getData(el) {
var curr = [];
el.children('li, ul').each(function(i, child) {
curr.push({
nodeName: child.nodeName,
nome: $(child).find("> span").text(),
cargo: $(child).find("> strong").text(),
subLevel: getData($(child))
});
});
return curr
}
var result = getData($('.root'));
console.log(JSON.stringify(result));
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="root"> <li><span>a</span><strong>b</strong></li><li><span>c</span><strong>d</strong></li><li><span>e</span><strong>f</strong></li><li> <ul> <li><span>g</span><strong>h</strong></li><li><span>i</span><strong>j</strong></li><li> <ul> <li><span>k</span><strong>l</strong></li></ul> </li></ul> </li></ul>

Related

Set entire select values with jQuery

I would like to know the best way to populate a select element using jQuery given a hash as seed data.
Ex:
var select_options = {
"option1": ["item1", "item2"],
"option2": ["item3", "item4"]
};
Using different hash keys to set up the select seed data.
Are you looking for something like this. But have to check if somebody has a better way of doing this.
var select_options = {
"option1": ["item1", "item2"],
"option2": ["item3", "item4"]
};
$(function() {
var selectedOption = "option1";
$.map(select_options, function(val, key) { //object
if (key == selectedOption) {
$.map(val, function(item, index) { //array
console.log(item + " " + index);
});
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Compare key of the object or directly access value of object with key. Here are two working example.
Comparing key.
var select_options = {
"option1": ["item1", "item2"],
"option2": ["item3", "item4"]
};
$(function() {
var selectedOption = "option1";
createDropdown(selectedOption);
function createDropdown(selectedOption){
$('select').html("");
$.map(select_options, function(val, key) { //object
if (key == selectedOption) {
$.map(val, function(item, index) { //array
$('select').append($("<option>").attr('value',index).text(item));
});
}
});
}
$('div').on('click', function() {
createDropdown($(this).attr('data-option'));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-option="option1">click for option1</div>
<div data-option="option2">click for option2</div>
<select>
</select>
Accessing value with key.
var select_options = {
"option1": ["item1", "item2"],
"option2": ["item3", "item4"]
};
$(function() {
var selectedOption = "option1";
createDropdown(selectedOption);
function createDropdown(selectedOption){
$('select').html("");
var array = select_options[selectedOption];
$.map(array, function(item, index) { //array
$('select').append($("<option>").attr('value',index).text(item));
});
}
$('div').on('click', function() {
createDropdown($(this).attr('data-option'));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-option="option1">click for option1</div>
<div data-option="option2">click for option2</div>
<select>
</select>

Angular List color change based ng-click

I am using angularjs I have two list when I click first one I will push the value into another scope and bind the value to second list. Now my requirement is when first list values which are moved to second list, I need to change the color of moved values in list1
Here I attached my fiddle
Fiddle
You can use findIndex and ng-class together to check if the second list contains the same item as first. If present apply css class to the first list item.
JS:
$scope.checkColor = function(text) {
var index = $scope.linesTwos.findIndex(x => x.text === text);
if (index > -1) return true;
else return false;
}
HTML:
<li ng-click="Team($index,line.text)" ng-class="{'change-color':checkColor(line.text)}">{{line.text}}</li>
Working Demo: https://jsfiddle.net/7MhLd/2659/
You can do something like this:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.lines = [{
text: 'res1'
},
{
text: 'res2'
},
{
text: 'res3'
}
];
$scope.linesTwos = [];
$scope.Team = function(index, text) {
var obj = {};
obj.text = text;
$scope.linesTwos.push(obj)
}
$scope.Team2 = function(index, text2) {
$scope.linesTwos.splice(index, 1)
}
$scope.containsObj = function(obj, list) {
var i;
for (i = 0; i < list.length; i++) {
if (angular.equals(list[i], obj)) {
return true;
}
}
return false;
};
}
.clicked {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<ul ng-repeat="line in lines">
<li ng-class="{'clicked': containsObj(line,linesTwos)}" ng-click="Team($index,line.text)">{{line.text}}</li>
</ul>
<ul>
<li>__________</li>
</ul>
<ul ng-repeat="line in linesTwos">
<li ng-click="Team2($index,line.text)">{{line.text}}</li>
</ul>
</div>
you have to achieve it using ng-class and create a dynamic class style for pushed data please check my working example fiddle
JS fiddle sample
in HTML nedd to do these changes
<li ng-click="Team($index,line.text,line)" ng-class="{'pushed':line.pushed}">
<li ng-click="Team2($index,line.text,line)">
In css
.pushed{color:red;}
In Controller
`$scope.Team=function(index,text,line){
var obj={};
obj = line;
$scope.linesTwos.push(obj)
line.pushed = true;
}`
`scope.Team2 = function(index,text2,line){
$scope.linesTwos.splice(index,1)
line.pushed = false;
}
`
its because angular two way binding

How can i search ordered list using the "each" function in JQuery

I want to do this loop using jquery but I can't do it.
This is my code
this.isFound = function (li, text){
for(var i = 0; i<li.length; i++){
if(li[i].innerHTML == text){
this.showError("Sorry, You can't enter a string twice");
return true;
break;
}
}
return false;
};
This is my JQuery loop
$.each(this.list, function(i, item){
if(this.text == item.innerHTML){
return true;
}
});
How can I do that using each or grep or any function else in JQuery?!
thanks in advance
You can use $.grep() to return an array of matches, or .filter() to return a jQuery collection of elements, where the return value of the callback should be Boolean true or false
$.grep()
$(function() {
var text = "abc";
var res = $.grep($("li"), function(el, index) {
return el.textContent === text
});
// `res` is an array containing one or more `DOM` elements
console.log(res);
res[0].style.color = "red";
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<ul>
<li>abc</li>
<li>def</li>
<li>ghi</li>
</ul>
.filter()
$(function() {
var text = "def";
var res = $("li").filter(function(index, el) {
return el.textContent === text
});
// `res` is a jQuery object containing one or more `DOM` elements
// where jQuery methods can be chained
console.log(res);
res.css("color", "green");
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<ul>
<li>abc</li>
<li>def</li>
<li>ghi</li>
</ul>
If you are trying to determine if a given element has .textContent, and if true do stuff, you can use .is(), which returns a Boolean; either true or false
$(function() {
var text = "ghi";
var i = 0;
var res = $("li").is(function(index, el) {
i = index;
return el.textContent === text
});
// `res` is a `Boolean`
console.log(res);
if (res) {
alert(text + " has already been set");
$("li").eq(i).css("color", "gold");
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<ul>
<li>abc</li>
<li>def</li>
<li>ghi</li>
</ul>

Couldn't append span element to array object in Angularjs/Jquery

Am struggling hard to bind an array object with list of span values using watcher in Angularjs.
It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).
The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.
DemoCode fiddle link
What am I missing in my code?
How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?
Please note that values will get changed any time as per a chart.
This is the code am using:
<script>
function rdCtrl($scope) {
$scope.dataset_v1 = {};
$scope.dataset_wc = {};
$scope.$watch('dataset_wc', function (newVal) {
//alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
$('#status').html(JSON.stringify($scope.dataset_wc));
}, true);
$(function () {
$('#tags input').on('focusout', function () {
var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
if (txt) {
//alert(txt);
$(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
var div = $("#tags");
var spans = div.find("span");
spans.each(function (i, elem) { // loop over each spans
$scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
id: i, // gives the id as "0,1,2.....n"
name: $(elem).text(), // push the text of the span in the loop
value: 3
}
});
$("#assign").click();
}
this.value = "";
}).on('keyup', function (e) {
// if: comma,enter (delimit more keyCodes with | pipe)
if (/(188|13)/.test(e.which)) $(this).focusout();
if ($('#tags span').length == 7) {
document.getElementById('inptags').style.display = 'none';
}
});
$('#tags').on('click', '.tag', function () {
var tagrm = this.innerHTML;
sk1 = $scope.dataset_wc;
removeparent(sk1);
filter($scope.dataset_v1, tagrm, 0);
$(this).remove();
document.getElementById('inptags').style.display = 'block';
$("#assign").click();
});
});
$scope.assign = function () {
$scope.dataset_wc = $scope.dataset_v1;
};
function filter(arr, m, i) {
if (i < arr.length) {
if (arr[i].name === m) {
arr.splice(i, 1);
arr.forEach(function (val, index) {
val.id = index
});
return arr
} else {
return filter(arr, m, i + 1)
}
} else {
return m + " not found in array"
}
}
function removeparent(d1)
{
dataset = d1;
d_sk = [];
Object.keys(dataset).forEach(function (key) {
// Get the value from the object
var value = dataset[key].value;
d_sk.push(dataset[key]);
});
$scope.dataset_v1 = d_sk;
}
}
</script>
Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.
You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/
function rdCtrl($scope){
$scope.dataset = [];
$scope.inputVal = "";
$scope.removeData = function(index){
$scope.dataset.splice(index, 1);
redoIndexes($scope.dataset);
}
$scope.addToData = function(){
$scope.dataset.push(
{"id": $scope.dataset.length+1,
"name": $scope.inputVal,
"value": 3}
);
$scope.inputVal = "";
redoIndexes($scope.dataset);
}
function redoIndexes(dataset){
for(i=0; i<dataset.length; i++){
$scope.dataset[i].id = i;
}
}
}
<div ng-app>
<div ng-controller="rdCtrl">
<div id="tags" style="border:none;width:370px;margin-left:300px;">
<span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
<div>
<input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
<button type="submit" ng-click="addToData()">Submit</button>
<img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />
</div>
</div>
<div id="status" style="margin-top:100px;"></div>
</div>
</div>

Firebase events not triggered properly when joining tables with Firebase-util

I'm using Firebase-util's intersection function to find all the comments for a given link. This seems to work fine the first time I call the join, but it doesn't seem to properly notify my value callback when I remove the contents of the database and replace them again. Shouldn't the references keep working as long as the resource path remains the same?
Run this example. When you click the button, it erases and recreates the data. As you can see, the comment list is not repopulated after the data gets recreated.
<link rel="import" href="https://www.polymer-project.org/components/polymer/polymer.html">
<script src="http://cdn.firebase.com/v0/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/firebase-util/0.1.0/firebase-util.min.js"></script>
<polymer-element name="my-element">
<template>
<h1>Test of Firebase-util.intersection</h1>
<div>
<button on-click={{initializeFirebase}}>Reset data</button>
</div>
<ul>
<template repeat="{{rootComment in comments}}">
<li>{{rootComment.comment.content}}
<ul>
<template repeat="{{subComment in rootComment.children}}">
<li>{{subComment.comment.content}}
<ul>
<template repeat="{{subSubComment in subComment.children}}">
<li>{{subSubComment.comment.content}}</li>
</template>
</ul>
</li>
</template>
</ul>
</li>
</template>
</ul>
</template>
<script>
Polymer('my-element', {
ready: function() {
var sanitizeUrl = function(url) {
return encodeURIComponent(url).replace(/\./g, '%ZZ');
};
var baseUrl = "https://nested-comments-test.firebaseio.com";
var linkUrl = baseUrl +
'/links/' +
sanitizeUrl(document.URL) +
'/comments';
var commentsUrl = baseUrl + '/comments';
var root = new Firebase(baseUrl);
this.initializeFirebase = function() {
function addLink(url, callback) {
var key = sanitizeUrl(url),
newLink = {
url: url,
createdAt: Firebase.ServerValue.TIMESTAMP
};
root.child('/links/' + key).update(newLink);
callback(key);
}
function addComment(attributes, callback) {
return root.child('/comments').push(attributes, callback);
}
function onCommentAdded(childSnapshot) {
var newCommentId = childSnapshot.name(),
attributes = {},
link = childSnapshot.val().link,
url = '/links/' + link + '/comments';
attributes[newCommentId] = true;
root.child(url).update(attributes);
}
root.remove(function() {
root.child('/comments').on('child_added', onCommentAdded);
addLink(document.URL, function(link) {
var attributes = {
link: link,
content: "This is the first comment."
},
firstCommentId, secondCommentId;
firstCommentId = addComment(attributes).name();
attributes = {
link: link,
content: "This is a reply to the first.",
replyToCommentId: firstCommentId
};
secondCommentId = addComment(attributes).name();
attributes = {
link: link,
content: "This is a reply to the second.",
replyToCommentId: secondCommentId
};
addComment(attributes);
attributes = {
link: link,
content: "This is another reply to the first.",
replyToCommentId: firstCommentId
};
addComment(attributes);
});
});
};
this.initializeFirebase();
var findChildrenForComment = function(snapshot, parentCommentId) {
var returnVal = [];
snapshot.forEach(function(snap) {
var comment = snap.val(),
commentId = snap.name();
if (comment.replyToCommentId === parentCommentId) {
var children = findChildrenForComment(snapshot, commentId);
var obj = {
commentId: commentId,
comment: comment,
parentId: parentCommentId
};
if (children.length) {
obj.children = children;
}
returnVal.push(obj);
}
});
return returnVal;
};
this.ref = Firebase.util.intersection(
new Firebase(linkUrl),
new Firebase(commentsUrl)
);
this.comments = {};
var that = this;
this.ref.on('value', function(snapshot) {
that.comments = findChildrenForComment(snapshot);
});
}
});
</script>
</polymer-element>
<my-element></my-element>
Apparently deleting a path entirely causes all callbacks on it to be canceled. The workaround for this behavior is to remove children one at a time rather than deleting their parent path.

Categories

Resources