1.I want to loop through an array
*ngFor="let item of myformNameArray"
Think myformNameArray.length have 3 items
If I console item it will be like
myFormName1
myFormName2
myFormName3
I have already made these form group in my typescript component.
Example
<form [formGroup]="myFormName3">
It will work perfectly!!
But i want to loop :means
<div *ngFor="let item of myformNameArray">
<form [formGroup]="{{item}}">
</form>
</div>
So when I do,
[formGroup]="{{item}}"
It throws me an error can't assign to object or interpolation
Or
[formGroup]="see(item)"
Where ,
see(item) :string {
return String(item);
}
ERROR TypeError: can't assign to property "validator" on "see(item)": not an object
[formGroup] requires a FormGroup Object not string
you need to make array of formgroups instead of string names
TS:
myformArray = [
this.myFormOne,
this.myFormTwo,
this.myFormThree
]
HTML:
<div *ngFor="let item of myformArray">
<form [formGroup]="item">
</form>
</div>
you can also use formArray instead of normal array
TS:
myFormArray = new FormArray([]);
this.myFormArray.push(myFormOne);
this.myFormArray.push(myFormTwo);
this.myFormArray.push(myFormThree);
HTML:
<div *ngFor="let form of myFormArray.controls;">
<form [formGroup]="form">
<input formControlName="controlOne" />
<input formControlName="ControlTwo" />
</form>
</div>
And also you should not use both square brackets and curly brackets (interpolation) for property binding, use either square brackets or interpolation.
internally angular converts square brackets to interpolation
either do this : [formGroup]="item"
or this : formGroup="{{item}}"
not both
Related
Here's my stackblitz
When I click on my button (in Stackblitz link) and push a value to the array, I'd like to have the field be valid, but it's remaining invalid. If I hard code in a value, it shows as valid, but not if I push a value from a click event.
QUESTION - Can anyone help me understand why? Do I need to use some sort of formArray type?
Here is my code.
registerForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.registerForm = this.formBuilder.group({
practicedStyles: [[], [Validators.required]]
});
}
get practicedStyles() {
return this.registerForm.get('practicedStyles');
}
add() {
this.practicedStyles.value.push(1);
}
<div class="card m-3">
<h5 class="card-header">Angular 8 Reactive Form Validation</h5>
<div class="card-body">
<form [formGroup]="registerForm">
<p>Is valid: {{practicedStyles.valid}}</p>
<p>Is required: {{practicedStyles.errors?.required}}</p>
<button class="btn btn-primary" (click)="add()">Add</button>
</form>
</div>
</div>
Did you try using FormGroup.setValue?
add() {
this.registerForm.get('practicedStyles').value.push(1);
this.registerForm.setValue({practicedStyles: this.registerForm.get('practicedStyles').value});
}
I think pushing the value directly to the array wouldn't trigger the change because you're not changing the object's reference. And if you try to reassign the FormGroup control to a new object:
this.practicedStyles.value = 1
you'll get the following errro message Cannot assign to 'value' because it is a read-only property.
When manipulating FormGroup controls you should use the FormGroup provided methods to do so:
FormGroup.setValue
FormGroup.patchValue
So even though you are not changing the object's reference, you are notifying the framework that the object did change.
I will try to be clear in my question. I have a "repeat.for" in my HTML
<div repeat.for="category of categories" class="flex-form-group">
<label class="flex-col-4">
${category.code}
</label>
<div class="flex-col-sm-6">
<dropdownlist style="min-width:200px" model-name="valueCategory" filter="category_id eq ${category.id}"
fields="id,value" display-field="value" id-field="id" value.bind='valueContract[$index}]'>
<data-template>${value}</data-template>
</dropdownlist>
</div>
</div>
My problem is in the "dropdownlist" component. I'm trying to bind the value of this component into an array. I would like to bind the value in the "valueContract" array and to the index of the repeat.for loop but I can't do it.
The error message is as follows :
ERROR [app-router] Error: Parser Error: Missing expected token ] at column 21 in expression [valueContract[$index}]]
I'm trying to bind value to ng-model="" directive because I'm displaying elements with it in loop.
I tried like this
<div class="form-group">
<div data-ng-repeat="(key, n) in langInput.values">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 u-no-padding">
<label class="sell__label" for="auction_name_account_{{n.selected }}">Główna nazwa Twojej aukcji ({{n.selected }}):</label>
<div class="pst-relative">
<input type="text"
id="auction_name_account_{{n.selected }}"
class="form-control"
name="auction_name_account"
data-ng-model="inputs.auction_name_account[key]"
data-ng-minlength="10"
data-ng-maxlength="60"
required />
<span class="sell__input-text sell__input-text--big-input" data-ng-show="sellItem.auction_name_account.$error.required">Wymagane!</span>
<span class="sell__input-text sell__input-text--big-input" data-ng-show="sellItem.auction_name_account.$error.minlength">Za krótkie!</span>
<span class="sell__input-text sell__input-text--big-input" data-ng-show="sellItem.auction_name_account.$error.maxlength">Za długie!</span>
</div>
</div>
</div>
I need to have unique models to firstly create working validation (spans below) and to gather and send data to rest api later on.
This [key] somehow doesn't print as key of object which is number but as normal string as I see in console.
Data of langInput is
$scope.langInput = {
values: [
{
id: 1,
selected: "pl"
},
{
id: 2,
selected: "eng"
}
],
And I would like to have ng-model="inputs.auction_name_account[1]" where 1 is binded value or something similiar. Also above array of objects changes.
auction_name_account is going to be an Object when it's produced.
This means all property accessors must be a string and that properties which aren't a string, will be typecasted into one. This is why, while key is an integer, it will be casted as a string upon usage.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
I have an angular Form and it used *ngFor for repeat an input box. Also, I have to validate dynamically all input boxes that are generated by *ngFor.
There is a JSON array called list that contains Questions. and I have to generate input boxes for answers and they should be validated. Validation information also in the list.
This is an example of the list
[{id:1,
mandatory:false,
questionDescription:"Blue flags are in position and contain words “Stop, Tank Car Connected” or “Stop, Men at Work”",
questionType:1,
validation:{maximum:100,minimum:0}},
{id:2,
mandatory:true,
questionDescription:"Wheels are chocked and handbrake(s) set” or “Stop, Men at Work",
questionType:2,
validation:{maxLength:10,minLength:3}}]
I tried to validate generated input boxes as described in here.
https://scotch.io/tutorials/angular-2-form-validation (see validation forms there).
So I have to give validation information for each input boxes like below.
(this example from given tutorial)
constructor(fb: FormBuilder){
this.complexForm = fb.group({
'firstName' : [null, Validators.required],
'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])]
})
this is the HTML for it.
<div class="form-group">
<label>First Name:</label>
<input class="form-control" type="text"[formControl]="complexForm.controls['firstName']">
</div>
<div class="form-group" >
<label>Last Name</label>
<input class="form-control" type="text" [formControl]="complexForm.controls['lastName']">
</div>
So in my case, all input boxes generate by *ngFor and I have to assign tags like firstName, lastName dynamically to those boxes.
So I used question.id as that tag and implemented control group as followed.
inspectionForm: FormGroup;
constructor(fb: FormBuilder) {
this.questionTemplate = templateService.getQuestionTemplate();
let objString: string = "{";
for (let item of this.questionTemplate.sectionList[0].questionList) {
if (item.questionType == 2) {
objString += '"' + item.id + '":null,';
}
}
objString = objString.slice(0, -1);
objString += '}';
let objJson = JSON.parse(objString);
for (let item of this.questionTemplate.sectionList[0].questionList) {
if (item.questionType == 2) {
objJson[item.id] = [null,Validators.compose([Validators.minLength(item.validation.minLength), Validators.maxLength(item.validation.maxLength)])];
}
}
this.inspectionForm = fb.group(objJson);
}
and here is my HTML code.
<form [formGroup]="inspectionForm" (ngSubmit)="submitForm(inspectionForm.value)">
<div *ngFor="let question of section.questionList" [ngSwitch]="question.questionType">
<ion-row *ngSwitchCase="QuestionType.String">
<ion-col width-80>{{question.questionDescription}}</ion-col>
<ion-col width-20>
<ion-input id="{{question.id}}" type="text" class="inspection-bottom-border" [formControl]="inspectionForm.controls['{{question.id}}']"></ion-input>
</ion-col>
</ion-row>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" [disabled]="!inspectionForm.valid">Submit</button>
</div>
</form>
The Problem is....
If I define [formControl] as [formControl]="inspectionForm.controls['{{question.id}}']"
I get an error like follows,
unhandled Promise rejection: Template parse errors:
Parser Error: Got interpolation ({{}}) where expression was expected at column 25 in [inspectionForm.controls['{{question.id}}']] in InspectionPage#36:91 ("idth-20>
<ion-input id="{{question.id}}" type="text" class="inspection-bottom-border" [ERROR ->][formControl]="inspectionForm.controls['{{question.id}}']"></ion-input>
then I searched for an answer in StackOverflow, I found someone has said don't use [] and {{}} in one time (Dynamic routerLink value from ngFor item giving error "Got interpolation ({{}}) where expression was expected")
But if I removed [] and defined as follows
formControl="inspectionForm.controls['{{question.id}}']"
I get an error as follows
EXCEPTION: Error in ./InspectionPage class InspectionPage - inline template:36:91 caused by: Cannot create property 'validator' on string 'inspectionForm.controls['2']'
(this '2' the is question.id of first type 2 question)
if I define as follows same error occurs
formControl="inspectionForm.controls['2']"
But the problem is if I define as follows with [formControl]
[formControl]="inspectionForm.controls['2']"
The app is Working Perfectly....
But I have to give question.id dynamically. How I can do that?
Are there someone have a solution for this error. Please give a suggestion.
Thank you very much.
just use [formControl]="inspectionForm.controls[question.id]"
Thanks #Sasxa for the answer
So I have some code that looks like this:
<input ng-model="search" type="text">
<td ng-repeat="key in targets">
{{ display_names[key] }}
</td>
To be more clear:
targets is a variable containing not-human readable ids such as key012
display_names is an object which has keys like: key012: "USA"
I would like to filter the display_names value from the search? Looking at the angularjs docs, I know I can filter key, but I haven't figured out how to filter display_names
Example
Here's a full example:
var TS = angular.module('myapp', []);
TS.controller('test', function($scope) {
$scope.targets = ["id_1", "id_2"];
$scope.display_names = {
"id_1": "USA",
"id_2": "Mexico"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myapp" ng-controller="test">
<input ng-model="search" placeholder="Search...">
<ul>
<li ng-repeat="key in targets">{{display_names[key]}}</li>
</ul>
</body>
<td ng-repeat="key in targets">
<span ng-if="display_names[key].indexOf(search) > -1">{{ display_names[key] }}</span>
</td>
use ng-if, or you could also use ng-show. Differences here
This way, as you write in search (which should be in $scope.search) angular will refresh the ng-repeat values to show
If you want to search it case-insensitive, you could use toLowerCase() function before using indexOf
display_names[key].toLowerCase().indexOf(search) > -1
You can't use a filter | in the html because you don't have the value you want to filter against in the array you are iterating over. Instead you can use ng-if to show/hide the elements based on the search. Something like:
<div ng-repeat="key in targets" ng-if="!search || !!display_names[key].match(search)">
{{ display_names[key] }}
</div>
The !! boolean cast is done because otherwise a new Regex object will be returned for the match which triggers a digest cycle which will return another new object and so on.
You also probably want to iterate over <tr> rather than <td>, and you need a <table> element for these elements to be allowed.
Example: http://plnkr.co/edit/qrpLKD9x4IBXowpIgnrf?p=preview
You could also write a custom filter for this, but it is a lot more work:
.filter('displayNames' function () {
return function (key, names, search) {
return !search || !!names[key].match(search);
};
});
And use it like key in targets | displayNames:display_names:search