x
)- [x] bug report -> please search issues before submitting
- [ ] feature request
@Angular/cli: 1.0.1
node: 7.5.0
os: win32 x64
Windows (10)
Running the application using ng serve
works fine.
using ng build
works fine.
when using ng build --prod --aot
or ng build --prod
I get the error.
It points back to this html file and the controls property??
````html
````
ERROR in ng:///C:/Angular/lanes4/src/app/containers/edit-user.component.html (34,13): Property 'controls' does exist on type 'AbstractControl'.
I would like to build it using --prod and --aot
Happened since updating to version 4.0.0, i've just been using ng build
Can be fixed by giving your component a get method:
get formData {
return this.form.get('Data');
}
and then in your template:
<div class="form-group" *ngFor="let field of formData.controls; let i = index">
@Thisen, It works with ng s
but I am still getting the same error when building using either ng build --prod
or ng build --prod --aot
.
Property 'controls
' does not exist on type 'AbstractControl'.
Thank you
Got it!
Looked at the docs - FormArray
The FormArray class contains the controls
property.
get formData() {
return <FormArray>this.passwordForm.get('Data');
}
Thanks @Thisen, without you help it would've taken longer.
I'm experiencing the same issue when trying to run ng build --prod
with the snippet below although it seems my circumstance is a bit different. Not seeing this occur on any of my other forms?
Can either of your offer any guidance? I'm also running 4.0.0
.
<form id="reset-password-form" novalidate [formGroup]="form" (ngSubmit)="submitForm()">
<div fxLayout fxLayoutWrap>
<!-- Current Password -->
<div fxFlex="50%" fxFlex.xs="100%">
<md-input-container id="currentPassword-container" class="full-width">
<md-placeholder>Current Password</md-placeholder>
<input id="currentPassword" mdInput required type="password" formControlName="currentPassword">
<md-hint align="end" *ngIf="form.controls.currentPassword.dirty && form.controls.currentPassword.errors?.required">Current password is required</md-hint>
<md-hint align="end" *ngIf="form.controls.currentPassword.dirty && form.controls.currentPassword.errors?.pattern">Must contain 8-16 characters, letters and numbers and symbols</md-hint>
</md-input-container>
</div>
<div fxFlex="50%" fxFlex.xs="100%"></div>
<div fxFlex="100%" fxLayout fxLayoutWrap formGroupName="passwords">
<!-- New Password -->
<div fxFlex="50%" fxFlex.xs="100%">
<md-input-container id="password-container" class="full-width">
<md-placeholder>New Password</md-placeholder>
<input id="password" mdInput required type="password" formControlName="password">
<md-hint align="end" *ngIf="form.controls.passwords.controls.password.dirty && form.controls.passwords.controls.password.errors?.required">New password is required</md-hint>
<md-hint align="end" *ngIf="form.controls.passwords.controls.password.dirty && form.controls.passwords.controls.password.errors?.pattern">Must contain 8-16 characters, letters and numbers and symbols</md-hint>
</md-input-container>
</div>
<div fxFlex="50%" fxFlex.xs="100%"></div>
<!-- Confirm Password -->
<div fxFlex="50%" fxFlex.xs="100%">
<md-input-container id="confirmPassword-container" class="full-width">
<md-placeholder>Confirm New Password</md-placeholder>
<input id="confirmPassword" mdInput required type="password" formControlName="confirmPassword">
<md-hint align="end" *ngIf="form.controls.passwords.controls.confirmPassword.dirty && form.controls.passwords.controls.confirmPassword.errors?.required">Password confirmation is required</md-hint>
<md-hint align="end" *ngIf="form.controls.passwords.controls.confirmPassword.dirty && !form.controls.passwords.controls.confirmPassword.errors?.required &&form.controls.passwords.errors?.passwordMismatch">Passwords do not match</md-hint>
</md-input-container>
</div>
<div fxFlex="50%" fxFlex.xs="100%"></div>
</div>
</div>
<div fxLayout fxLayoutAlign="center">
<!--Action buttons-->
<button md-raised-button type="submit" [disabled]="!form.valid">RESET PASSWORD</button>
</div>
</form>
ERROR in ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (22,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (22,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (22,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (23,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (23,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (23,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (32,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (32,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (32,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (33,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (33,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (33,11): Property 'controls' does not exist on type 'AbstractControl'.
so, my issue was solved by changing the way controls were referenced in my <md-hint>
blocks
changed to form['controls'].passwords['controls'].confirmPassword.dirty
.
can anyone expand one why this is necessary with forms? is it because of the change detection cycle? I find it quite curious that the error was only ocurring on one of my form when the pattern I was using was consistent all forms...
This problem still present.
If use form.get('Data').controls inside *ngFor and run ng build --prod, you will see error:
Property 'controls' does not exist on type 'AbstractControl'.
Angular CLI: 1.0.6
Angular: 4.1.3
node: 6.10.3
I can confirm this.
when using --prod
the HTML fails:
Property 'controls' does not exist on type 'AbstractControl'.
For now, I'm usin workaround of passing the logic to the ts
, but it's not good because it's a public method.
version: Angular 4
@angular/cli: 1.2.1
node: 8.2.1
os: darwin x64
I can run the program on localhost: 4200. When ng build -- prod --aot, I get the following error:
Property 'controls' does not exist on type 'AbstractControl'.
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params, Router } from "@angular/router";
import { FormGroup, FormControl, FormArray, Validators } from "@angular/forms";
import { RecipeService } from "app/recipes/recipe.service";
import { Recipe } from "app/recipes/recipe.model";
@Component({
selector: 'app-recipe-edit',
templateUrl: './recipe-edit.component.html',
styleUrls: ['./recipe-edit.component.css']
})
export class RecipeEditComponent implements OnInit {
id: number;
editMode = false;
recipeForm: FormGroup;
constructor(private route: ActivatedRoute,
private recipeService: RecipeService,
private router: Router) { }
ngOnInit() {
this.route.params.subscribe(
(params: Params) => {
this.id = +params['id'];
this.editMode = params['id'] != null;
this.initForm();
// console.log(this.editMode);
}
);
}
onSubmit() {
const newRecipe = new Recipe(
this.recipeForm.value['name'],
this.recipeForm.value['description'],
this.recipeForm.value ['imagePath'],
this.recipeForm.value ['ingredients']);
if (this.editMode) {
this.recipeService.updateRecipe(this.id, newRecipe);
}
else {
this.recipeService.addRecipe(newRecipe);
}
}
onClickX(index: number) {
(
}
onClickCancel(){
this.router.navigate(['../'], {relativeTo: this.route})
}
onClickAddIngredient() {
(
'name': new FormControl(null, Validators.required),
'amount': new FormControl(null,
// [Validators.required,
// Validators.pattern(/'^[1-9]+[0-9]*$'/)]
)
})
);
}
private initForm() {
let recipeName = '';
let recipeImagePath = '';
let recipeDescription = '';
let recipeIngredients = new FormArray([]);
if(this.editMode) {
const recipe = this.recipeService.getRecipe(this.id);
recipeName = recipe.name;
recipeImagePath = recipe.imagePath;
recipeDescription = recipe.description;
if(recipe['ingredients']) {
for(let ingredient of recipe.ingredients) {
recipeIngredients.push(
new FormGroup({
'name': new FormControl(ingredient.name, Validators.required),
'amount': new FormControl(ingredient.amount, [
Validators.required,
// Validators.pattern(/'^[1-9]+[0-9]*$'/)
])
})
);
}
}
}
this.recipeForm = new FormGroup({
'name': new FormControl(recipeName, Validators.required),
'imagePath': new FormControl(recipeImagePath, Validators.required),
'description': new FormControl(recipeDescription, Validators.required),
'ingredients': recipeIngredients
});
}
}
I am using 'get'. Can anyone help? Any suggestions?
Thank you.
La solucion mas facil es: formGroup.controls['any']['controls'].
Thank you!!
Having the same problem. ERROR in ng:///C:/Web/src/app/part-d-table/Modules/d8-tables/d8-tables.component.html (129,81): Property 'PercentVal' does not exist on type 'any[]'.
ERROR in ng:///C:/Web/src/app/dashboard/dashboard.component.html (25,30): Property 'center' does not exist on type boardComponent'.
ERROR in ng:Web/src/app/column-a-table/column-a-table.component.html (12,40): Property 'refresh' does not exist on type 'ColumnTableComponent'
But works when I use ng build
thnks @zpydee , this solution worked for me:
i used myForm['controls'].links['controls'] instead of myForm.controls.links.controls
What works for me (even using --prod flag) is, instead of using controls in the FormArray I use value:
*ngFor="let item of myForm.get('items').value"
formGroupName.controls['attributeName'] works for me
In my case only ng build --prod --aot
was failing with Property 'controls' does not exist on type 'AbstractControl'
I changed
<div *ngFor="let arr_item of myForm.controls['some_items'].controls;let indx=index;let lst=last;" class="input-group">
to
<div *ngFor="let js_arr_item of getControls(myForm, 'some_items');let indx=index;let lst=last;" class="input-group">
&
getControls(frmGrp: FormGroup, key: string) {
return (<FormArray>frmGrp.controls[key]).controls;
}
turns out, its yet another "cast" issue (pun intended) ;-)
Thanks @shammelburg souflam
Solution worked for me
change:
myForm.get('some_items').controls
to:
myForm.get('some_items')['controls'];
worked for me when using --prod
Did the same as @leandrodiniz and it also worked with --env=prod --aot
.
Hi, I am using an abstract control in the form which has child component.
For some reason the child inputs get disabled. I am trying to keep it enabled all the time.
Not sure what I am doing wrong. :(
tried: this.paymentMethodForm.controls['card-number'].disable({ emitEvent: false }); --NOT working---
`import { Component, Input, Output, EventEmitter, OnChanges } from '@angular/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '@angular/forms';
import { System } from '../system';
import { BillingAndPaymentsService } from './billing-payments.service'
import { PaymentMethod } from './payment-methods'
export abstract class AddPaymentMethodComponent implements OnChanges {
@Input() system: System;
@Input() paymentMethod: PaymentMethod;
@Input() alwaysSave = false;
@Input() isCancelable = false;
@Output() saved = new EventEmitter
@Output() canceled = new EventEmitter();
@Input() isActive = true;
paymentMethodForm: FormGroup;
showError: boolean = false;
isLoading: boolean = false;
constructor(protected fb: FormBuilder, protected billingAndPaymentsService: BillingAndPaymentsService, controlsConfig: { [key: string]: any; }, extra?: { [key: string]: any; }) {
controlsConfig = Object.assign(controlsConfig,
{
useInstallationAddress: [false],
save: [this.alwaysSave],
address: this.fb.group({
street: ['', Validators.required],
city: ['', [Validators.required, Validators.maxLength(40)]],
state: ['', Validators.required],
zip: ['', [Validators.required, Validators.maxLength(20)]]
})
});
this.paymentMethodForm = this.fb.group(controlsConfig);
}
abstract patchPaymentMethodForm(paymentMethod: PaymentMethod): void;
toggleAddressControls() {
// this.paymentMethodForm.get('card-number').enable();
if (this.paymentMethodForm.get('useInstallationAddress').value)
this.paymentMethodForm.get('address').disable();
else
this.paymentMethodForm.get('address').enable();
}
onSubmit(paymentMethod: PaymentMethod) {
if (this.paymentMethod)
Object.assign(paymentMethod, this.paymentMethod);
paymentMethod.isHidden = !this.paymentMethodForm.get('save').value;
if (this.paymentMethodForm.get('useInstallationAddress').value) {
const installationAddress = this.system.installationAddressLine2
? (this.system.installationAddressLine1 + ', ' + this.system.installationAddressLine2)
: this.system.installationAddressLine1; // Create installation address line, check if line 2 is null
paymentMethod.billingStreet = installationAddress;
paymentMethod.billingCity = this.system.installationAddressCity;
paymentMethod.billingState = this.system.installationAddressState;
paymentMethod.billingPostalCode = this.system.installationAddressZipCode;
} else {
paymentMethod.billingStreet = this.paymentMethodForm.value['address']['street'];
paymentMethod.billingCity = this.paymentMethodForm.value['address']['city'];
paymentMethod.billingState = this.paymentMethodForm.value['address']['state'];
paymentMethod.billingPostalCode = this.paymentMethodForm.value['address']['zip'];
}
this.isLoading = true;
this.billingAndPaymentsService.savePaymentMethod(paymentMethod).then(result => {
this.isLoading = false;
return this.saved.emit(result);
}).catch(() => {
this.isLoading = false;
this.showError = true;
});
// this.paymentMethodForm.get('card-number').enable();
}
enablePaymentMethod(){
//this.paymentMethodForm.get('card-number').enable();
}
cancel() {
// console.log('this.paymentMethodForm.getcard-number.enable():', this.paymentMethodForm.get('card-number').enable()); --NOT Working---
// this.paymentMethodForm.get('card-number').enable();
//console.log('this.paymentMethodForm.getcard-number.Afterenable():', this.paymentMethodForm.get('card-number').enable());
this.canceled.emit();
}
ngOnChanges(changes: any): void {
if (changes.paymentMethod) {
this.paymentMethodForm.reset();
this.paymentMethodForm.controls['card-number'].disable({ emitEvent: false });
this.paymentMethodForm.controls['card-name'].disable({ emitEvent: false });
this.enableCreditCardInputs();
this.patchPaymentMethodForm(changes.paymentMethod.currentValue);
if (changes.paymentMethod.currentValue) {
this.paymentMethodForm.patchValue({
useInstallationAddress: false,
save: this.alwaysSave,
});
if (changes.paymentMethod.currentValue.id) {
for (let prop in this.paymentMethodForm.controls) {
if (this.paymentMethodForm.controls.hasOwnProperty(prop) && this.paymentMethodForm.controls[prop] instanceof FormControl) {
if (prop !== 'useInstallationAddress' && prop !== 'save' && !prop.startsWith("address."))
this.paymentMethodForm.controls[prop].disable();
}
}
}
} else {
this.paymentMethodForm.patchValue({
useInstallationAddress: false,
save: this.alwaysSave,
});
}
this.toggleAddressControls();
}
}
}`
HTML part Child Component
@{
Layout = "_AddPaymentLayout.cshtml";
ViewBag.PaymentMethodTypeClass = "add-card-component";
}
</div>
MAIN HTML
<div class="dash-section collapse-section one-time-payment" [ngBusy]="busyOneTimePayment">
<a class="collapse-toggle ngclick" (click)="collapeseOneTimePayment()" [class.collapsed]="collapse.oneTimePayment"> @*"collapse.oneTimePayment = !collapse.oneTimePayment " ;showCancel=false;null*@
<h3 class="section-title">One Time Payment</h3>
</a>
<div class="collapse collapse-body" id="collapseOneTimePayment" [collapse]="collapse.oneTimePayment">
<div class="panel-group step-one" [class.hidden]= "(!isOtherOneTimePaymentSelected &&( oneTimePaymentMethod?.id || show.oneTimePayment.stepTwo || (hasCreditCardMethod && hasBankPaymentMethod)))">
<div class="panel" [class.expanded]="expand.oneTimePayment.card" [class.hidden]="expand.oneTimePayment.bank">
<div class="panel-heading" (click)="expandOneTimePayment('card')">
<h4 class="panel-title">Credit Card</h4>
</div>
<div class="panel-body">
<div class="panel-inner">
<add-card (saved)="createdOneTimePaymentMethod($event)"
[system]="selectedSystem"
[isCancelable]="true"
(canceled)="cancelExpand($event, 'card')"
[paymentMethod]="oneTimePaymentMethod">
</add-card>
</div>
</div>
</div>
Why is this issue closed? Is this fixed in production builds now? Doesn't seem like it...
Running Angular 5.2.3 and was having the same problem. I have a nested FormGroup i.e.
// simplified
this.deviceForm = this.formBuilder.group({
deviceName: '',
advancedOptions: this.formBuilder.group({
bridgeUrl: 'wss://api.my.site:443',
}),
})
// this.deviceForm: FormGroup
// this.deviceForm.controls.advancedOptions: AbstractControl
// ^^ should really be type FormGroup
// this.deviceForm.controls.advancedOptions.controls.bridgeUrl
// ^^ ERROR 'controls' doesn't exist on type 'AbstractControl'
I found a few ways to get around this (thanks to y'all posting here). Assuming we have:
this.deviceForm.controls.advancedOptions.controls.bridgeUrl
We can:
.get()
:this.deviceForm.get('advancedOptions')!.get('bridgeUrl')!
// Note the '!'s to tell TS to assume `get` result is non-null
(<FormGroup> this.deviceForm.controls.advancedOptions).controls.bridgeUrl
// Define AbstractFormGroup
interface AbstractFormGroup extends FormGroup {
controls: {
[key: string]: AbstractControl & FormGroup & AbstractFormGroup,
}
}
export class ... {
deviceForm: AbstractFormGroup
}
// Note: This makes nested form groups (a.controls.b.controls.c... etc.)
// acceptable by the compiler, however this exposes both AbstractControl
// and FormGroup properties on all controls, so you can hit runtime errors
// if you try to use FormGroup properties when your control is just an
// AbstractControl and vice versa.
I ended up going with 1 as I think it's the cleanest
This worked for me:
form.get('passwords').get('confirmPassword').dirty
This worked for me:
form.get('passwords').get('confirmPassword').dirty
This is not allowed by angular-tslint, because functions may fire multiple times
Что работает для меня (даже используя флаг --prod), вместо использования элементов управления в FormArray я использую значение :
*ngFor="let item of myForm.get('items').value"
Спасибо!!! Всё работает!!!
In my case only ng build --prod was failing with -
Property 'controls' does not exist on type 'AbstractControl'
I changed
<div *ngFor="let item of myForm.controls['keyName'].controls;let indx=index;let lst=last;" >
to
HTML:-
<div *ngFor="let item of getControls(myForm, 'keyName');let indx=index;let lst=last;" >
TS File:-
getControls(frmGrp: FormGroup, key: string) {
return (<FormArray>frmGrp.controls[key]).controls;
}
It worked for me!
CLI doesn't complain when ['controls']
property accessor is used.
Below worked for me
```
Please reopen the issue still occurs in Angular 5.2.0
use safe navigation operator ?
change:
myForm.get('myField').controls
to:
myForm.get('myField')?.controls
for validation errors use...
<span *ngIf="f.YOUR_FORM_KEY.controls.YOUR_FORM_KEY.errors?.YOUR_FORM_VALIDATION">YOUR_FORM_KEY is YOUR_FORM_VALIDATION</span>
eg.
<span *ngIf="f.name.controls.name.errors?.required">Name is required</span>
ts file
get f(): any {
return this.userForm.controls;
}
This solution works for me
myForm.get('<formGroupName>').get('<formControlName>').hasError('required')
try this, it works for me
*ngFor="let item of formGroup?.get('timings')?.controls; let i = index;"
<ng-container [formGroup]="providerService.providerFG">
<ng-container formArrayName="contentSites" *ngFor="let site of providerService.providerFG.get('contentSites').value; let i = index">
<ng-container [formGroupName]="i">
<input formControlName="id">
<app-content-site [idSite]="route.snapshot.paramMap.get('id')" [index]="i" *ngIf="isSiteActivated() && route.snapshot.paramMap.get('id') === providerService.providerFG.get(['contentSites', i]).get('id').value"></app-content-site>
</ng-container>
</ng-container>
</ng-container>
@anonymous1983 Using *ngFor="... form.get('foo').value"
instead of *ngFor="... form.get('foo').controls"
does fix the template error, but it introduces reinitialization of the components within the array. This means, within your nested form you can only type one character, then it loses focus, because the nested component is getting recreated (ngOnInit
is getting called for every key stroke).
My form looks like this:
form = this.fb.group({
foo: this.fb.array([{ x: '', y: '' }]),
});
Though i'd go for *ngFor="... form.get('foo')['controls']
to prevent the template error:
<form [formGroup]="form">
<ng-container formArrayName="foo">
<div *ngFor="let item of form.get('foo')['controls']; let i = index">
<app-custom-control-value-accessor [formControlName]="i"></app-custom-control-value-accessor>
</div>
</ng-container>
</form>
Got it!
Looked at the docs - FormArray
The FormArray class contains the
controls
property.
get formData() { return <FormArray>this.passwordForm.get('Data'); }
Thanks @Thisen, without you help it would've taken longer.
I'm using angular 8 at this moment and I've used
get formData() { return this.passwordForm.get('Data') as FormArray; }
La solucion mas facil es: formGroup.controls['any']['controls'].
thank you, gracias, this helped me!
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
Got it!
Looked at the docs - FormArray
The FormArray class contains the
controls
property.get formData() { return <FormArray>this.passwordForm.get('Data'); }
Thanks @Thisen, without you help it would've taken longer.