angularJS - iterating through JSON object - javascript

I have a nested JSON "object" called znanja that I want to display on my webpage. It will contain a number of values that I want to make into a list. Basically I'm building a portfolio and want to list my skills. So far I've managed to display the title, and the whole object, or by calling a specific one (for instance {{ znanje.ena }}), but I can't figure out how to display them without the attribute name. If I only call {{ znanje }}, I get them listed like in the JSON. Is there a angularJS directive I can do this with? I'm new to angular, so any help is appreciated.
my view:
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="znanje in skill.znanja">{{ znanje }}</p>
</div>
my data:
$scope.skills = [
{
title: "Code Knowledge",
znanja : [{
ena : "Javascript",
dva : "HTML",
tri : "CSS",
stiri : "SASS"
}]
},
{
title: "Base Code Knowledge",
znanja : [{
ena : "Java",
dva : "PhP"
}]
},
{
title: "Data",
znanja : [{
ena : "MongoDB",
dva : "MySQL"
}]
}
];
PS: I've named the znanja attributes ena, dva, tri, stiri instead of 1, 2, 3, 4 to be able to call them in the html.

The object which you wanted to apply a loop is nothing but the 1st element in znanja array, so you should be specify skill.znanja[0] instead of skill.znanja.
By doing this you ng-repeat will iterate through each property of object and {{znanje}} will print the value of each property of znanja[0]
Markup
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="znanje in skill.znanja[0]">{{ znanje }}</p>
</div>

It is possible to get ngRepeat to iterate over the properties of an
object using the following syntax:
<div ng-repeat="(key, value) in skill.znanja"> ... </div>
https://docs.angularjs.org/api/ng/directive/ngRepeat

In order to display the attributes you need a DOM element and a DOM element need a specific value to render so You have to manual at least for one iteration specifically call attributes.
How ever if you have any repetitions you can include it using ng-repeat like you have done.
That is if you want to display each attribute on the html page individually and later want to access it but if you just want to show as json object that will be as easy as passing the json

<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="(key,value) in skill.znanja[0]">{{key}} <b>:</b> {{value}}</p>
</div>

(tested) combined both znanja-object 0 and the value:
<div ng-repeat="skill in skills">
<h1>{{ skill.title }}</h1>
<p ng-repeat="(key, value) in skill.znanja[0] ">{{ value }}</p>
</div>

The simplest and best way to solve this issue is by changing your data structure. Simply remove the wrapping array around the lists you iterate on, turning them into object map:
$scope.skills = [
{
title: "Code Knowledge",
znanja : {
ena : "Javascript",
dva : "HTML",
tri : "CSS",
stiri : "SASS"
}
},
{
title: "Base Code Knowledge",
znanja : {
ena : "Java",
dva : "PhP"
}
},
{
title: "Data",
znanja : {
ena : "MongoDB",
dva : "MySQL"
}
}
];
If you did not intend to use that array in any way (all examples contain only one element), then there's no reason for having it there.
There's no need to change anything in your original ng-repeat that way.

Related

Problem accessing an array element from json in angular/html

I have the following json data, which comes from mongoDB:
{"list":
[{
"_id":"62f2fabd09de07c09f9e17e2",
"categoryName":"Web development",
"subcategories":[
{
"subcategoryName":"Backend",
"skills":["Nodejs", "Express"]
},
{
"subcategoryName":"Frontend",
"skills":["Css", "SASS"]
}
]
},
{
"_id":"62f33ba62ae52a71daa99a30",
"categoryName":"Cybersecurity",
"subcategories":[
{
"subcategoryName":"Red team",
"skills":["cURL","wfuzz"]
},
{
"subcategoryName":"Blue team",
"skills":["Cloudfare", "Burpsuite"]
}
]
}]
}
This is my angular scope, which gets the json data from the endpoint:
$scope.listSkills = function() {
$http.get("/showSkills").success(function(skills_from_database){
$scope.skills = skills_from_database.list;
})
}
And finally is my html/angular code
<div ng-repeat="category in skills">
<h1>{{category.categoryName}}</h1>
<div ng-repeat="subcategory in category.subcategories">
<hr>
<h2>{{subcategory.subcategoryName}}</h2>
<div ng-repeat="skill in category.subcategories">
<h5>{{skill.skills}}</h5>
</div>
</div>
</div>
The result is:
Category works
Subcategory works, but it gets all skills from the category, not only from the subcategory
Skills doesn't work, it gets the skills section but it should get all the arrays value, which I don't know how to do
Your inner loop needs to iterate over each member of subcategory.skills . I'm not sure why you are iterating again over the same object. (ng-repeat="subcategory in category.subcategories" and ng-repeat="skill in category.subcategories")
<div ng-repeat="skill in subcategory.skills">
{skill}
</div>

