Turning an array into a nested list - javascript

Pretty new to Angular, and I'm trying to do a sort of unconventional operation.
Say I have an array like this: ["A","B","C","D","E","F","G"];
I want to output HTML like this:
<ul>
<li>A</li>
<ul>
<li>B</li>
<ul>
<li>C</li>
<ul>
<li>D</li>
<ul>
<li>E</li>
<ul>
<li>F</li>
<ul>
<li>G</li>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
Essentially, I just want to keep nesting until I hit the end of the array. I'm having trouble figuring out how to do this. I don't have any code examples, unfortunately, because I'm having trouble how to do this without freezing the browser inside a while loop.
Nevertheless, here's what I've got:
<div class="trail" ng-include="'trail'"></div>
<script type="text/ng-template" id="trail">
<li>{{trailItem.content}}<li>
<ul ng-repeat="trailItem in post.trail" ng-include="'trail'">
</ul>
</script>
The above is meant to work with a data structure where post is an array of objects, of which content is a property.
However, this loops forever, and the browser freezes.

var ary = ["A", "B", "C", "D", "E", "F", "G"];
var $container = $('<div></div>');
var dom = $container;
for (var i = 0; i < ary.length; i++) {
dom = appendDom(dom, ary[i]);
}
function appendDom(dom, value) {
var $ul = $('<ul><li>' + value + '</li></ul>');
$(dom).append($ul);
return $ul;
}
alert($container.html());
The output is your need

I couldn't get it to work exactly with the one dimensional array like you posted but I did find a really good example with a jsfiddle at http://benfoster.io/blog/angularjs-recursive-templates
Also, here is what I have so far:
http://jsfiddle.net/haydenk/s19v2f1m/3/
<div ng-controller="MainCtrl">
<script type="text/ng-template" id="awesomeTree">
{{ awesomeThing }}
<ul ng-if="awesomeThings">
<li ng-repeat="awesomeThing in awesomeThings" ng-include="'awesomeTree'"></li>
</ul>
</script>
<ul>
<li ng-repeat="awesomeThing in awesomeThings" ng-include="'awesomeTree'"></li>
</ul>
</div>
var app = angular.module('testApp',['ngAnimate']);
app.controller('MainCtrl', function ($scope) {
$scope.awesomeThings = ['A','B','C','D','E','F','G','H'];
});

try this one .
HTML :
<div ng-controller="testCtrl">
<div add-ul-li arr-list-val=arrList>
</div>
</div>
JS :
app.controller("testCtrl",function($scope){
$scope.arrList = ["A","B","C","D","E","F","G"];
})
.directive("addUlLi",function(){
var finalHtml="";
return {
scope : {arrListVal: '='},
link: function(scope,ele,attr){
scope.arrListVal.reverse();
angular.forEach(scope.arrListVal,function(oneElement,key){
console.log(key)
if(key==0){
finalHtml = "<ul> <li>"+oneElement+"</li> </ul>";
}else{
finalHtml = "<ul> <li>"+oneElement+" "+finalHtml+"</li> </ul>";
}
if((key+1)==scope.arrListVal.length){
ele.append(finalHtml);
}
})
}
}
})
Check this plunker

Related

Checking an <a> elements text value against a string

