how to use ng-repeats in ng-repeat with ng-if - angularjs

I am trying to do following but it's not working.
<div ng-repeat="a in ar">
<div ng-repeat="b in br">
<div ng-if="a.num == b.num">{{b.type}}
</div>
</div>
</div>
I am trying to do array objectives comparing same values
arrays is
ar = [ {num:1, str:"a"}, {num:2, str:"b"}, {num:3, str:"c"} ];
br = [ {num:3, type:"text"}, {num:5, type:"number"}, {num:8, type:"date"}];

It is working, its creating the outside divs, you can see it if you add a reference to the a items:
<div ng-repeat="a in ar">
{{a.str}}
<div ng-repeat="b in br">
<div ng-if="a.num == b.num">
{{b.type}}
</div>
</div>
</div>

Related

Storing dynamic form field as an array in angular

question.component.ts
ngOnInit() {
this.challengeId = this.route.snapshot.paramMap.get('challengeId');
// this.selectedNoOfAttempt = this.noofattempts[1];
this.myForm = this._fb.group({
question: ['', [Validators.required]],
correctAnswers: this._fb.array([
this.initCorrectAnswer(),
]),
selectedNoOfAttempt: ['', [Validators.required]]
});
}
initCorrectAnswer() {
return this._fb.group({
correctAnswers: ['', Validators.required],
});
}
addAnswer() {
const control = <FormArray>this.myForm.controls['correctAnswers'];
control.push(this.initCorrectAnswer());
}
removeAnswer(i: number) {
const control = <FormArray>this.myForm.controls['correctAnswers'];
control.removeAt(i);
}
question.component.html
<div formArrayName="correctAnswers">
<div *ngFor="let correctAnswers of myForm.controls.correctAnswers.controls; let i=index" class="panel panel-default">
<div class="panel-heading">
<span>Answer {{i + 1}}</span>
<span class="glyphicon glyphicon-remove pull-right" *ngIf="myForm.controls.correctAnswers.controls.length > 1" (click)="removeAnswer(i)">Remove</span>
</div>
<div class="panel-body" [formGroupName]="i">
<div class="form-group col-xs-3">
<input type="text" class="form-control" formControlName="correctAnswers">
<small [hidden]="myForm.controls.correctAnswers.controls[i].controls.correctAnswers.valid" class="text-danger">
Answer is required
</small>
</div>
</div>
</div>
</div>
<div class="margin-20">
<a (click)="addAnswer()" style="cursor: default">
Add another answer +
</a>
</div>
The code above works as it is intended, dynamically insert more fields if needed, and also remove. It also able to return all the dynamic fields, however it is storing the data as
correctAnswers (array)
[0] (object)
correctAnswers: "test" (string)
[1] (object)
correctAnswers: "abc" (string)
I would like to store the data as follow
correctAnswers (array)
[0] "test" (string)
[1] "abc" (string)
In your initCorrectAnswer() function you are adding form group with child form control to your form array, that is why you see it as array of objects. Instead of this, you should add form control:
initCorrectAnswer() {
return this._fb.control('', Validators.required);
}
I also added correctAnswers getter for convenient use in HTML:
get correctAnswers(): FormArray {
return this.myForm.get('correctAnswers') as FormArray;
}
updated add and remove functions:
addAnswer() {
this.correctAnswers.push(this.initCorrectAnswer());
}
removeAnswer(i: number) {
this.correctAnswers.removeAt(i);
}
here is HTML:
<form [formGroup]="myForm">
<div formArrayName="correctAnswers">
<div class="panel panel-default"
*ngFor="let correctAnswer of correctAnswers.controls; index as i">
<div class="panel-heading">
<span>Answer {{i + 1}}</span>
<span class="glyphicon glyphicon-remove pull-right"
*ngIf="correctAnswers.controls.length > 1"
(click)="removeAnswer(i)">Remove</span>
</div>
<div class="panel-body">
<div class="form-group col-xs-3">
<input type="text" class="form-control" [formControlName]="i">
<small [hidden]="correctAnswer.valid" class="text-danger">
Answer is required
</small>
</div>
</div>
</div>
</div>
</form>
StackBlitz: https://stackblitz.com/edit/angular-643srq?file=app%2Fapp.component.html
Official reference
There is no way for you to achieve it through Angular's reactive form, because every form group that is repeated (via your *ngFor) is an object. Note that your form group name is actually your *ngFor index: formGroupName = i; and that your form control is correctAnswers - that corresponds to your object property with name correctAnswers as you have expected it.
You can however, do some post processing though. Simply use an array map() to flatten your object into arrays:
var flattenedArray = this.myForm.correctAnswers.map(x=>x.correctAnswers);

