Displaying Nested Objects from JSON file in Angular2 - arrays

Learning how to display nested data using Angular 2. There are lots of similar questions on the web but I haven't seen anything broken down into a simple object I can follow and repeat.
I have a list that shows a JSON list of heroes:
Basic List & Detail for Superman and Batman
My current goal is to show a list of accounts of the selected hero.
My problem is code here related to a list where I'd like to show accounts based on the hero chosen.
My JSON is broken where I can see sub-nested detail but I can't seem to get that level of detail into a list.
hero-detail.component.html
<main class="col-sm-9">
<div *ngIf="hero">
<h2>{{hero.user[0].firstName}} {{ hero.user[0].lastName }}</h2>
<div>
<label>First Name: </label>
<input [(ngModel)]="hero.user[0].firstName" placeholder="First Name">
</div>
<div>
<label>Last Name: </label>
<input [(ngModel)]="hero.user[0].lastName" placeholder="Last Name">
</div>
<ul class="list-group">
<li class="list-group-item" *ngFor="let hero of heroes">
<div *ngFor="let account of accounts">
{{ account[0].accountName }}
</div>
</li>
</ul>
</div>
</main>
hero-detail.component.ts
import { Component, Input } from '#angular/core';
import { Hero } from './hero';
#Component({
selector: 'my-hero-detail',
templateUrl: './heroes-detail.component.html'
})
export class HeroesDetailComponent {
#Input()
hero: Hero;
}
hero-component.html
<aside class="col-sm-3">
<div class="list-group">
<button class="list-group-item"
*ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
{{ hero.user[0].firstName }} {{ hero.user[0].lastName }}
</button>
</div>
</aside>
<my-hero-detail [hero]="selectedHero"></my-hero-detail>
heroes.component.ts
import { Component, OnInit } from '#angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
providers: [ HeroService ]
})
export class HeroesComponent implements OnInit {
title = 'Tour of Heroes';
heroes: Hero[];
selectedHero: Hero;
constructor(
private heroService: HeroService) { }
getHeroes(): void {
this.heroService
.getHeroes()
.then(heroes => this.heroes = heroes);
}
ngOnInit(): void {
this.getHeroes();
}
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
}
mock-heroes.ts
import { Hero } from './hero';
export const HEROES: Hero[] =
[
{
"heroId": 1001,
"alias": "Superman",
"user": [
{
"firstName": "Clark",
"lastName": "Kent",
"email": "clark.kent#dailyplanet.com"
}
],
"accounts": [
{
accountNum: "1234567890",
accountName: "Personal Checking",
type: "checking",
balance: 1500.00
},
{
accountNum: "2345678901",
accountName: "Personal Savings",
type: "savings",
balance: 2000.00
}
]
},
{
"heroId": 1002,
"alias": "Batman",
"user": [
{
"firstName": "Bruce",
"lastName": "Wayne",
"email": "bruce.wayne#wayne.com"
}
],
"accounts": [
{
accountNum: "1234567890",
accountName: "Personal Checking",
type: "checking",
balance: 7500000.00
},
{
accountNum: "2345678901",
accountName: "Personal Savings",
type: "savings",
balance: 20000000.00
}
]
}
]

You have to do like this:
<ul class="list-group">
<li class="list-group-item" *ngFor="let hero of heroes">
<div *ngFor="let account of hero.accounts">
{{ account[0].accountName }}
</div>
</li>
</ul>
You have to use second *ngFor with hero.accounts,
and make your template structure better, you are using hero in top div element, how you are getting that:
<div *ngIf="hero">
So check out first based on your requirement.
Hope this help you.

