AngularJS nested objects in the same bootstrap row - json

i have a JSON object
{
"products": [
{
"devices": [
{
"label": "P1D1"
},
{
"label": "P1D2"
}
]
},
{
"devices": [
{
"label": "P2D1"
},
{
"label": "P2D2"
}
]
}
]
}
and i want to have in HTML something like this
<div class="row">
<div class="col-3">
P1D1
</div>
<div class="col-3">
P1D2
</div>
<div class="col-3">
P2D1
</div>
<div class="col-3">
P2D2
</div>
</div>
AngularJS is the language i am using, but i don't seem the find the right syntax
<div class="row">
<div ng-repeat="product in obj.products">
<div class="col-3" ng-repeat="device in product.devices">
{{device.label}}
</div>
</div>
</div>
How can i achieve all the subitems to be displayed in a bootstrap column next to eachother?

I think you can't do it directly using only HTML. Alternatively you can use some manipulation in Javascript to flatten your data.
JAVASCRIPT
$scope.getItems = function(){
return $scope.obj.products.flatMap(function(element){
return element.devices;
})
}
HTML
<div class="col-3" ng-repeat="device in getItems()">
{{device.label}}
</div>
Check my example:
https://codepen.io/avgustint/pen/XWYyoyd?editors=1111

Related

Nested Children Json in Angular HTML

I have a JSON with nested children. RowElements can have n colElements and colElements can have n RowElements.
JSON
"container": {
"id": "37ec0632-3391-4ef5-a9cb-25db2216fa75",
"rowElements": [
{
"id": "80e1dae7-b497-48d3-80ad-b94d36ada642",
"colElements": [
{
"id": "c662efe9-615c-4de5-97d3-2b02a5bce831",
"rowElements": [
{
"id": "b31960fd-c082-4d3b-88fc-c05f0cf837aa",
"colElements": []
},
{
"id": "7552306a-ca61-4d80-bb4e-d6c8d15c2c78",
"colElements": []
},
{
"id": "f669896d-132b-468e-8dcf-f2b59d509a76",
"colElements": []
}
]
}
]
}
]
}
How can i iterate over the children dynamically in the template like:
<div class="row">
<div class="col">
<div class="row">
<div class="col">
</div>
<div class="col">
</div>
<div class="col">
</div>
...
</div>
...
</div>
...
</div>
You can use nested *ngFor to iterate the JSON and display it dynamically.
I also created a stackblitz for you to check my solution.
HTML - I'm display the id here just to check the JSON.
<div class="row" *ngFor="let firstRow of arr.container.rowElements">
{{ firstRow.id }}
<div class="col" *ngFor="let firstCol of firstRow.colElements">
{{ firstCol.id }}
<div class="row" *ngFor="let secondRow of firstCol.rowElements">
{{ secondRow.id }}
<div class="col" *ngFor="let secondCol of secondRow.colElements"></div>
</div>
</div>
</div>
AppComponent.ts - I added a variable to hold your sample JSON
export class AppComponent {
arr = {
container: {
id: '37ec0632-3391-4ef5-a9cb-25db2216fa75',
rowElements: [{
id: '80e1dae7-b497-48d3-80ad-b94d36ada642',
colElements: [{
id: 'c662efe9-615c-4de5-97d3-2b02a5bce831',
rowElements: [{
id: 'b31960fd-c082-4d3b-88fc-c05f0cf837aa',
colElements: []
},
{
id: '7552306a-ca61-4d80-bb4e-d6c8d15c2c78',
colElements: []
},
{
id: 'f669896d-132b-468e-8dcf-f2b59d509a76',
colElements: []
},
],
}, ],
}, ],
},
};
constructor() {
console.log(this.arr.container);
}
}

Angular associate json value to img path

I have to display data that comes from an api that works well, I need to display each country with its corresponding flag but I don't understand how to associate the value of a json with the path of an image.
example : for the
libelle: Cambodge bigramme: KH
display: src/assets/flags/KH.jpg
libelle: France bigramme: FR
display: src/assets/flags/FR.jpg
I have tried to be as clear as possible.
thank you.
json
"drapeaux": [
{
"id": 1,
"mnemo": "KHM",
"libelle": "Cambodge",
"bigramme": "KH"
},
{
"id": 2,
"mnemo": "KHM",
"libelle": "France",
"bigramme": "FR"
}
]
}
service
getAll(): Observable<Ipost[]> {
return this.http.get<Ipost[]>(this.api);
}
components.ts
getAllNations() {
let resp = this.homeService.getAll();
resp.subscribe(result => {
this.postArray = result;
});
}
html
<div class="col-12">
<mat-card>
<div class="row">
<div class="col-1" *ngFor="let post of postArray">
{{post.libelle}}
<img [src]="post.bigramme.jpg" alt="flag">
</div>
</div>
</mat-card>
</div>
You have two options:
Option 1: In your service:
getAll(): Observable<Ipost[]> {
return this.http.get<Ipost[]>(this.api).pipe(
map(p => ({
...p,
bigramme: `src/assets/flags/${p.bigramme}.jpg`
}))
)
}
And then your Component's html:
<div class="col-12">
<mat-card>
<div class="row">
<div class="col-1" *ngFor="let post of postArray">
{{post.libelle}}
<img [src]="post.bigramme" alt="flag">
</div>
</div>
</mat-card>
</div>
Option 2: Or you can change only your Component's html:
<div class="col-12">
<mat-card>
<div class="row">
<div class="col-1" *ngFor="let post of postArray">
{{post.libelle}}
<img src="src/assets/flags/{{ post.bigramme }}.jpg" alt="flag">
</div>
</div>
</mat-card>
</div>