I really need your help with coding this for me. How can I check an <a>'s text element against a string value to see if the tab already exists or not?
I apologize in advance as I am new to this and I am not sure how to accomplish this. An answer using jQuery is fine as well.
var x = "tabTwo"
Some new function here to check and see if the string value tabTwo matches any of the existing tab text values, return true or false.
Here is the HTML markup/structure:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<ul class="tabs">
<li><a href='#tab1'>tabOne</a></li>
<li><a href='#tab2'>tabTwo</a></li>
<li><a href='#tab3'>tabThree</a></li>
<li><a href='#tab4'>tabFour</a></li>
</ul>
</body>
</html>
You can target the a element with jQuery by giving it a class or id and targeting it like so.
$('#tab1');
And then you can get the value using .text() (or many other options)
$('#tab1').text();
And then you can compare it.
if ($('#tab1').text() === x) {
// Do stuff
}
You can further abstract this by assigning all the a tags a shared class and looping through them, and targeting using $(this).
$('.tab_link').each(function(){
if ($(this).text() === x) {
// Do stuff
}
});
I am not sure that understood your problem, but I'll provide you 2 solutions.
1) If you want to check using the id
function isTabExistsById(id) {
return $('.tabs a[href="#'+id+'"]').length > 0;
}
console.log(isTabExistsById('tab1')); // true
console.log(isTabExistsById('tab3')); // true
console.log(isTabExistsById('tabFour')); // false
console.log(isTabExistsById('tab5')); // false
<!DOCTYPE html>
<html>
<head></head>
<body>
<ul class="tabs">
<li><a href='#tab1'>tabOne</a></li>
<li><a href='#tab2'>tabTwo</a></li>
<li><a href='#tab3'>tabThree</a></li>
<li><a href='#tab4'>tabFour</a></li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</body>
</html>
2) If you want to check using the content
function isTabExistsByCaption(text) {
var result = false;
$('.tabs a').each(function() {
if ($(this).text().trim() == text) {
result = true;
return;
}
});
return result;
}
console.log(isTabExistsByCaption('tabOne')); // true
console.log(isTabExistsByCaption('tabFour')); // true
console.log(isTabExistsByCaption('tabFive')); // false
console.log(isTabExistsByCaption('tab3')); // false
<!DOCTYPE html>
<html>
<head></head>
<body>
<ul class="tabs">
<li><a href='#tab1'>tabOne</a></li>
<li><a href='#tab2'>tabTwo</a></li>
<li><a href='#tab3'>tabThree</a></li>
<li><a href='#tab4'>tabFour</a></li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</body>
</html>
Hope, I understood your problem. If no, could you explain it with more details, please?
Add a class to the a tag and then you can try :
var link = $('.link').text();
if(link == "some Value")
...
You could give a unique class attribute for you 'a' tags. and select the 'a' using jquery like this
$('.classname').each(function(){
if($(this).text() == 'tabTwo' { //here you have it
}
})
var match = "tabTwo"
var tabArray = document.querySelectorAll('li>a');
tabArray.forEach((elem)=>{
if(match === elem.innerText){
return true;
}
return false
});
At first, you have to get all <a> elements using $("a") and iterate through them via .each(function() {...}. Inside the loop, you have to check, does the text() of current element equal to needed string: if it is - then we change tabExists variable from false to true. In my example I have written separate function, so you can invoke it with any parameter you like. I have called checkTabExistence("tabTwo") which should log true and checkTabExistence("tabSix") which should log false:
$(document).ready(function() {
checkTabExistence("tabTwo");
checkTabExistence("tabSix");
});
function checkTabExistence(stringToCheck) {
var tabExists = false;
$("a").each(function() {
if($(this).text() === stringToCheck) {
tabExists = true;
}
});
console.log(stringToCheck + " exists: " + tabExists);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="tabs">
<li><a href='#tab1'>tabOne</a></li>
<li><a href='#tab2'>tabTwo</a></li>
<li><a href='#tab3'>tabThree</a></li>
<li><a href='#tab4'>tabFour</a></li>
</ul>

Accessing and Displaying JSON Object with AngularJS

I'm trying to access an object in JSON with AngularJS, and display the values. I have done this when I create an array in JSON but this time I want to show an example with an object. This is my code:
My JSON File
{ "user": {
"Name":"Ben",
"City":"New York"}}
My angular app
var app = angular.module('myApp', []);
app.controller('jsonObjectExample', function($scope, $http) {
$http.get("jsonobject.json").then(function (response) {
$scope.myData = response.data.user;
});
});
My HTML
<body>
<div ng-app="myApp" ng-controller="jsonObjectExample">
<ul>
<li ng-repeat="x in myData">
{{ x.Name + ', ' + x.City }}
</li>
</ul>
</div>
</body>
Here is a link to these files on plunker: https://plnkr.co/edit/uBRf99AjYH9zX0WuHsW3?p=preview
Can someone explain where I'm going wrong? Thanks.
remove the ng-repeat. myData is object, not an array so no need to use the ng-repeat
<body>
<div ng-app="myApp" ng-controller="jsonObjectExample">
<ul>
<li >
{{ myData.Name + ', ' + myData.City }}
</li>
</ul>
</div>
</body>
Demo
If you are using ng-repeat make sure the json which you are parsing should give some array value.
you can correct your json like:
{ "user": [{
"Name":"Ben",
"City":"New York"}]}
Other codes are working fine. Please check this

AngularJS custom filter called 2 times

I'm trying out Angular custom filter example from: https://scotch.io/tutorials/building-custom-angularjs-filters#filters-that-actually-filter which in my version looks like:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="demo" >
<div>
<p><strong>Original:</strong></p>
<ul class="list">
<li ng-repeat="x in example1">{{ x.name }}</li>
</ul>
<p><strong>Static Language Filter:</strong></p>
<ul class="list">
<li ng-repeat="x in example1 | staticLanguage">{{x.name }}</li>
</ul>
</div>
</div>
<script>
var app = angular.module('myApp', []);
var counter=0;
app.controller('demo', function($scope){
$scope.example1 = [
{name: 'C#', type : 'static'},
{name: 'PHP', type : 'dynamic'},
{name: 'Go', type : 'static'},
{name: 'JavaScript', type: 'dynamic'},
{name: 'Rust', type: 'static'}
];
});
// Setup the filter
app.filter('staticLanguage', function() { // Create the return function and set the required parameter name to **input**
return function(input) {
counter+=1;
console.log(counter);
var out = [];
// Using the angular.forEach method, go through the array of data and perform the operation of figuring out if the language is statically or dynamically typed.
angular.forEach(input, function(input) {
if (input.type === 'static') {
out.push(input);
}
});
return out;
};
});
</script>
</body>
</html>
It seems from console.log that for some reason custom filter function staticLanguage is called two times but from the code itself it is called only one time: ng-repeat="x in example1 | staticLanguage"
Anyone has any idea why?
P.S I've yet to figure out what does "dirty-checking" has to do with my question...
if I remove counter variable and just put some console.log("text") in it's place staticLanguage function is still called two times
As far as I am aware this is due to AngularJS dirty-checking and has been asnwered elsewhere here. This is normal, have a read of the link.
This is normal, angularjs uses a 'dirty-check' approach, so it needs to call all the filters to see if any changes exist. After this it detects that you have a change on one variable (the one that you typed) and then it re-executes all filters again to detect if it has other changes.
See the first answer of this question
How does data binding work in AngularJS?
Well, I don't know if this will serve to you , but here's a snippet working that could be a possible solution for you:
var app = angular.module('app', []);
app.controller('mainCtrl', function($scope) {
$scope.languages = [
{
"name":"C#",
"type":"static"
},
{
"name":"PHP",
"type":"dynamic"
},
{
"name":"Go",
"type":"static"
},
{
"name":"JavaScript",
"type":"dynamic"
},
{
"name":"Rust",
"type":"static"
}
];
$scope.static_languages = $scope.languages.filter(x => x.type == 'static');
$scope.dynamic_languages = $scope.languages.filter(x => x.type == 'dynamic');
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js">
</script>
</head>
<body ng-controller="mainCtrl">
<div>
<p><strong>All languages:</strong></p>
<ul class="list">
<li ng-bind="language.name" ng-repeat="language in languages"></li>
</ul>
<p><strong>Static Languages Filter:</strong></p>
<ul class="list">
<li ng-bind="language.name" ng-repeat="language in static_languages"></li>
</ul>
<p><strong>Dynamic Languages Filter:</strong></p>
<ul class="list">
<li ng-bind="language.name" ng-repeat="language in dynamic_languages"></li>
</ul>
</div>
</body>
</html>

Handlebars.js group by value

I'm using Handlebars to display some datas via ajax, and the JSON is like this:
{"data":[
{ "sn":"43","areasn":"3","name":"X1","status":"empty","seats":"12"},
{ "sn":"22","areasn":"1","name":"F1","status":"empty","seats":"8"},
{ "sn":"12","areasn":"2","name":"E1","status":"empty","seats":"6"},
{ "sn":"18","areasn":"3","name":"R3","status":"empty","seats":"6"},
{ "sn":"31","areasn":"1","name":"G4","status":"empty","seats":"4"},
{ "sn":"23","areasn":"2","name":"W5","status":"empty","seats":"12"}
]}
and I need to use handlebars.js in order to display tables in differents areas, something like these:
<script id="tables-template" type="text/x-handlebars-template">
{{#each data}}
// All tables in area-1
<ul id="area-{{areasn}}">
<li id="{{sn}}">{{name}}</li>
</ul>
// All tables in area-2
<ul id="area-{{areasn}}">
<li id="{{sn}}">{{name}}</li>
</ul>
// All tables in area-3
<ul id="area-{{areasn}}">
<li id="{{sn}}">{{name}}</li>
</ul>
{{/each}}
</script>
I have no idea how to write a helper for this, is anyone can help? thanks!
There is probably a better way of doing this as I don't know about handlebars, but this should do what you are looking for:
(function() {
var id = 0,
cache = [];
var ids={};
Handlebars.registerHelper("groupData", function(data) {
var dataKey = id++;
ids[data.areasn]=true;
if(cache[data.areasn]==undefined) cache[data.areasn]={id:data.areasn, data:[data]};
else cache[data.areasn].data.push(data)
if(dataKey==context.data.length-1){
context.cache=[];
for(var i in ids){
context.cache.push(cache[i])
}
}
});
})();
var context={"data":[
{ "sn":"43","areasn":"3","name":"X1","status":"empty","seats":"12"},
{ "sn":"22","areasn":"1","name":"F1","status":"empty","seats":"8"},
{ "sn":"12","areasn":"2","name":"E1","status":"empty","seats":"6"},
{ "sn":"18","areasn":"3","name":"R3","status":"empty","seats":"6"},
{ "sn":"31","areasn":"1","name":"G4","status":"empty","seats":"4"},
{ "sn":"23","areasn":"2","name":"W5","status":"empty","seats":"12"}
]}
var template = Handlebars.compile($("#your-template").text());
var html = template(context);
document.body.innerHTML=html;
Check fiddle for html:
http://jsfiddle.net/mE49M/226/

Handlebars.js printing object doesn't work

this might be real simple but I've tried many examples and still couldn't make it working.
So I've got this code to check if the entry is written by the author and if so, I want to print it into template.
function printTitltes() {
var currentUser = JSON.parse(localStorage.getItem('currentUser'))
var author = currentUser["username"];
var allEntries = JSON.parse(localStorage.getItem("allEntries"));
var template = Handlebars.compile($("#template").html());
var authorEntry;
if (!allEntries) {
return
} else {
for (var i=0; i<allEntries.length; i++) {
if (allEntries[i]["author"] === author) {
authorEntry = allEntries[i];
$("#titleArea").append(template(authorEntry));
}
}
}
}
And my template is:
<script type='text/template' id='template'>
<ul class="entries-list">
{{#each auhorEntry}}
<li data-id="{{ID}}">
<span> {{date}} </span>
{{title}}
</li>
{{/each}}
</ul>
</script>
When executed, all I got is an empty template. I've must have been sending a wrong object to the template but couldn't grasp how could I do it right. Anyone whould spot it for me please?
<script type="text/x-handlebars-template" id="template">

Categories

Resources