How to toggle click a single elements CSS class in Angular 2?

I'm looping through an API response and displaying some items (female and male age groups) on a page with the following code:
<ng-container *ngFor="let event of day.availableEvents">
{{ event.name }}
<br>
<ng-container *ngFor="let maleAgeGroup of event.maleAgeGroups">
<span [class.is-active]="status" (click)="updateStatus()" {{ maleAgeGroup }}</span>
</ng-container>
</ng-container>
And, this the JSON data I'm working with:
"days": [
{
"date": "2021-04-14T00:00:00.000Z",
"availableEvents": [
{
"id": 1,
"name": "Event A",
"femaleAgeGroups": ["U13", "U15", "U17"],
"maleAgeGroups": ["U13", "U15", "U17"]
},
{
"id": 2,
"name": "Event B",
"femaleAgeGroups": ["U13", "U15", "U17"],
"maleAgeGroups": ["U13", "U15", "U17"]
},
]
}
]
On click of an age group I want to toggle its status from true or false so that the is-active CSS class is add/removed.
No matter what SO answer I try, I can't get it to work and in most cases end up with an error like 'Cannot assign status to type string'. This is why I've stripped back the above code right to basics - maybe it's because of the way my data is structured?
The example below is what I'm trying to end up with, where the highlighted text has been clicked and is-active class applied:
[class.is-active] needs to 'bind' to a value, it is unclear to me the intent of what you trying to do as a whole, but, each age group needs a state. Thus, you need to update/modify your data either from the server or augment in your component with the status for each age group...
"femaleAgeGroups": [{name:"U13", active:true}, {name:"U15", active:false}, {name:"U17", active:false}], etc..
Then in the template you can bind the css class to the boolean value
<ng-container *ngFor="let maleAgeGroup of event.maleAgeGroups">
<span [class.is-active]="maleAgeGroup.active" (click)="updateStatus(maleAgeGroup)" {{ maleAgeGroup.name }}</span>
</ng-container>
.. and to update you pass the item to update function and update its active state:
updateStatus(item:any): void {
item.active = !item.active;
}

dynamically Build ng-template using list

I am trying to build ng-template dynamically, In the Data structure, I have a Object that contains list of object of same type or other type of object.
[
{
type: "device",
id: 1,
allowedTypes: ["device","action"],
max: 5,
columns: [
{
type: "action",
id: "1"
},
{
type: "device",
id: 2,
allowedTypes: ["device","action"],
max: 5,
columns: [
{
type: "action",
id: "1"
},
{
type: "action",
id: "2"
}
]
}
]
}
]
My ng-template code:
<script type="text/ng-template" id="and.html">
<div class="container-element box box-red">
<h3>And {{item.id}}</h3>
<ul dnd-list="item.columns"
dnd-allowed-types="item.allowedTypes"
dnd-disable-if="item.columns.length >= item.max">
<li ng-repeat="element in item.columns"
dnd-draggable="element"
dnd-effect-allowed="move"
dnd-moved="item.columns.splice($index, 1)"
dnd-selected="models.selected = element"
ng-class="{selected: models.selected === element}"
ng-include="element.type + '.html'" onload="onloadAction()">
</li>
</ul>
<div class="clearfix"></div>
</div>
</script>
In the ng-template code the first level or different types of object can easily be added, however same type of object does not work properly when added in the 2nd level, it seems the its going in a recursive loop.
This is because the nested ng-template (child) ng-template use of root item.columns from the ng-repeat="element in item.columns".
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'">
</li>
any advise how to resolve this issue.
I have managed to resolve this issue, ng-repeat create a new child scope, however the item from the parent scope is also visible to in the child scope, as this is recursive that mean child template and parent template both have the variable with the same name called item. However the child scope variable item is ignored:
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'">
</li>
in the above snippet the element also has a variable called item, so in the child scope when we call item.columns the item variable of parent is invoked again, to ensure that the item variable of child is not ignored, we need to use ng-init with ng-include and set the current element as item in the child scope as shown below:
<li ng-repeat="element in item.columns"
dnd-draggable="element"
ng-include="element.type + '.html'" ng-init="item=element">
</li>
To read more on this please visit
http://benfoster.io/blog/angularjs-recursive-templates