This issue was solved using the Elvis operator (?.) from here: Angular2 ngFor Iterating over JSON
hero.ts
export class Hero {
id: number;
name: string;
firstName: string;
lastName: string;
accounts: Array<Account>;
}
export interface Account {
bank: string;
type: string;
balance: number;
}
heroes-detail.component.html
<main class="col-sm-9">
<div *ngIf="hero">
<h2>{{hero.firstName}} {{ hero.lastName }}</h2>
<div>
<label>id: </label>{{hero.id}}
</div>
<div>
<label>First Name: </label>
<input [(ngModel)]="hero.firstName" placeholder="First Name">
</div>
<div>
<label>Last Name: </label>
<input [(ngModel)]="hero.lastName" placeholder="Last Name">
</div>
<table class="table table-hover">
<thead>
<tr>
<th>Bank Name</th>
<th>Account Type</th>
<th>Balance</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let account of hero?.accounts">
<td>{{ account.bank }}</td>
<td>{{ account.type }}</td>
<td>{{ account.balance }}</td>
</tr>
</tbody>
</table>
</div>
</main>
mock-heroes.ts
import { Hero } from './hero';
export const HEROES: Hero[] =
[
{
"id": 11,
"name": "Superman",
"firstName": "Clark",
"lastName": "Kent",
"accounts": [
{
"bank": "Chase",
"type": "Checking",
"balance": 1000.00
},
{
"bank": "Chase",
"type": "Savings",
"balance": 2000.00
}
]
},
{
"id": 12,
"name": "Batman",
"firstName": "Bruce",
"lastName": "Wayne",
"accounts": [
{
"bank": "Bank of Gotham",
"type": "Checking",
"balance": 1000000000.00
},
{
"bank": "Bank of Gotham",
"type": "Savings",
"balance": 2000000000.00
}
]
},
{
"id": 13,
"name": "Wonder Woman",
"firstName": "Diana",
"lastName": "Prince",
"accounts": [
{
"bank": "",
"type": "",
"balance": 0.00
},
{
"bank": "",
"type": "",
"balance": 0.00
}
]
}
]

Related

How to pass JSON data to a modal in angular 2

I am trying to pop up a modal in angular 2 that will display a list of people. The source of the list is a JSON file. I think the data is not being properly bound to the table in the modal. I am new to angular 2 and am not sure what I am missing.
Service to read JSON file:
returns-json-array-service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs';
#Injectable()
export class ReturnsJsonArrayService {
constructor(private http: Http) {}
getPeople(): Observable<any> {
return this.http.request('./people.json')
.do( res => console.log('HTTP response:', res))
.map(res => res.json().payload)
.do(console.log);
//.map(res => res.json());
/*return this.http.get('./people.json')
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));*/
}
}
SAmple json file: people.json
{
"id": "1",
"name": "David Martinez Ros",
"email": "info#davidmartinezros.com",
"age": "33"
},
{
"id": "2",
"name": "Paco Roberto Corto",
"email": "paco.roberto.corto#gmail.com",
"age": "51"
},
{
"id": "3",
"name": "Silvia Elegante i Latina",
"email": "silvia.elegante.latina#gmail.com",
"age": "30"
}
]
modal-component.ts
import {Component, Input} from '#angular/core';
import {NgbModal, NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import { ReturnsJsonArrayService } from './returns-json-array.service';
#Component({
selector: 'ngbd-modal-content',
providers: [ReturnsJsonArrayService],
template: `
<div class="modal-header">
<h4 class="modal-title">Hi there!</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
<div class="modal-body" *ngFor="let person of peopleData | async" >
<p>One fine body…</p>
<table border=1>
<tr>
<td>
<h3>Id: {{ person.id }}</h3>
</td>
<td>
<h3>name: {{ person.name }}</h3>
</td>
<td>
<h3>email: {{ person.email }}</h3>
</td>
<td>
<h3>age: {{ person.age }}</h3>
</td>
<td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="activeModal.close('Close click')">Submit</button>
</div>
`
})
export class NgbdModalContent {
#Input() name;
#Input() peopleData: Observable<Array<any>>;
constructor(public activeModal: NgbActiveModal,private peopleService: ReturnsJsonArrayService) {
this.peopleData = this.peopleService.getPeople();
console.log("AppComponent.data:" + this.peopleData);
}
}
#Component({
selector: 'ngbd-modal-component',
templateUrl: './modal-component.html'
})
export class NgbdModalComponent {
constructor(private modalService: NgbModal) {}
open() {
const modalRef = this.modalService.open(NgbdModalContent);
modalRef.componentInstance.name = 'Barb' ;
console.log("Peopledatra on open():" + modalRef.componentInstance.peopleData);
}
}
modal-component.html
<button class="btn btn-primary" (click)="open()">Assign</button>
this.peopleService.getPeople() returns an observable which is cold to activate it and make it hot you must add a subscribe this.peopleService.getPeople().subscribe() the subscribe will take a success method as the first argument like so:
this.peopleService.getPerople().subscribe(
(json) => {
// do something here with the json
}
)
Once the json is returned you can set it to a property within your components scope like so:
this.peopleService.getPerople().subscribe(
(json) => {
this.json = json;
}
)
That property will then be accessible with in the components template.

