I have this simple directive in Angular for counting nested arrays:
import { AfterViewInit, Directive, Input, OnDestroy } from '@angular/core';
@Directive({
selector: '[rhsNestedArrayCounter]',
exportAs: 'rhsNestedArrayCounter'
})
export class NestedArrayCounterDirective implements AfterViewInit, OnDestroy {
static nextIndex = -1;
@Input() appCounter: number | string = '';
index;
constructor() {
this.index = NestedArrayCounterDirective.nextIndex++;
}
ngAfterViewInit(): void {
if (typeof this.appCounter === 'string') {
return;
}
NestedArrayCounterDirective.nextIndex = this.appCounter;
}
ngOnDestroy(): void {
NestedArrayCounterDirective.nextIndex = -1;
}
}
And I used it in my html like this, lets call it FormComponent:
<form [formGroup]="detailForm" class="form-container">
<ng-container rhsNestedArrayCounter="0">
<div *ngFor="let section of sections; let sectionIndex = index">
<div class="section">
<div class="section-content">
<h3>{{ section.title }}</h3>
<div formArrayName="responses">
<div
*ngFor="
let questionWithAnswer of section.questionsWithAnswers;
let questionIndex = index
">
<div class="question">
<div
rhsNestedArrayCounter
#counter="rhsNestedArrayCounter"
class="question-content"
[formGroupName]="counter.index">
<h4>
{{
questionWithAnswer.questionDescription
| textReplacer: '#EmployeeName':employeeName
}}
</h4>
<div>
<mat-form-field
color="accent"
id="sectionAnswer-{{ counter.index }}">
<textarea
matInput
placeholder="Answer"
formControlName="text"
name="text"
id="sectionAnswerInput-{{ counter.index }}"
[required]="questionWithAnswer.isRequired"
cdkTextareaAutosize
#autosize="cdkTextareaAutosize"
cdkAutosizeMinRows="2"
cdkAutosizeMaxRows="6"></textarea>
<mat-error
*ngIf="responses.controls[counter.index].get('text')?.errors?.['required']"
id="sectionAnswerError"
>Required field</mat-error
>
<mat-error
*ngIf="responses.controls[counter.index].get('text')?.errors?.['minlength']"
id="sectionAnswerMinLengthError"
>Min 2 characters</mat-error
>
<mat-error
*ngIf="responses.controls[counter.index].get('text')?.errors?.['maxlength']"
id="sectionAnswerMaxLengthError"
>Max 6000 characters</mat-error
>
<mat-error
*ngIf="responses.controls[counter.index].get('text')?.errors?.['pattern']"
id="sectionAnswerSpecialCharactersPatternError"
>Only letters, numbers, and some punctuation marks are
allowed.</mat-error
>
</mat-form-field>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</ng-container>
</form>
When I used FormComponent in my PageComponent one time everything worked fine, now I have a PageTwoComponent and I need to use the FormComponent more than one time, and because this counter is global I got errors about the index. For example the form have 15 questions, and I got the error of index 16 because when start count the second FormComponent it start from 16 because the first FormComponent finish in 15 (using two times the FormComponent in a Parent component).
So I thought maybe used a dictionary in the directive where I have for every component a unique index for every name, but I don’t know how to implement this, or maybe another idea (I’m a C# developer) any help is welcome.
2
Answers
If I understood it correctly, you want such usage
rhsNestedArrayCounter="0"
to restore counter to index 0, and then justrhsNestedArrayCounter
to save current index and increment it.If that is so then you should firstly use ngOnInit hook rather than ngAfterViewInit, and, considering your usage
rhsNestedArrayCounter="0"
0 would be passed as a string "0" here.also to not make hacks with initializing and clearing the "counter" in directives, you can use a simple service for that counter, which you’ll just put in the parent component’s
providers
sectionand that service should basically created "scoped" version of counter for the FormComponent and it should resolve the problem for you
provide service like here
and use increment in the directive like here
even without any hooks it should work correctly
using the directive multiple times in different components, they all share the same static nextIndex value, which is causing the index to increment globally.
create a counter service
user the counert in your directive
send unique key for every instance