In the process of constructing a website with the Angular 2 CLI, I have encountered a perplexing issue. Specifically, I am working on a page that features a reactive form and have developed a method named addQuestion() that is invoked within the ngOnInit lifecycle hook. Strangely, when this method is executed in ngOnInit, it successfully includes a Question object with an array of answers as intended. However, when I trigger the same method through a button press on the page, the resulting Question object lacks the attached array of answers. Upon inspection, I have identified a particular line where this discrepancy appears to arise.
Could someone shed some light on what mistake I might be making?
To provide further clarification, the addQuestion() method:
- Initializes a Question object
- Proceeds to create four answer objects and appends them to the Question object
- Ultimately pushes the completed Question object into a Questions array
Execution of this method from ngOnInit successfully generates a complete Question object containing four embedded answers, which are then added to the questions array.
Conversely, executing the method from a button press directly on the page using:
<a href="" (click)="addQuestion()">Add Question</a>
results in the addition of the Question object but without the anticipated answers array. The code snippet delineates where I suspect the error may lie. Notably, I've conducted console log commands preceding this line, confirming that the answers are being properly added. However, subsequent to the push operation, they seem to vanish. I speculate that this could be attributable to a scope-related issue, however, my limited experience as a junior developer impedes my ability to resolve it independently.
export class QuestionListComponent implements OnInit {
@Input('quizForm')
public quizForm: FormGroup;
@Input('questions')
public questions: Question[];
nextId: number;
constructor(private cd: ChangeDetectorRef) { }
// <previous> 1. Create FormGroup quizForm
// <previous> 2. Add Quiz controls to FormGroup (via toFormGroup)
// 3. Add questions FormArray to FormGroup
// 4. Add first Question to questions FormArray
ngOnInit() {
console.log('Initializing question list', this.questions);
this.nextId = 1;
this.quizForm.addControl('questions', new FormArray([]));
this.addQuestion();
}
private getNextId(): number{
return this.nextId++
}
addQuestion() {
const question: Question = {
id: this.getNextId(),
title: 'My Question',
instructions: 'Instructions here',
time: 30000,
answerId: 1,
answers: []
};
for(var i=1;i<=4;i++){
const a: Answer = {
id: i,
data: "Answer #" + i.toString(),
type: "TEXT"
}
question.answers.push(a);
}
this.questions.push(question); <--- This is the error line of code
this.cd.detectChanges();
return false;
}
Note: In crafting this code, I referenced an informative Reactive Forms tutorial, wherein interfaces rather than classes were employed. Despite my unfamiliarity with interfaces, I'm contemplating whether this distinction might correlate with my current predicament. Provided below are the interface definitions:
export interface Question {
id: number;
title: string;
instructions: string;
time: number;
answerId: number;
answers?: Answer[];
}
export interface Answer {
id: number;
data: string;
type: string;
}
As an additional troubleshooting measure, I will attempt converting these interfaces to classes to ascertain if it rectifies the issue. Furthermore, considering the possibility of an error originating from the HTML segment, I'm including the relevant code below for inspection.
<div [formGroup]="quizForm">
<div formArrayName="questions">
<div *ngFor="let question of questions; let idx=index">
Question {{question.id}} (<a href="" (click)="removeQuestion(idx)">Remove</a>)
<app-question-form [questions]="quizForm.controls.questions" [question]="question">
</app-question-form>
</div>
<a href="" (click)="addQuestion()">Add Question</a>
</div>
</div>
An elucidating insight emerged while researching similar issues on Stack Overflow. According to a response to a comparable inquiry, "You will not be able to access this input inside Component Two's constructor, only inside its 'ngOnInit.'" Intriguingly, it intersects with another user's explanation stating that Input decorators facilitate object transfer between components solely within the 'ngOnInit' context. If validated, this information poses a newfound challenge for me as it contradicts my prior understanding. Until now, I believed that was precisely the purpose served by the Input decorator.