I get an exception Error TypeError and Error Context
when the submit button is clicked. If I will delete the ngIf
directive It will work as excepted, The Full StackTrace:
PlayerNameFormComponent.html:8 ERROR TypeError: Cannot read property 'value' of undefined
at Object.eval [as handleEvent] (PlayerNameFormComponent.html:8)
at handleEvent (core.js:13547)
at callWithDebugContext (core.js:15056)
at Object.debugHandleEvent [as handleEvent] (core.js:14643)
at dispatchEvent (core.js:9962)
at eval (core.js:12301)
at SafeSubscriber.schedulerFn [as _next] (core.js:4343)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:240)
at SafeSubscriber.next (Subscriber.js:187)
at Subscriber._next (Subscriber.js:128)
PlayerNameFormComponent.html
<form (ngSubmit)="onSubmit(firstPlayer.value, secondPlayer.value)"> // The line that throws the exception
<div class="input-field col s6">
<label for="firstPlayer">First Player Name</label>
<input #firstPlayer id="firstPlayer" name="firstPlayer" type="text" class="validate">
</div>
<div *ngIf="isMultiplePlayers" class="input-field col s6">
<label for="secondPlayer">Second Player Name</label>
<input #secondPlayer id="secondPlayer" name="secondPlayer" type="text" class="validate">
</div>
<button type="submit" class="waves-effect waves-light btn">Start</button>
</form>
PlayerNameFormComponent.ts
export class PlayerNameFormComponent {
isMultiplePlayers = true;
public onSubmit(firstPlayer: string, secondPlayer: string) {
console.log(firstPlayer);
console.log(secondPlayer);
}
}
EDIT:
I changed my form tag to - <form (ngSubmit)="onSubmit(firstPlayer?.value, secondPlayer?.value)">
and now its print to console the firstPlayer input value and instead of secondPlayer value its prints null
Thanks for any kind of help :)
Template reference variables can be accessed anywhere in template, so the docs state clearly. This article is very helpful to understand what happens with structular directives, in this case your *ngIf
.
What happens with the *ngIf
is that it creates it's own template, so your template reference is accessible inside the template, the template created by *ngIf
and only in that scope.
Here's excerpt from the website:
Sample code that throws error:
<div *ngIf="true">
<my-component #variable [input]="'Do you see me?'>
</div>
{{ variable.input }}
The reason for this is the ngIf directive - or any other directive used together with a star (*). These directives are so called structural directives and the star is just a short form for something more complex. Every time you use a structural directive (ngIf, ngFor, ngSwitchCase, ...) Angular's view engine is desugaring (it removes the syntactical sugar) the star within two steps to the following final form (using the previous ngIf as an example):
<ng-template [ngIf]="true">
...
</ng-template>`
Did you notice? Something extraordinary emerged out of the previous HTML containing the structural directive - the ng-template node. This node is the reason for limiting the scope of the template reference variable to exactly this inner DOM part only - it defines a new template inside. Because of limiting a variable to its defining template any variable defined within the ng-template (and this means within the DOM part of the ngIf) cannot be used outside of it. It cannot cross the borders of a template.
But how to solve your underlying problem, i.e getting the values... You almost have a template-driven form set up already, so you could do that, or then go the reactive way :)
Your problem doesn't come from your *ngIf
. Try to remove temporary the error, using Elvis operator:
onSubmit(firstPlayer?.value, secondPlayer?.value)
Or you can make sure into your onSubmit that the HTML element firstPlayer and secondePlayer return HTMLObject.
Into your component, do this:
onSubmit(firstPlayer, secondPlayer) {
console.log(firstPlayer, secondPlayer);
}
And into your HTML template, change the (ngSubmit)
line with:
<form (ngSubmit)="onSubmit(firstPlayer, secondPlayer)">
If the result is correction you get ...
<input id="firstPlayer" name="firstPlayer" type="text" class="validate">
...
... into the console.
If it is really undefined, use [ngModel]="firstPlayer"
and check if the error still occurs.