Angular 9 cannot check or uncheck checkbox - html

I have a table that is populated from an array coming from an API. The next thing I want to do is to add some checkboxes in a tab next to the table to filter data in the table. I'm adding the checkboxes dynamically because until the array comes from the API I don't know the filters (I know the category of the filters. ie Country or Language, but I don't know which countries or which languages will come in the array).
So, the problem is that I am trying to have a formArray to contain the checkboxes and I add to them programmatically as soon as I know what the values for the filters will be. But, when I try to click (just with my mouse) on the generated checkboxes I cannot. It doesn't check or uncheck.
However, if I just add the checkboxes without the formArray I can check and uncheck to my hearts content.
Here is my html for when I cannot check or uncheck (initially all of them are checked)
<form [formGroup]="languageForm">
<div *ngIf='results && results.length'>
<div class=" custom-control custom-checkbox mb-3" *ngFor="let item of languageForm.controls.filters.controls; let i = index" formArrayName="filters">
<input class=" custom-control-input" [formControlName]="i" id="i" type="checkbox" />
<label class=" custom-control-label" [for]="i">
{{ f_languages[i].label }}
</label>
</div>
</div>
</form>
Here is the html (for the one that does work)
<div *ngIf='results && results.length'>
<div class=" custom-control custom-checkbox mb-3" *ngFor="let item of f_countries; let i = index">
<input class=" custom-control-input" id="{{ item.value }}" type="checkbox" />
<label class=" custom-control-label" for="{{ item.value }}">
{{ item.value }}
</label>
</div>
</div>
Here is the TS for both (for the sake of the example I will make the filters static)
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
f_countries = [
{label: 'United States', value: 'US' },
{label: 'United Kingdom', value: 'UK' },
{label: 'Germany', value: 'DE' },
{label: 'Philippines', value: 'PH' }
];
f_languages = [
{label: 'English', value: 'EN' },
{label: 'German', value: 'DE' },
{label: 'French', value: 'FR' },
{label: 'Spanish', value: 'ES' }
];
//constructor omitted but nothing interesting there
ngOnInit() {
// search form init and other things
this.languagesForm = this.formBuilder.group({
filters: new FormArray([])
});
}
doSearch(): void {
this.searchService.search(this.searchForm.get('country').value, this.searchForm.get('language').value)
.subscribe(results => {
this.results = results;
this.slicedResults = this.results.slice(0, this.pageSize);
//load the filters
this.initializeFilters();
});
}
initializeFilters(): void {
//normally here the mapping from results to the filters
//but omitted since I said that for the example the filters are static
this.f_languages.forEach((o, i) => {
const control = new FormControl(true);
(this.languagesForm.controls.filters as FormArray).push(control);
});
}
Thanks in advance for all the help, I'm sure it's something stupid that I just cannot see anymore after staring at it for so many hours.
EDIT -- I don't know exactly why this worked but it did. See below my final html which is now mysteriously clickable
<form [formGroup]="languagesForm">
<div *ngIf='results && results.length'>
<div class=" custom-control custom-checkbox mb-3" *ngFor="let item of languagesForm.controls.filters.controls; let i = index" formArrayName="filters">
<input checked="checked" class=" custom-control-input" id="{{ i }}" [formControlName]="i" [value]="f_languages[i].value" type="checkbox" />
<label class=" custom-control-label" [for]="i">
{{ f_languages[i].label }}
</label>
</div>
</div>
</form>
Apparently if it doesn't have id in the input and for in the label the thing is not un/checkable. Maybe someone will be able to explain why...

Related

Unable to select a value from angular dropdown list for a default

In order to provide a country list for users to select when they fill in address info. I designed an address ngForm to collect the address. Besides, the form also works for users to editing their address info, that means if address exists, all the existing values will be patched first. That means that the existing address elements, such as country name, will need to be in the top of the country list or simply picked up one from the country list as default... that is the user's county will shows up whenever the users open their address info. They should also be able to change to another country by picking one from the list.
With below html and ts code, I could hardly make it for user's existing country displaying as default.
<form #addressForm="ngForm" (ngSubmit)="onSubmit(addressForm.value)">
<div class="d-flex justify-content-end mb-1">
<button [disabled]="!addressForm.valid || !addressForm.dirty" type="submit" class="btn btn-sm btn-primary">
<span style="font-size: 0.8em">Save Address</span>
</button>
</div>
......
<div class="form-row">
<div class="form-group col-md-4">
<label for="state">State/Province/Region:</label>
<select
id="state" class="form-control" name="State" [(ngModel)]="state">
<option *ngFor="let state of states let i = index"
[selected]="i === 0"
[ngValue]="state">{{state}}
</option>
</select>
</div>
<div class="form-group col-md-4">
<label for="country">Country:</label>
<select
id="country" class="form-control" name="Country" [(ngModel)]="country"
(change)="onCountrySelected($event.target.value)">
<option *ngFor="let country of countries let i = index"
[selected]="i === 0"
[ngValue]="country">{{country}}
</option>
</select>
</div>
<div class="form-group col-md-4">
<label for="zipcode">Zip Code:</label>
<input
......
</div>
</div>
</form>
component.ts
getCountries() {
this.accountService.getUserAddress().subscribe((resp: IAddress) => {
this.address = resp;
if (this.address.country !== null)
{
this.memberService.getCountries().subscribe((resp: ICountry[]) => {
for (let country of resp)
{
this.countries.push(country.name);
}
this.countries = [this.address.country, ...this.countries];
this.states = [this.address.state, ...this.states];
});
} else {
this.memberService.getCountries().subscribe((resp: ICountry[]) => {
for (let country of resp)
{
this.countries.push(country.name);
}
this.countries = ['', ...this.countries];
}, error => {
console.log(error);
});
}
});
}
onCountrySelected(countryIdx: any) {
this.countryId = parseInt(countryIdx);
this.memberService.getStates(this.countryId).subscribe((resp: any[]) => {
this.states = [];
for (let state of resp)
{
this.states.push(state.name);
}
});
}
onSubmit(addressFormValues) {
console.log(addressFormValues);
this.accountService.updateUserAddress(addressFormValues).subscribe((address: IAddress) => {
this.toastr.success('Address saved');
}, error => {
this.toastr.error(error.message);
console.log(error);
});
}
Alternatively, I also tried assigning country's index got from the countries list so as to directly pick the country as selected at the beginning. That seemed not working as well.
<!-- begin snippet: js hide: false console: true babel: false -->
correspondingly change the selected in html as:
<option *ngFor="let country of countries let i = index"
[selected]="i === countryIndex"
[ngValue]="country">{{country}}
</option>
I also tried [selected]="address.country === country", I could still failed to get user's existing country value as default selected.
Apart from this issue, all the collected address data can be successfully submitted to back-end.
I think there is a typo in
<option *ngFor="let county of countries let i = index"
[selected]="i === countryIndex"
[ngValue]="country">{{country}}
</option>
you should use county instead of country.

Display all the data in a checkbox that are coming from the api in vuejs

I am facing an issue where i want to display the data of an array from api in checkbox. I have list of checkbox calling from another api and i want to show the selected values with checked in that list of checkbox but i cannot
Here is the sample of code:
<ul class="checkboxes">
<li v-for="(role, i) in roles" :key="i">
<input
:id="'checkbox' + i"
type="checkbox"
v-model="selected"
:value="role"
/>
{{ role.name }}
</li>
</ul>
All though all the checkbox are displaying but it is not displaying the ones with checked that are coming from backend.
For example: i have 10 values inside roles. but not showing checked in the page.
Roles looks like this:
roles:['x:list', 'y:list']
please help
I built a sample component showing how to bind an array of roles to checkboxes:
<template>
<div class="bind-multiple-checkboxes">
<h3>Select Roles</h3>
<div class="row">
<div class="col-md-6">
<div class="form-check" v-for="(role, index) in roles" :key="index">
<input class="form-check-input" type="checkbox" :id="'checkbox' + index" v-model="role.selected">
<label class="form-check-label" :for="'checkbox' + index">
{{ role.name }}
</label>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
roles: [
{
name: 'role1',
selected: true
},
{
name: 'role2',
selected: false
},
{
name: 'role3',
selected: false
},
{
name: 'role4',
selected: true
},
]
}
}
}
</script>
it is important that you have an empty array to bind the selected values in two ways. note that role.name does not exist, since role is a string in your array:
new Vue({
el: '#app',
data: {
roles: ['x:list', 'y:list', 'z:list'],
selected: ['z:list'] // fill if you want a checkbox prefilled
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id='app'>
<ul class="checkboxes">
<li v-for="role in roles" :key="role.id">
<label>
<input
type="checkbox"
:value="role"
v-model="selected"
/>
{{ role }}</label>
</li>
</ul>
<p>{{ selected }}</p>
</div>
you can read more about input bindings here

Add multiple checkboxes based on input length in Angular

Currently, I have a single checkbox in my Angular application which I plot using the HTML code:
<input type="checkbox" id="box1" value="Apple">
<label for="box1"> Apple</label>
However, I now need to tweak the functionality such that the number of checkboxes is dependant on the array input. Also, the contents of the arrays should be the labels for the checkboxes.
For ex:
If my array is arr = ['Apple', 'Mango','Banana'], I should get 3 checkboxes (as the length of arr is 3) like this:
How can I do this?
use *ngFor for acheiving this
app.component.html
<div *ngFor="let item of arr;">
<input type="checkbox" id="{{item}}" [value]="item " (change)="getItem($event)">
<label for="{{item}}"> {{item }}</label>
</div>
app.component.ts
arr = ['Apple', 'Mango','Banana'];
getItem(item) {
//check if the checkbox selected or not
if(item.target.checked) {
let value = item.target.value;
console.log(value);
//Do your thing here
}
}
Hope this help's :)
There is multiple way to achieve this.
HTML
<div *ngFor="let item of array; let i = index">
<input type="checkbox" [checked]="item.status" (click)="checked(i)">
<label> {{item.name}}</label>
</div>
<div *ngFor="let item of arr;">
<input type="checkbox" id="{{item}}" [value]="item ">
<label for="{{item}}"> {{item }}</label>
</div>
Class
array = [
{ name: "Apple", status: true },
{ name: "Mango", status: true },
{ name: "Banana", status: true }
];
checked(i) {
this.array[i].status = !this.array[i].status;
}
arr = ["Apple", "Mango", "Banana"];
You can also find working link: stackblitz

Angular 9 - different formGroupName with same name of formControlName affects same formControlName

I created form: FormGroup variable where I defined group with a FormArray localizationData: FormArray like this in constructor of my service:
this.form = this.formBuilder.group({
localizationData: this.formBuilder.array([])
});
Then I pushing to that FormArray a FormGroup with specific FormControl with this function:
addLocalizedFormGroup(locale?: any){
locale = (locale == undefined) ? this.selectedLocale : locale;
let formArray = <FormArray>this.form.get('localizationData');
formArray.push(this.formBuilder.group({
locale: [locale.code],
codelistName: ['', Validators.required]
}));
locale.created = true;
this.createdLocales.push(locale);
}
In ngOnInit of component I called that function twice. Example of locale object variable:
{ "code": "SK", "name": "Slovenčina" }
To show to user specific format of that locale I using this function:
localeFormatter = (x: any) => x.code + " | " + x.name;
I implemented simple options list with localizations for user to select one:
<div class="form-group col-3">
<label>Lokalizácia
<select class="form-control" [(ngModel)]="this.defservice.selectedLocale">
<option *ngFor="let locale of this.defservice.createdLocales" [ngValue]="locale">{{this.defservice.localeFormatter(locale)}}</option>
</select>
</label>
</div>
That options list works fine. When I select different language, model change as a object. To find a FormGroup by locale I create very simple function for that:
localizationIndexOf(locale: any): number{
return (<FormArray>this.form.get('localizationData')).controls.findIndex(x => x.get('locale').value == locale.code);
}
And now, the problem what I am challenging is to show user value of FormControl, codelistName, as you can see defined in function addLocalizedFormGroup. Here is html:
<ng-container [formGroup]="defservice.form">
<ng-container formArrayName="localizationData">
<ng-container [formGroupName]="defservice.localizationIndexOf(defservice.selectedLocale)">
<div class="row">
<div class="form-group col-2">
<label>Lokalizácia
<input type="text" class="form-control" [value]="defservice.localeFormatter(defservice.selectedLocale)"
disabled="true">
</label>
</div>
<div class="form-group col-10">
<label>Názov <span style="color: red">*</span>
<input type="text" class="form-control" formControlName="codelistName">
</label>
</div>
</div>
</ng-container>
</ng-container>
</ng-container>
But after switch language in option list, localization value change correctly, localizationIndexOf(defservice.selectedLocale) return correct index but after edit codelistName of any index of FormmArray created with function addLocalizedFormGroup, what I added, only first one (with index 0) is changing. I print whole value of form and it show only changed value of first language. Event if I have 2 or 10 languages. I mean 2 or 10 pushed FormGroups into localizationData FormArray of form: FormGroup. It seems like on first load of component, formGroup never update his value, I ref to this line:
<ng-container [formGroupName]="defservice.localizationIndexOf(defservice.selectedLocale)">
Thank you for any advice.
I recreated the problem on my side but was unable to find a solution with *ControlName='' syntax. I found one with [formControl]='' but you will have to forget the formGroupName hierachy.
If you can keep a reference of the index of the current FormGroup of the localizationData: FormArray, you will be able to get the control from the array:
<input class="..." type="text" [formControl]="localizationData.at(currentLocaleIndex).get('codelistName')">
localizationData is a getter for the FormArray:
get localizationData(): FormArray {
return this.form.get('localizationData') as FormArray
}
And a solution to keep currentLocaleIndex up to date is to update the value when a change happens on the <select> like this:
<select (change)="updateCurrentLocaleIndex()" class="form-control" [(ngModel)]="this.defservice.selectedLocale">
<option *ngFor="let locale of this.defservice.createdLocales" [ngValue]="locale">{{this.defservice.localeFormatter(locale)}}</option>
</select>
In your component class :
updateCurrentLocaleIndex() {
this.currentLocaleIndex = this.localizationIndexOf(this.defservice.selectedLocale)
}

how to make radio buttons selected in angularjs

i am new to angularjs and javascript,I am having a list of radio buttons and have to make some of them selected,so can anybuddy please tell me how to achieve this?I tried ng-value=true with no luck,my code is as below:
<ons-list-item modifier="tappable" ng-repeat="area in vm.AreaList" >
<label class="radio-button radio-button--list-item line-h45">
<input type="radio" ng-bind="area.name" ng-model="vm.selectedArea" name="area" ng-value="area.code" >
<div class="radio-button__checkmark radio-button--list-item__checkmark">
</div>
{{area.name}}
</label>
</ons-list-item>
you can do something like this in your controller:
$scope.results = {
favorites: [{
id: "WatchList1",
title: "WatchList1"
}, {
id: "WatchList2",
title: "WatchList2"
}, {
id: "WatchList3",
title: "WatchList3"
}]
};
$scope.selectedRow = {
id: 'WatchList2'
};
$scope.event = {
type: {
checked: true
}
}
and your html:
<div>
<div ng-repeat="row in results.favorites">
<input type="radio" ng-model="selectedRow.id" value="{{ row.id }}" style="opacity: 1;" class="pointer" />
<span>{{ row.title }}</span>
</div>
</div>
Single box
You should use ngChecked for that.
https://docs.angularjs.org/api/ng/directive/ngChecked
<ons-list-item modifier="tappable" ng-repeat="area in vm.AreaList" >
<label class="radio-button radio-button--list-item line-h45">
<input type="radio" ng-bind="area.name" ng-model="vm.selectedArea" name="area" ng-value="area.code"
ng-checked="true">
<div class="radio-button__checkmark radio-button--list-item__checkmark">
</div>
{{area.name}}
</label>
</ons-list-item>
Only one radio button can be selected at a time.
If you want multiple selected items, then use checkbox and to select, make model value equal to value attribute.