Angular Multi-item carousel

Ive been trying to make the angular carousel work, but iam currently stuck.
I am a newbie in angular, thus can i not get the ng-repeat too work correct.
what ive done:
<div id="slides_control">
<div>
<carousel interval="3000">
<slide ng-repeat="book in bookslider" active="book.active">
<div class="col-md-3"><img ng-src="{{book.img}}"></div>
<div class="col-md-3"><img ng-src="{{book[$index +1].img}}"></div>
<div class="col-md-3"><img ng-src="{{book[$index +2].img}}"></div>
<div class="col-md-3"><img ng-src="{{book[$index +3].img}}"></div>
<div class="carousel-caption">
<h4>Slide {{$index+1}}</h4>
</div>
</slide>
</carousel>
</div>
$scope.bookslider = [
{
img: "images/headerslider/5.jpg"
},
{
img: "images/headerslider/4.jpg"
},
{
img: "images/headerslider/2.jpg"
},
{
img: "images/headerslider/3.jpg"
}
];
This display only the first image because it cannot "render" - book[$index +1].img how would one go about getting the next index item for this situation?
Working plunk: http://plnkr.co/edit/VcD8tKOtfQGuOgt4tO08
I gone through the plunker you provided and I under stand your requirement. I think the mistake that you made is where you loop the bookslider object. You need to loop through bookslider object instead of that you looped through the book object which is actually an individual object of the bookslider array.
You just change the carousel object like this to fix the issue.
<carousel interval="3000">
<slide ng-repeat="book in bookslider track by $index" active="book.active">
<div class="col-md-3"><img ng-src="{{bookslider[($index) %4 ].img}}" style="width=100px"></div>
<div class="col-md-3"><img ng-src="{{bookslider[($index+1) % 4].img}}"></div>
<div class="col-md-3"><img ng-src="{{bookslider[($index+2) % 4].img}}"></div>
<div class="col-md-3"><img ng-src="{{bookslider[($index+3) % 4].img}}"></div>
<div class="carousel-caption">
<h4>Slide {{$index+1}}</h4>
</div>
</slide>
</carousel>
I have attached the working plunker here.

Creating parent div inside ng-repeat

