1

I have the following component in html and I simply try to pass input value to the component:

<mat-accordion class="example-headers-align">
    <mat-expansion-panel [expanded]="expanded" hideToggle>
      <mat-form-field *ngIf="expanded">
        <input #empName matInput type="text" formControlName="empName"/>
      </mat-form-field>
    </mat-expansion-panel>
      <button *ngIf="expanded" mat-button (click)="add(empName.value)">Add</button>
    </div>
</mat-accordion>

However, the value is undefined in the component method and even I try to pass empName, instead of empName.value the parameter is also undefined. So, what is the mistake in this approach? How can I pass the input value without using [(ngModel)]?

add(data) { // data --> undefined
  this.add.emit(data)
}

I also get "Cannot read property 'value' of undefined" error on <button *ngIf="expanded" mat-button (click)="add(empName.value)">Add</button>.

1
  • I did not mention this in my solution but there's an extra </div> that breaks your template there Commented Dec 23, 2020 at 22:55

3 Answers 3

2

In your html file

<mat-accordion class="example-headers-align">
        <mat-expansion-panel [expanded]="expanded" hideToggle>
          <mat-form-field *ngIf="expanded">
            <input matInput type="text" [formControl]="empName"/>
          </mat-form-field>
        </mat-expansion-panel>
          <button *ngIf="expanded" mat-button (click)="add()">Add</button>
        </div>
    </mat-accordion>

In your ts file

empName = new FormControl('');

add() { // remove the parameter
  // this.add.emit(data), try if it is working first
     console.log(this.empName);
}

Hope it helps.

Happy Coding!

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot, but actually I am looking for a solution without using [(ngModel)]. Is it possible?
@Fredrick I have editted the answer. check if it works.
Thanks, again I am wondering why is it not possible to pass a value easily? I am wondering if it is possible or not without using form control or ngModel.
1

Explanation

What you are doing is perfectly valid but you have not taken into consideration the scope of the template variables.

Using structural directives creates scopes/boundaries which block the usage of those variables, as you can see there: https://angular.io/guide/template-reference-variables#template-variable-scope

So to solve your problem in the way you want you need to work on your template and remove the usage of the *ngIfs

A Partial solution

The following code which just omits the *ngIfs works as you'd expect it to (naturally this is not a complete solution since your component without the *ngIfs just behaves differently from what you wanted):

<div>
    <mat-accordion class="example-headers-align">
        <mat-expansion-panel [expanded]="false" hideToggle>
            <mat-form-field>
                <input #empName matInput type="text" formControlName="empName" >
      </mat-form-field>
        </mat-expansion-panel>
        <button mat-button (click)="add(empName.value)">Add</button>
    </mat-accordion>
</div>

You can check it out in this stackblitz project: https://stackblitz.com/edit/angular-ivy-c64ppz?file=src/app/app.component.html (please ignore the console errors on the material components, those are not the point here :P)

A Possible Solution

One thing that would change your code in the smallest degree but allow you to keep your implementation could be to avoid the *ngIfs but hide the elements via css instead, as in the following:

Template:

<div>
    <mat-accordion class="example-headers-align">
        <mat-expansion-panel [expanded]="expended" hideToggle>
            <mat-form-field [ngClass]="{'hidden': !expanded}">
                <input #empName matInput type="text" formControlName="empName" >
      </mat-form-field>
        </mat-expansion-panel>
        <button [ngClass]="{'hidden': !expanded}" mat-button (click)="add(empName.value)">Add</button>
    </mat-accordion>
</div>

css:

.hidden {
  display: none;
}

Again here's a stackblitz in which you can see it working: https://stackblitz.com/edit/angular-ivy-iamrut?file=src/app/app.component.html

1 Comment

My pleasure :) , I think it was important to explain why something which is a standard angular feature was just not working, instead of finding alternative ways to accomplish what you wanted. Anyway the scope I think is just the only tricky aspect of the template variables, so I believe it's good that you got to experience it first hand here :)
1

You are using formControlName with reactive forms, so if you want to access the value of this fields, then you have to access it from the formGroup form object.

Something like this:

employeeForm: FormGroup;

and the value of the form fields you can acess like this:

employeeForm.value.empName

So in your function try to pass value like this:

<button *ngIf="expanded" mat-button (click)="add(employeeForm.value.empName)">Add</button>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.