Angular, connect objects and display right information

I'm creating an angular webapp, listing different cars in a sidebar and some information about the specific car in a informationbox.
The purpose is to show the right information in the box when clicking the different cars.
I have two different arrays(two API-endpoints), where the first array lists the car name, and the other one got the information about the car. But I have no idea how to connect the objects with the primary key and the foreign key, and how I'm supposed to output the right information after clicking the car.
app.js:
angular.module('myApp', [])
.controller('MyController', function($scope, $http) {
function fetch() {
$http({method : 'GET',url : 'http://*cars*'})
.success(function(data) {
$scope.cars = data;
});
$http({method : 'GET',url : 'http://*information*'})
.success(function(data) {
$scope.information = data;
});
}
fetch();
})
html:
<div id="sidebar">
<ul>
<li ng-repeat="name in cars">{{ name.displayName }}</li>
</ul>
</div>
For now all I have done is that I've fetched the data and outputed the cars in the sidebar. But now I've been googling and trying to connect the cars to the information with loops and functions for hours, but stil clueless.
Yes, I'm new to this. Any kind of help would be great! Thanks
You can deal with this with the ng-route. You can do something like :
In your route definition:
.when(/cars/:Id), {
name: 'cars',
templateUrl : 'ayourtemplate.html',
controller : 'yourCtrl'
})
In your html:
<div id="sidebar">
<ul>
<li ng-repeat="name in cars">{{ name.displayName }}</li>
</ul>
</div>
The Id will be your key tou will just have to match the right key in your $scope.information
It depends on what information those arrays contains.
If you're sure, that every element corresponds to other, you can just use $index in the html.
<li ng-repeat="name in cars">
{{ name.displayName }}
<p>{{ information[$index] }}</p>
</li>
However, if elements in array aren't ordered, you will have to check primary keys of objects in arrays. Let's assume, that data in arrays looks like this:
cars:
[
{ id: "1", name: "Carrera GT" },
{ id: "2", name: "DB 11" },
... and so on
]
information:
[
{ id: "2", info: "Lorem ipsum" },
{ id: "1", info: "Dolor sit amet" },
...
]
Then I'd suggest using loops and constructing new array using ids.
var carinfo = [];
cars.forEach(car => {
obj["id"] = car.id;
obj["name"] = car.name;
obj["info"] = ""; // Placeholder
info.forEach(c => {
if (c.id === car.id) {
obj["info"] = c.info;
}
});
carinfo.push(obj);
});
$scope.carInfo = carinfo;
Then you can use $scope.carInfo in the html file.
<li ng-repeat="car in carInfo">
{{ car.name }}
<p>{{ car.info }}</p>
</li>

AngularJS: I clearly do not understand the use of ng-init

I have an extremely hierarchical JSON structure as a scope variable in my AngularJS controller. I want to loop around different sections of that variable. I thought about using ng-init to specify where in the structure I am. Here is some code:
my_app.js:
(function() {
var app = angular.module("my_app");
app.controller("MyController", [ "$scope", function($scope) {
$scope.things = {
name: "a",
children: [
{
name: "a.a",
children: [
{ name: "a.a.a" },
{ name: "a.a.b" }
]
},
{
name: "a.b",
children: [
{ name: "a.b.a" },
{ name: "a.b.b" }
]
}
]
}
}]);
});
my_template.html:
<div ng-app="my_app" ng-controller="MyController">
<ul>
<li ng-init="current_thing=things.children[0]" ng-repeat="thing in current_thing.children>
{{ thing.name }}
</li>
</ul>
</div>
I would expect this to display a list:
a.a.a
a.a.b
But it displays nothing.
Of course, if I specify the loop explicitly (ng-repeat="thing in things.children[0].children") it works just fine. But that little snippet of template code will have to be run at various points in my application at various levels of "things."
(Just to make life complicated, I can get the current thing level using standard JavaScript or else via Django cleverness.)
Any ideas?
ng-init runs at a lower priority (450) than ng-repeat (1000). As a result, when placed on the same element, ng-repeat is compiled first meaning that the scope property created by ng-init won't be defined until after ng-repeat is executed.
As a result, if you want to use it in this manner, you'd need to place it on the parent element instead.
<div ng-app="my_app" ng-controller="MyController">
<ul ng-init="current_thing=things.children[0]">
<li ng-repeat="thing in current_thing.children>
{{ thing.name }}
</li>
</ul>
</div>

Categories