I have 25 items from JSON string. Each item comes with a key called "InRowPlcement" and the value is assigned as "0" or "1" or "2" so on.
{"ItemID":"516","ItemName":"Newzeland Lake Tysonno","InRowPlcement":0},
{"ItemID":"514","ItemName":"Newzeland Lake Tysonno","InRowPlcement":0},
{"ItemID":"546","ItemName":"Underworld Lives","InRowPlcement":0},
{"ItemID":"527","ItemName":"In a holiday beach","InRowPlcement":1},
{"ItemID":"542","ItemName":"Underworld Lives","InRowPlcement":1},
{"ItemID":"525","ItemName":"Lake somewhere","InRowPlcement":1},
{"ItemID":"540","ItemName":"Coral Structure at Andaman","InRowPlcement":1},
{"ItemID":"569","ItemName":"Ice Rock, Ireland","InRowPlcement":2}
The intention is, placed the "0" "InRowPlacement" items in the first row, "1" in the second row, "2" in the third row and so on. The number of items may vary in each row. It may possible from 1 to 5 in a single row.
I started the ng-repeat
<div class="ROW" ng-repeat="item in items">
<div class="COLUMN">{{item.ItemName}}<div>
</div>
I need the result should be like
<div class="ROW">
<div class="COLUMN">Newzeland Lake Tysonno<div>
<div class="COLUMN">Newzeland Lake Tysonno<div>
<div class="COLUMN">Underworld Lives<div>
</div>
<div class="ROW">
<div class="COLUMN">In a holiday beach<div>
<div class="COLUMN">Underworld Lives<div>
<div class="COLUMN">Lake somewhere<div>
<div class="COLUMN">Coral Structure at Andaman<div>
</div>
Thanks in advance for your help.
SOLUTION UPDATE:
Based on the logic provided by #vp_arth, here is the actual code, which works for me
var view_rows = {};
angular.forEach(response.data, function(InRowPlcement,index){
if (!view_rows[response.data[index].InRowPlcement]) view_rows[response.data[index].InRowPlcement] = [];
view_rows[response.data[index].InRowPlcement].push(response.data[index]);
});
groups = view_rows;
This can be done with bunch of filters, but much better just prepare your data structure for view layer in the controller.
In your controller:
let data = [
{"ItemID":"516","ItemName":"Newzeland Lake Tysonno","InRowPlcement":0},
{"ItemID":"514","ItemName":"Newzeland Lake Tysonno","InRowPlcement":0},
{"ItemID":"546","ItemName":"Underworld Lives","InRowPlcement":0},
{"ItemID":"527","ItemName":"In a holiday beach","InRowPlcement":1},
{"ItemID":"542","ItemName":"Underworld Lives","InRowPlcement":1},
{"ItemID":"525","ItemName":"Lake somewhere","InRowPlcement":1},
{"ItemID":"540","ItemName":"Coral Structure at Andaman","InRowPlcement":1},
{"ItemID":"569","ItemName":"Ice Rock, Ireland","InRowPlcement":2}
];
let view_rows = {};
data.forEach(row => {
if (!view_rows[row.InRowPlcment]) view_rows[row.InRowPlcment] = [];
view_rows[row.InRowPlcment].push(row);
});
$scope.groups = view_rows;
Then, in view:
<div class="ROW" ng-repeat="(i, rows) in groups">
<div class="COLUMN" ng-repeat="row in rows">{{row.ItemName}}<div>
</div>
You could add the expression in DOM using ng-if to breakdown the items.
<div class="ROW" ng-repeat="item in items">
<div ng-if ="item.InRowPlcement == 0">
<div class="COLUMN">{{item.ItemName}}<div>
</div>
<div ng-if ="item.InRowPlcement == 1">
<div class="COLUMN">{{item.ItemName}}<div>
</div>
<div ng-if ="item.InRowPlcement == 2">
<div class="COLUMN">{{item.ItemName}}<div>
</div>
</div>
Working Plunker: https://plnkr.co/edit/vFR6NUIu6Uyl8XSOTiax?p=preview
I have written the below code as per your requirement and believe that it would work as per your requirement.
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.8/angular-filter.js"></script>
<script>
var mainModule = angular.module('mainModule', ['angular.filter']);
mainModule.controller('mainCntrl', function($scope) {
$scope.items = [
{"ItemID":"516","ItemName":"Newzeland Lake Tysonno","InRowPlcement":0},
{"ItemID":"514","ItemName":"Newzeland Lake Tysonno","InRowPlcement":0},
{"ItemID":"546","ItemName":"Underworld Lives","InRowPlcement":0},
{"ItemID":"527","ItemName":"In a holiday beach","InRowPlcement":1},
{"ItemID":"542","ItemName":"Underworld Lives","InRowPlcement":1},
{"ItemID":"525","ItemName":"Lake somewhere","InRowPlcement":1},
{"ItemID":"540","ItemName":"Coral Structure at Andaman","InRowPlcement":1},
{"ItemID":"569","ItemName":"Ice Rock, Ireland","InRowPlcement":2}
];
});
</script>
</head>
<body ng-app="mainModule">
<div ng-controller="mainCntrl">
<ul ng-repeat="(key, value) in items | groupBy: 'InRowPlcement'">
<div class="ROW">
<div class="COLUMN" ng-repeat="item in value">
{{ item.ItemName }}
</li>
</div>
</ul>
</div>
</body>
</html>

