Jack
Jack

Reputation: 1

Cannot pass input value from view to component using #input

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>.

Upvotes: 1

Views: 1014

Answers (3)

Dario Piotrowicz
Dario Piotrowicz

Reputation: 1102

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

Upvotes: 1

Tushar
Tushar

Reputation: 2078

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>

Upvotes: 1

DETSUP
DETSUP

Reputation: 107

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!

Upvotes: 2

Related Questions