Collapse/Expand nested div in Angular 6

I am developing a schedule like structure using div. And my design looks like this.
What i want is when loading, only 1st level should be displayed (all venues) and when clicking on venue its immediate child should be displayed and so on. Is there any way to do so. my html is:
<div class="div-table">
<div class="div-table-row">
<div class="div-header-col" style="visibility: hidden;">A</div>
<div *ngFor="let date of dates" class="div-date-col">{{date | date:'d E'}}</div>
</div>
<!-- level1 -->
<div *ngFor="let venue of venues" class="level1" style="color: red">
<div class="div-table-row-level1" >
<div class="div-header-col">{{venue.name}}</div>
<div *ngFor="let x of dates" class="div-event-level1-col"></div>
</div>
<!-- level2 -->
<div *ngFor="let category of venue.categories" class="level2" style="color: blue">
<div class="div-table-row-level2">
<div class="div-header-col" style="padding-left: 10px">{{category.name}}</div>
<div *ngFor="let x of dates" class="div-event-level2-col"></div>
</div>
<!-- level3 -->
<div *ngFor="let asset of category.assets" class="level3" style="color: green">
<div class="div-table-row-level3">
<div class="div-header-col" style="padding-left: 20px">{{asset.name}}</div>
<div *ngFor="let x of dates" class="div-event-level3-col assest-hover" "></div>
</div>
</div>
</div>
</div>
</div>
My data for the table(div) is :
[
{
"id":1,
"name":"venue1",
"categories":[
{
"id":1,
"name":"cat1",
"assets":[
{
"id":1,
"name":"assest1"
},
{
"id":2,
"name":"assest2"
}
]
},
{
"id":2,
"name":"cat2",
"assets":[
{
"id":3,
"name":"assest3"
},
{
"id":4,
"name":"assest4"
}
]
}
]
},
{
"id":2,
"name":"venue2",
"categories":[
{
"id":3,
"name":"cat3",
"assets":[
{
"id":5,
"name":"assest5"
},
{
"id":6,
"name":"assest6"
}
]
},
{
"id":4,
"name":"cat4",
"assets":[
{
"id":7,
"name":"assest7"
},
{
"id":8,
"name":"assest8"
}
]
}
]
},{
"id":3,
"name":"venue3",
"categories":[
{
"id":5,
"name":"cat5",
"assets":[
{
"id":9,
"name":"assest9"
},
{
"id":10,
"name":"assest10"
}
]
},
{
"id":6,
"name":"cat6",
"assets":[
{
"id":11,
"name":"assest11"
},
{
"id":12,
"name":"assest12"
}
]
}
]
}
]
If you have entire data loaded together then you have good news that it can be implemented in a very simple way -
You can play around Element Reference. Nothing needs to be managed from ts file.
in html
<div *ngFor="let venue of venues" class="level1" style="color: red"
(click)="ele.class = ele.class == 'showChildren' ? '' : 'showChildren'"
[ngClass]="{ hideChildren : ele.class !== 'showChildren' }">
Repeat the same for all parent div
in CSS
.hideChildren>div{
display: none;
}
Here is the working copy- https://stackblitz.com/edit/angular-n43ihd
There are some more way to handle if the data is being fetched in Asynchronous fashion. Then these logic will move to ts file.
You can try to hide component's on-load, and set them to visible onClick
$scope.$on('$viewContentLoaded', function() {
// Hide all unwanted div's here
});

AngularJS + bootstrap carousel help to display all the images