Want to use subarray in ng-repeat

My two dimensional is like this
{
"MKey1": {
"v1": "2015-10-29 14:03:41",
"v2": "2016-01-04 15:36:13",
"v3": "2015-11-02 19:53:11",
"v4": "2015-12-09 19:15:04",
"v5": "2015-08-18 19:12:37",
"v6": "2015-09-20 17 :00:58"
},
"Mkey2": {
"v1": "2015-10-29 14:03:41",
".v2": "2016-01-04 15:36:13",
"v3": "2015-11-02 19:53:11",
"v4": "2015-12-09 19:15:04",
"v5": "2015-08-18 19:12:37",
"v6": "2015-09-20 17:00:58"
}
}
here almost everything is dynamic, even Key & values. Want to take first set of array and need to print inner array key values in table
Try like this
<div ng-repeat="(key, value) in obj" ng-if="$first">
<div ng-repeat="(subkey, subvalue) in value">
{{subvalue}}
</div>
</div>
DEMO
Try this
<div ng-repeat="value in object">
<!-- get all nested objects -->
<div ng-repeat="values in value">
<!--get values of all nested object -->
{{values}}
</div>
</div>
you can also use $index in parent loop
<div ng-app="myApp">
<div data-ng-controller="myCtrl">
<div ng-repeat="(key, value) in obj" ng-if="$index==0">
{{key}}
<div ng-repeat="(subkey, subvalue) in value">
{{subkey}} : {{subvalue}}
</div>
</div>
</div>
https://jsfiddle.net/Frangly/jpe1vyrb/2/

In ng-repeat how to get the $last item in a filter?

I define a collection of language objects like this:
$scope.languages = [
{'name':'English', value:'english', 'checked':true, 'available': true},
{'name':'German', value:'german', 'checked':false, 'available': true},
{'name':'Spanish', value:'spanish', 'checked':true, 'available': true}
];
Then I display them in checkboxes like this:
<div class="form-group">
<label for="description">Languages</label>
<div class="checkbox" data-ng-repeat="language in languages">
<label><input type="checkbox" ng-model="language.checked">{{language.name}}</label>
</div>
</div>
And as they are checked on and off, I display a list of them like this:
<div class="dataRow">
<div class="dataLabel">Languages:</div>
<div class="dataValue text-success" data-ng-repeat="language in languages">
<span ng-if="language.checked">{{language.name + ($last ? '' : ',')}}</span>
</div>
<div class="clear"></div>
</div>
And as long as the last language is selected, then the final comma will not be shown. But if the last language (Spanish) is not selected, then the final comma is erroneously shown.
Instead of $last I need something like $last(isChecked). How do I do that?
You could iterate only over the checked items by adding a filter in your ng-repeat like this:
<div class="dataRow">
<div class="dataLabel">Languages:</div>
<div class="dataValue text-success" data-ng-repeat="language in languages | filter: {checked: true}">
{{language.name + ($last ? '' : ',')}}
</div>
<div class="clear"></div>
</div>
That way you know the last element is checked.
Here's a working fiddle http://jsfiddle.net/q7ch1ysh/
Just specify that in the ternary:
language.name + ($last && language.checked ? '' : ',')
try this:
<div class="dataValue text-success" data-ng-repeat="language in languages track by $index">
<span ng-if="language.checked">{{language.name + (($index==languages.length && language.checked) ? '' : ',')}}</span>
</div>

Resources