Filter unique value per key in angularjs and get checked

I have an angular object, i have to show its records with filter and sorting. Also i have to show the records of unique values per keys within the object with checkbox.
I shows record with filter and sorting also i showed the unique values per key with checkbox.
Now i have to get the values of these checkbox per key.
Here is my code with plunker url below.
index.html
<body ng-controller="myController">
<label ng-repeat="option in structure.tabs">
<input type="checkbox" ng-model="option.selected">{{option.index}}
</label>
<table border="1" width="100%">
<tr>
<th ng-repeat="header in structure.tabs" ng-show="header.selected" ng-click="sortData(header.filter)">{{header.index}}</th>
</tr>
<tr ng-repeat="data in structure.info | orderBy:sortColumn:reverseSort">
<td ng-show="structure.tabs[0].selected">{{data.name}}</td>
<td ng-show="structure.tabs[1].selected">{{data.age}}</td>
<td ng-show="structure.tabs[2].selected">{{data.city}}</td>
<td ng-show="structure.tabs[3].selected">{{data.designation}}</td>
</tr>
</table>
<h1>Unique Values Table (per key)</h1>
<table border="1" width="100%" style="margin-top: 50px;">
<tr>
<th ng-repeat="header1 in structure.tabs" ng-show="header1.selected">{{header1.index}}</th>
</tr>
<tr>
<td ng-repeat="(hk, hv) in structure.tabs" ng-show="hv.selected">
<table border='1'>
<tr ng-repeat="(dk, dv) in structure.info | unique:hv.filter">
<td>
<input type="checkbox">{{dv[hv.filter]}}
</td>
</tr>
</table>
<br>
<button ng-click="getChecked(hv.filter)">Get Checked</button>
</td>
</tr>
</table>
</body>
app.js
var app = angular.module('myApp', []);
app.controller("myController", function ($scope,$log) {
$scope.sortColumn="name";
$scope.reverseSort=false;
$scope.sortData=function(column) {
$scope.reverseSort=($scope.sortColumn==column) ? !$scope.reverseSort : false;
$scope.sortColumn=column;
}
$scope.structure={
"tabs": [
{
"index": "Name",
"filter": "name",
"selected": true
},
{
"index": "Age",
"filter": "age",
"selected": true
},
{
"index": "City",
"filter": "city",
"selected": true
},
{
"index": "Designation",
"filter": "designation",
"selected": true
}
],
"info": [
{
"name": "Abar",
"age": "27",
"city": "Ghaziabad",
"designation": "Php Developer"
},
{
"name": "Abar",
"age": "27",
"city": "Okhla",
"designation": "Html Developer"
},
{
"name": "Nishant",
"age": "25",
"city": "Delhi",
"designation": "Angular Developer"
},
{
"name": "Amit",
"age": "30",
"city": "Noida",
"designation": "Android Developer"
}
]
};
$scope.getChecked = function(tab) {
alert("Need to get all checked value of key: "+tab);
}
});
app.filter('unique', function() {
return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
});
See in plunker http://embed.plnkr.co/wblXhejmSWApBeCAusaI/
You can do like below example:
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />'); </script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
<script src="script.js"></script>
</head>
<body ng-controller="myController">
<h1>Filter Table</h1>
<label ng-repeat="option in structure.tabs">
<input type="checkbox" ng-model="option.selected">{{option.index}}
</label>
<table border="1" width="100%">
<tr>
<th ng-repeat="header in structure.tabs" ng-show="header.selected" ng-click="sortData(header.filter)">{{header.index}}</th>
</tr>
<tr ng-repeat="data in structure.info | orderBy:sortColumn:reverseSort">
<td ng-show="structure.tabs[0].selected">{{data.name}}</td>
<td ng-show="structure.tabs[1].selected">{{data.age}}</td>
<td ng-show="structure.tabs[2].selected">{{data.city}}</td>
<td ng-show="structure.tabs[3].selected">{{data.designation}}</td>
</tr>
</table>
<h1>Unique Values Table (per key)</h1>
<table border="1" width="100%" style="margin-top: 50px;">
<tr>
<th ng-repeat="header1 in structure.tabs" ng-show="header1.selected">{{header1.index}}</th>
</tr>
<tr>
<td ng-repeat="(hk, hv) in structure.tabs" ng-show="hv.selected">
<table border='1'>
<tr ng-repeat="(dk, dv) in structure.info | unique:hv.filter">
<td>
<input ng-model="item" type="checkbox" ng-change="getCheckedValues(item,dv,hv.filter)">{{dv[hv.filter]}}
</td>
</tr>
</table>
<br>
<button ng-click="getChecked(hv.filter)">Get Checked</button>
</td>
</tr>
</table>
</body>
</html>
app.js
var app = angular.module('myApp', []);
app.controller("myController", function ($scope,$log) {
$scope.sortColumn="name";
$scope.reverseSort=false;
$scope.sortData=function(column) {
$scope.reverseSort=($scope.sortColumn==column) ? !$scope.reverseSort : false;
$scope.sortColumn=column;
}
var array = []
array["name"] = [];
array["age"] = [];
array["designation"] = [];
array["city"] = [];
$scope.getCheckedValues = function(e,val,key){
console.log(val)
if(e){
array[key].push(e)
}else{
array[key].shift()
}
}
$scope.structure={
"tabs": [
{
"index": "Name",
"filter": "name",
"selected": true
},
{
"index": "Age",
"filter": "age",
"selected": true
},
{
"index": "City",
"filter": "city",
"selected": true
},
{
"index": "Designation",
"filter": "designation",
"selected": true
}
],
"info": [
{
"name": "Abar",
"age": "27",
"city": "Ghaziabad",
"designation": "Php Developer"
},
{
"name": "Abar",
"age": "27",
"city": "Okhla",
"designation": "Html Developer"
},
{
"name": "Nishant",
"age": "25",
"city": "Delhi",
"designation": "Angular Developer"
},
{
"name": "Amit",
"age": "30",
"city": "Noida",
"designation": "Android Developer"
}
]
};
$scope.getChecked = function(tab) {
alert("Need to get all checked value of key: "+tab);
console.log(array[tab])
}
});
app.filter('unique', function() {
return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
});
Alright. Apologies for my previous answer I completely botched the question.
Anyhow I spent almost an hour trying to solve this and managed to do it using $scope.$$watchers[0].last and underscorejs.
//this is how getChecked looks like now
$scope.getChecked = function(tab) {
var selectedKey = tab.$$watchers[0].last;
_.each($scope.structure.info,function(row){
_(row).pairs().filter(function(item){
_.each(item,function(key){
if(key===selectedKey)
{
console.log(row);
return;
}
})
})
})
Above method is responsible for identifying the key and spitting in console, each time you select a key in below table. So check console.
The solution is on below plunkr.
https://embed.plnkr.co/kbiCwhW0RrdHtO3hVEEk/

ng-repeat in other ng-repeat is not working

{
"data": {
"name": "NAME",
"tests": [
{
"testname": "abc",
"relatedResource": [
{
"accessType": "fttb",
},
{
"accessType": "fttn",
}
]
},
{
"testname": "xyz",
"relatedResource": [
{
"accessType": "fttp",
},
{
"accessType": "fttp",
}
]
}
]
}
}
Controller
$scope.data=response.data.tests;
<div ng-repeat="l in data">
<div ng-repeat="i in l.relatedResource">
{{i.accessType}}
</div>
</div>
try this, you need multiple ng-repeat to access relatedResource
here I printed the output
<div ng-controller="MyCtrl">
<div ng-repeat="(key,val) in data">
{{val.name}}
<div ng-repeat="test in val.tests">
- {{test.testname}}
<div ng-repeat="resource in test.relatedResource">
- -{{resource.accessType}}
</div>
</div>
</div>
</div>
Try this snippet
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.data = {
"data": {
"name": "NAME",
"tests": [
{
"testname": "abc",
"relatedResource": [
{
"accessType": "fttb",
},
{
"accessType": "fttn",
}
]
},
{
"testname": "xyz",
"relatedResource": [
{
"accessType": "fttp",
},
{
"accessType": "fttp",
}
]
}
]
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="obj in data">
<span ng-repeat="val in obj.tests">
{{val.testname}}
<span ng-repeat="v in val.relatedResource">
{{v.accessType}}
</span>
<br/>
</span>
</div>
</div>
There is actually not much information about the question.
If you receive the json-data from a remote server, you should always check and convert it to a real json-object.
You can simply use
$scope.data = response.data.tests;
$scope.getData = function()
{
return angular.toJson($scope.data);
}
or you can test it with:
{{data | json}}

AngularJS ng-repeat for a JSON contains String or an array of a same property

I'm having a JSON data namely $scope.family, it contains the family.name and optionally family.child
app.controller('test', function ($scope) {
$scope.family = [
{
"name": "Siva",
"child": [
{
"name": "Suriya"
},
{
"name": "Karthick"
}
]
},
{
"name": "Kumar",
"child": [
{
"name": "Rajini"
},
{
"name": "Kamal"
},
{
"name": "Ajith"
}
]
},
{
"name": "Samer",
"child": "Ranjan"
},
{
"name": "Mahesh",
"child": "Babu"
},
{
"name": "Joseph"
}
];
});
Cases:
If family.child has one child then the name is directly assign as a string
If family.child has more than one child then the name is assign as a array of string with the property family.child.name
If family.child doesn't in the collection just show the family.name
My Expected Output UI is
Siva
Suriya
Karthick
Kumar
Rajini
Kamal
Ajith
Samer
Ranjan
Mahesh
Babu
Joseph
My HTML Source Code (I Can't able to get the expected output from this code)
<ul>
<li ng-repeat="member in family">
{{ member.name }}
<div class="liststyling" ng-if="member.child.length > 0">
<ul>
<li ng-repeat="chdMember in member.child>
{{ chdMember.name }}
</li>
</ul>
</div>
</li>
</ul>
Kindly assist me...
Please refer the fiddle here. You need some changes in the model and loop with the new modified model - newFamily instead of family.
HTML:
<div ng-app="app" ng-controller="test">
<ul>
<li ng-repeat="member in newFamily">
{{ member.name }}
<div class="liststyling" ng-if="member.child.length > 0">
<ul>
<li ng-repeat="chdMember in member.child track by $index">
{{ chdMember.name }}
</li>
</ul>
</div>
</li>
</ul>
</div>
JS:
var app = angular.module('app', []);
app.controller('test', function ($scope) {
$scope.family = [
{
"name": "Siva",
"child": [
{
"name": "Suriya"
},
{
"name": "Karthick"
}
]
},
{
"name": "Kumar",
"child": [
{
"name": "Rajini"
},
{
"name": "Kamal"
},
{
"name": "Ajith"
}
]
},
{
"name": "Samer",
"child": "Ranjan"
},
{
"name": "Mahesh",
"child": "Babu"
},
{
"name": "Joseph"
}
];
$scope.newFamily = [];
angular.forEach($scope.family, function (v, k) {
var existingChildArray = v.child;
var newChildArray = [];
if (!angular.isArray(v.child) && v.child) {
newChildArray.push({ 'name': v.child });
}
var addChild = newChildArray.length > 0 ? newChildArray : existingChildArray;
$scope.newFamily.push({ 'name': v.name, 'child': addChild });
});
});
Try this for your actual output.
<ul>
<li ng-repeat="member in family">
{{ member.name }}
<div class="liststyling">
<ul>
<li ng-repeat="chdMember in member.child">
{{ chdMember.name }}
</li>
</ul>
</div>
</li>
</ul>
$scope.family = [
{
"name": "Siva",
"child":
[
{
"name": "Suriya"
},
{
"name": "Karthick"
}
]
},
{
"name": "Kumar",
"child": [
{
"name": "Rajini"
},
{
"name": "Kamal"
},
{
"name": "Ajith"
}
]
},
{
"name": "Samer",
"child": [{name:"Ranjan"}]
},
{
"name": "Mahesh",
"child": [{name:"Babu"}]
},
{
"name": "Joseph",
"child": []
}
];
You can add the following method to your controller
$scope.isArray = function(obj) {
return angular.isArray(obj);
}
and update the markup as
<li ng-repeat="member in family">
{{ member.name }}
<div class="liststyling">
<ul ng-if="isArray(member.child)">
<li ng-repeat="chdMember in member.child">
{{ chdMember.name }}
</li>
</ul>
<ul ng-if="member.child && !isArray(member.child)">
<li>
{{ member.child }}
</li>
</ul>
</div>
</li>
This should do, I think.
Even though #MarcNuri provided a good answer. But if you are not changing the data pattern you can use this also.
HTML
<ul>
<li ng-repeat="member in family">
{{ member.name }}
<div class="liststyling" ng-if="isArray(member.child) && member.child.length > 0">
<ul>
<li ng-repeat="chdMember in member.child">
{{ chdMember.name }}
</li>
</ul>
</div>
<div class="liststyling" ng-if="!isArray(member.child) && member.child.length > 0">
<ul>
<li>
{{ member.child}}
</li>
</ul>
</div>
</li>
</ul>
JS
app.controller('test', function ($scope) {
$scope.isArray = angular.isArray;
$scope.family = [
{
"name": "Siva",
"child": [
{
"name": "Suriya"
},
{
"name": "Karthick"
}
]
},
{
"name": "Kumar",
"child": [
{
"name": "Rajini"
},
{
"name": "Kamal"
},
{
"name": "Ajith"
}
]
},
{
"name": "Samer",
"child": "Ranjan"
},
{
"name": "Mahesh",
"child": "Babu"
},
{
"name": "Joseph"
}
];
});
just notice $scope.isArray = angular.isArray; in js.Find plank HERE
Here is a simple running version of your code JSFiddle (not the best coding practices)
Keep in mind that you should use at least AngularJS 1.1.15 version at least to use ng-if.
You should simply tidy up your script a little and it'll work:
HTML:
<body ng-app="myApp">
<div ng-controller="ctrl">
<ul>
<li ng-repeat="member in family">
<h2>
{{ member.name }}
</h2>
<div class="liststyling" ng-if="member.child.length > 0">
<ul>
<li ng-repeat="chdMember in member.child">
{{ chdMember.name }}
</li>
</ul>
</div>
</li>
</ul>
</div>
</body>
Javascript:
var app = angular.module('myApp',[]);
app.controller('ctrl', MyCtrl);
function MyCtrl($scope) {
$scope.family = [
{
"name": "Siva",
"child": [
{
"name": "Suriya"
},
{
"name": "Karthick"
}
]
},
{
"name": "Kumar",
"child": [
{
"name": "Rajini"
},
{
"name": "Kamal"
},
{
"name": "Ajith"
}
]
},
{
"name": "Samer",
"child": [{name:"Ranjan"}]
},
{
"name": "Mahesh",
"child": []
},
{
"name": "Joseph"
}
];
}

In Angular how can you dynamically add an input to be applied once

I have searched the web and found no example. I wonder if someone could help.
I have two instances of a dropdown or maybe more and I want to apply the add input dynamically to only that form but it applies to everyone with that ng-model everywhere on the web page.
The code is here https://plnkr.co/edit/PPDYKjztPF528yli9FbN
HTML:
<div class="main-content__right" ng-controller="QuestionController">
<div ng-repeat="element in questionList">
<fieldset>
<div ng-repeat="choice in formOptionData track by $index">
<a class="remove-field remove u-pull-right" ng-click="remove()">Remove</a>
<input id="input{{choice.name}}" placeholder="{{choice.label}}" type="number" name="{{choice.name}}">
</div>
<div id="add-more" class="well">
<div class="field">
<div style="width:100%;" class="dropdown">
<select name="{{options.name}}" id="select" data-ng-model="selectedValue" data-ng-options="options as options.label for options in element.inputElement | orderBy:'label'" ng-change="onCategoryChange(selectedValue)">
<option value="" data-id="null" disabled="" selected="">Select an item...</option>
</select>
</div>
</div>
{{formData}}
</div>
</fieldset>
</div>
</div>
APP.js
var app = angular.module("cab", []);
app.controller('QuestionController', function($scope) {
$scope.formOptionData = [];
$scope.selectedValue = {};
$scope.questionList = [{
"sectionTitle": "Travel",
"inputType": "select",
"inputElement": [{
"label": "Public transport",
"name": "travelOutgoing",
"helpInfo": "include train journeys",
"type": "select"
}, {
"label": "Taxis",
"name": "travelOutgoing",
"type": "select"
}
]
},
{
"sectionTitle": "Leisure",
"title": "Enter the amount you spend on entertainment and leisure. Leave them blank if they don\"t apply to you.",
"inputType": "select",
"inputElement": [
{
"label": "Eating out",
"name": "leisureOutgoing",
"helpInfo": "Include coffees, teas and snacks",
"type": "select"
},
{
"label": "Going out",
"name": "leisureOutgoing",
"helpInfo": "Include drinks, taxis, admission charges",
"type": "select"
}
] }
];
$scope.onCategoryChange = function(selectedItem) {
this.formOptionData.push(selectedItem);
};
$scope.remove = function(element) {
this.formData.splice(element,1);
};
});

Resources