I have an array of objects, where I have the url of the image. I need to display these images in carousel:
<div class="item active">
<div class="row cst-carouselImg">
<div class="col-sm-3 col-xs-6" ng-repeat="image in pack.hotels.current.hotelImages | limitTo:'4'">
<a href="#"><img
ng-src="<?php
echo 'http://photos.hotelbeds.com/giata/';
?>{{image.path}}"
alt="Image" class="img-responsive"></a>
</div>
</div>
</div>
At this point I have only the first 4 pictures from the array. Next I display the next 4 images from the array:
<div class="item">
<div class="row cst-carouselImg">
<div class="col-sm-3 col-xs-6" ng-repeat="image in pack.hotels.current.hotelImages" ng-if="$index > 3 && $index <8">
<a href="#"><img
ng-src="<?php echo
'http://photos.hotelbeds.com/giata/';
?>{{image.path}}"
alt="Image" class="img-responsive"></a>
</div>
</div>
</div>
How can I display all the images using ng-repeat instead of manually adding <div class="item"> and setting manually $index?
Here i take some sample array you can modify it accordingly
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl',function($scope, $timeout) {
$scope.hotelImages=[{id:1},{id:2},{id:3},{id:4},{id:5},{id:6},{id:7}];
$scope.loopCount=Math.ceil($scope.hotelImages.length/4);
$scope.getNumber = function(num) {
var arr=[];
for(i=0;i<num;i++){
arr.push(i);
}
return arr;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="item" ng-repeat="i in getNumber(loopCount) track by $index">
Carousel :-{{i}}
<div class="row cst-carouselImg">
<div class="col-sm-3 col-xs-6" ng-repeat="image in hotelImages" ng-if="$index >=(i*4) && $index <(i*4)+4" >
image:- {{image.id}}
</div>
</div>
</div>
</div>
If I understood you correctly you are aiming at having a nested ng-repeat, one for the items and one for the images. Let me know if I misunderstood you or you need some clarifications. Please see this snippet below:
var app = angular.module("app", []);
app.controller('exampleCtrl', function($scope){
$scope.hotels= [
[
{
path: "hotel1 path1",
otherprop: true
},
{
path: "hotel1 path2",
otherprop: false
},
{
path: "hotel1 path3",
otherprop: true
}
],
[
{
path: "hotel2 path1",
otherprop: true
},
{
path: "hotel2 path2",
otherprop: true
}
],
[
{
path: "hotel3 path1",
otherprop: false
},
{
path: "hotel3 path2",
otherprop: false
},
{
path: "hotel3 path3",
otherprop: false
},
{
path: "hotel3 path4",
otherprop: true
}
]
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="exampleCtrl">
<div class="item" ng-repeat="hotel in hotels">
<p>This is Hotel #{{$index+1}}</p>
<div class="row cst-carouselImg">
<div class="col-sm-3 col-xs-6" ng-repeat="image in hotel">
<a href="#">
<img ng-src="{{image.path}}" class="img-responsive" alt="(this is alt text)"/>
Image {{$index+1}}'s path: {{image.path}}
</a>
</div>
</div>
</div>
</div>
</div>

Multidimensional array with jquery templates

I have the following javascript object
var arr = [
[
{ "id": 1, "name": "one" },
{ "id": 2, "name": "two" },
{ "id": 3, "name": "three" }
],
[
{ "id": 4, "name": "four" },
{ "id": 5, "name": "five" },
{ "id": 6, "name": "six" }
],
]
I'm trying to use jquery templates to create the following HTML
<div class="row">
<div class="cell">
<span>1</span> : <span>one</span>
</div>
<div class="cell">
<span>2</span> : <span>two</span>
</div>
<div class="cell">
<span>3</span> : <span>three</span>
</div>
</div>
<div class="row">
<div class="cell">
<span>4</span> : <span>four</span>
</div>
<div class="cell">
<span>5</span> : <span>five</span>
</div>
<div class="cell">
<span>6</span> : <span>six</span>
</div>
</div>
I am using the following templates with no luck :(
<script id="rowTemplate" type="text/x-jQuery-tmpl">
<div class="row">
{{tmpl "#cellTemplate"}}
</div>
</script>
<script id="cellTemplate" type="text/x-jQuery-tmpl">
<div class="cell">
<span>${id}</span> : <span>${name}</span>
</div>
</script>
The line that calls the template is the following:
$("#rowTemplate").tmpl(arr).replaceAll("#somediv");
I am getting only one row with one cell with no data...
<div class="row">
<div class="cell">
<span></span> : <span></span>
</div>
</div>
What am I doing wrong?
I think the problem is with usage of replaceAll and the missing parameter to tmpl in the template.
Try this(used replaceWith for #someDiv and passed $data as tmpl parameter for child template):
<script type="text/javascript">
var arr =
[
[
{
"id": 1,
"name": "one"
},
{
"id": 2,
"name": "two"
},
{
"id": 3,
"name": "three"
}
],
[
{
"id": 4,
"name": "four"
},
{
"id": 5,
"name": "five"
},
{
"id": 6,
"name": "six"
}
]
];
$(function(){
$("#somediv").replaceWith($("#rowTemplate").tmpl(arr));
});
</script>
<script id="rowTemplate" type="text/x-jQuery-tmpl">
<div class="row">
{{tmpl($data) "#cellTemplate"}}
</div>
</script>
<script id="cellTemplate" type="text/x-jQuery-tmpl">
<div class = "cell"><span>${id}</span>:<span>${name}</span></div>
</script>
<div id="somediv"></div>