Angular table filter clearing group - html

I have 2 filters on a user list. A user can select a group containing members and use the search filter to search by last name. When the user backspaces a user to look for another, this resets the groups to all users. I need this to only show the users in the selected group.
TS
updateFilter(event) {
const val = event.target.value.toLowerCase();
const temp = this.temp.filter(function (d) {
return d.lastName.toLowerCase().indexOf(val) !== -1 || !val;
});
this.rows = temp;
if (this.table) {
this.table.offset = 0;
}
}
onGroupSelected($event) {
const groupId = $event.target ? $event.target.value : $event;
if (groupId === 'none') {
this.rows = this.temp;
} else {
const groupUsers = this.groupUserMap.get(groupId);
if (groupUsers) {
this.rows = this.temp.filter((serviceUser) =>
groupUsers.includes(serviceUser.id));
} else {
this.rows = [];
}
}
// #ts-ignore
this.userSelections = this.userSelections ? this.userSelections : {};
this.userSelections.groupId = groupId;
localForage.setItem(this.username, this.userSelections);
}
HTML
<input
type='text'
class="form-control w-200px"
placeholder='Search by Last Name...'
(keyup)='updateFilter($event)'
/>
<select class="form-control w-200px" (change)="onGroupSelected($event)">
<option value="none">All service users</option>
<option *ngFor="let group of groups"
[value]="group.id"
[selected]="userSelections.groupId === group.id">
{{group.name}}
</option>
</select>

You can use ngModel with tow-way binding, to save and manipulate search filters:
<select
class="form-control w-200px"
[(ngModel)]="selectedGroup"
(change)="onGroupSelected()"
>
<option value="none">All service users</option>
<option *ngFor="let group of groups" [value]="group.id">
{{ group.name }}
</option>
</select>
<input
type="text"
class="form-control w-200px"
placeholder="Search by Last Name..."
[(ngModel)]="search"
(keyup)="updateFilter()"
/>
And in order not to lose your users table you can create a copy which will be filtered and displayed.
public initialUsers = [
{ id: 100, groupId: 1, name: 'foo' },
{ id: 101, groupId: 2, name: 'bar' },
{ id: 102, groupId: 1, name: 'john' },
{ id: 103, groupId: 2, name: 'doe' },
{ id: 104, groupId: 2, name: 'baaar' },
{ id: 105, groupId: 1, name: 'fooodoe' },
];
public filteredUsers = [];
ngOnInit(): void {
this.filteredUsers = this.initialUsers;
}
Here is a demo on stackblitz, I used a list to go fast but It's just display. You just have to replace <ul> <li></li> </ul> by your <table> ... </table>

If you would want to take an observable way of doing this, then I would suggest to make a form of your controls, ooooor just use 2 form controls instead. I chose form here as it wraps it up nicely with both form controls (search and dropdown):
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
search: [''],
group: [0] // "all" option as initial id
})
}
Then we would listen to when the form value changes and assign the filtered data to a variable, here named filteredUsers$.
this.filteredUsers$ = this.form.valueChanges.pipe(
startWith(this.form.value), // to trigger initially
// 'this.users' refers to your original users array
map((value: any) => {
// 'all' option is chosen, just filter based on search
if (value.group === 0) return this.users.filter(x => x.lastName.toLowerCase().includes(value.search))
// filter by group and search
return this.users.filter(x => {
return (x.groupId === value.group) && (x.lastName.toLowerCase().includes(value.search.toLowerCase()))
})
})
)
That is it, then we just iterate filteredUsers$ in the template:
<tr *ngFor="let user of filteredUsers$ | async">
Of course we need the form in the view and it would look like this:
<form [formGroup]="form">
<input
type="text"
placeholder="Search by Last Name..."
formControlName="search"
/>
<select formControlName="group">
<option *ngFor="let group of groups" [ngValue]="group.id">
{{ group.name }}
</option>
</select>
</form>
Here is a DEMO with the above code

Related

Angular CLI disable html form if previous option not selected?

I have a form that has a few select fields populated with options.
<form [formGroup]="selectVehicleForm">
<select formControlName="Manufacturer">
<option *ngFor='let cars of cars$'>{{cars.Manufacturer}}</option>
</select>
<select formControlName="Model">
<option *ngFor='let cars of cars$'>{{cars.Model}}</option>
</select>
</form>
My question - how can I disable my "Model" field as long as a user has nothing selected in "Manufacturer"?
You can try like this (not tested) :
constructor(private fb: FormBuilder) {
this.selectVehicleForm = this.fb.group({
Manufacturer: [],
Model: [{ value: '', disabled: true }]
)};
this.selectVehicleForm.get('Manufacturer').valueChanges.subscribe(value => {
if (value) {
this.selectVehicleForm.get('Model').enable();
} else {
this.selectVehicleForm.get('Model').reset('');
this.selectVehicleForm.get('Model').disable();
}
this.selectVehicleForm.updateValueAndValidity();
})
}
You can listen (change) on the FormControl Manufacturer and call enable()/disable() on the FormControl Model
See the Stackblitz
Relevant parts are :
HTML
<select formControlName="Manufacturer" (change)="onChangeManufacturer($event)">
<option *ngFor='let cars of cars$'>{{cars.Manufacturer}}</option>
</select>
Typescript
selectVehicleForm = new FormGroup({
Manufacturer: new FormControl(),
Model: new FormControl(),
});
ngOnInit() {
this.selectVehicleForm.controls['Model'].disable();
}
onChangeManufacturer(value) {
const formControlModel = this.selectVehicleForm.controls['Model'];
if(this.selectVehicleForm.controls['Manufacturer']) {
formControlModel.enable();
} else {
formControlModel.disable();
}
}

Populate select options based on another select with Vue and JSON

Need help creating a dynamic search form with select options for Districts, Regions and locations.
Regions select must be populated based on the District and Locations based on the Regions
The data is stored on a JSON file with the following structure:
[
{
"level": 1,
"code": 1,
"name": "District"
},
{
"level": 2,
"code": 101,
"name": "Region"
},
{
"level": 3,
"code": 10101,
"name": "Location"
}
]
here´s the complete JSON file:
https://gist.github.com/tomahock/a6c07dd255d04499d8336237e35a4827
html snippet
<select name="district" v-model="district">
<option value=''>Select District</option>
<option v-for="district in filterDistricts" :value="district.code">
{{ district.name }}
</option>
</select>
<select name="region" v-model="region">
<option value=''>Select Region</option>
<option v-for="region in filterRegions" :value="region.code">
{{ region.name }}
</option>
</select>
<select name="location" v-model="location">
<option value=''>Select Location</option>
<option v-for="location in filterLocations" :value="location.code">
{{ location.name }}
</option>
</select>
javascript snippet
data() {
return {
searchData: [],
districts: [],
regions: [],
locations: []
}
},
created(){
this.fetchData();
},
computed: {
filterDistricts() {
return this.districts = this.searchData.map(res => ({
level: res.level,
code: res.code,
name: res.name
}))
.filter( res => res.level === 1)
},
filterRegions() {
return this.regions = this.searchData.map(res => ({
level: res.level,
code: res.code,
name: res.name
}))
.filter( res => res.level === 2)
},
filterLocations() {
return this.locations = this.searchData.map(res => ({
level: res.level,
code: res.code,
name: res.name
}))
.filter( res => res.level === 3)
}
},
methods: {
fetchData(){
axios.get('http://localhost:8000/json/searchData.json')
.then((response) => (
this.searchData = response.data
))
.catch((err) => {
console.log(err)
})
}
}
I think I need to associate de code numbers, but I can´t figure out how.
Any ideas?
Thanks
First, I wouldn't bother with those map calls since you're only reproducing the same structure.
Second, I'll assume that each sub-element (region / location) relates to its parent (district / region) via a pattern where each sub's code is prefixed with the parent code, followed by a two-digits, zero-padded.
With that in mind, try this in your computed properties
filterDistricts () {
return this.searchData.filter(({ level }) => level === 1)
},
filterRegions () {
// assuming you don't want any selections until a district is chosen
if (!this.district) return []
const codeCheck = new RegExp(`^${this.district}\\d{2}$`)
return this.searchData.filter(({ level, code }) =>
level === 2 && codeCheck.test(code))
},
filterLocations () {
if (!this.region) return []
const codeCheck = new RegExp(`^${this.region}\\d{2}$`)
return this.searchData.filter(({ level, code }) =>
level === 3 && codeCheck.test(code))
}
Extra notes...
From looking at your template, it seems you should initialise your data as
data () {
return {
searchData: [],
district: null,
region: null,
location: null
}
}
Computed properties don't need to be stored in data properties so you don't need districts, regions and locations.
Your label options should also be disabled so they cannot be selected, eg
<option disabled value="">Select Region</option>

how to get a specific field value from an object retrieved and bind it to a property in the component TypeScript

Hello i have a type script code that populate options from a back end service ,Now how to perform 2 way data binding on or
,And how to get a specific field value from the object retrieved
for Example the Objects i retrieved each one of them is in json format like this :
countryCode:"TUR"
countryId:185
countryName:"Turkey"
countryPhoneCode:"90"
__proto__:Object
my html is like this :------
<div class="form-group ">
<label class="control-label" for="countryCode">Country</label>
<select class="form-control" id="countryCode"formControlName="countryCode">
<option *ngFor="let country of countryList"
[attr.value]="country.countryCode" [selected]="country.countryCode === viewCountryCode">
{{country.countryName}}</option>
</select>
</div>
here is some of my type script:---
registrationForm: FormGroup;
username: AbstractControl;
useremail: AbstractControl;
commercialWebSiteLink: AbstractControl;
corporateWebSiteLink: AbstractControl;
countryCode: String = "jo";
viewCountryCode: string = "jo";
createSignupForm() {
this.registrationForm = this.builder.group({
username: ['', Validators.compose([
Validators.required,
UserNameValidator.userNameRange,
UserNameValidator.OnlyAlphabets
])],
useremail: ['', Validators.compose([
Validators.required,
EmailValidator.mailFormat,
EmailValidator.domainCheckFormat,
EmailValidator.mailLength,
EmailValidator.specialCharacters
])],
countryCode: [''],
commercialWebSiteLink: ['', Validators.compose([
Validators.required,
UrlValidator.urlFormat,
])],
corporateWebSiteLink: ['', Validators.compose([
Validators.required,
UrlValidator.urlFormat,
])],
merchantType: ['PSP']
});
this.username = this.registrationForm.controls['username'];
this.useremail = this.registrationForm.controls['useremail'];
this.commercialWebSiteLink = this.registrationForm.controls['commercialWebSiteLink'];
this.corporateWebSiteLink = this.registrationForm.controls['corporateWebSiteLink'];
this.regestrationErrorMessage = " ";
}
submitsignup(RegistrationForm: any) {
if (!RegistrationForm.errors && RegistrationForm.valid) {
if ((<HTMLInputElement>document.getElementById("termsandConditons")).checked) {
this.isAcceptTerms = false;
} else {
this.isAcceptTerms = true;
}
this.homeService.signUpMarchent(RegistrationForm).subscribe(
response => {
console.log(response);
if (response.success) {
this.signUpDone == true;
} else {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.' + response.code);
if (this.regestrationErrorMessage == '') {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.errGeneralError');
}
}
},
error => {
this.regestrationErrorMessage = this.translate.instant('MerchantRegistration.errGeneralError');
}
);
}
}
Now i want in my type script to retrieve Country Id from the object i retrieved , And I want to save it in a type script variable when i submit the form ,so i can then submit it to the back end instead of country code
Any Help will please ,
this is how i solved it
<div class="form-group ">
<label class="control-label" for="countryId">Country</label>
<select class="form-control" id="countryId" formControlName="countryId">
<option *ngFor="let country of countryList" [attr.value]="country.countryId" [selected]="country.countryCode === viewCountryCode">
{{country.countryName}}</option>
</select>
</div>
I made a new form control named in the type script class ,countryId: 1 in the createSignupForm().

HTML5 datalist only loads first autocomplete suggestion from the filtered array

I am unable to get all the suggested elements shown in the datalist except the first one. I have checked and my array has more than 1 elements. I have no idea why other elements are not being rendered in the suggestions.
Here is my code:
HTML
<input type="text" list="searchUsers" class="form-control with-danger-addon" placeholder="Search for..." [(ngModel)]="query" (keyup)=filter()>
<datalist id="searchUsers" *ngIf="filteredList.length > 0">
<option *ngFor="let item of filteredList" value={{item.FirstName}}></option>
</datalist>
TypeScript
filter() {
if (this.query !== "") {
this.filteredList = this.users.filter(function (el) {
if(el["FirstName"].toLowerCase().search(this.query.toLowerCase()) > -1 ||
el["LastName"].toLowerCase().search(this.query.toLowerCase()) > -1 ||
el["Username"].toLowerCase().search(this.query.toLowerCase()) > -1)
{
return true;
}
}.bind(this));
} else {
this.filteredList = [];
}
return false;
}
select(item) {
this.query = item;
this.filteredList = [];
}
Array Format
this.users = [
{
FirstName: 'Hannah',
LastName: 'Lie',
Username: 'abcd'
},
{
FirstName: 'Hamid',
LastName: 'Kam',
Username: 'efgh'
}
];
Please help.
Using BehaviorSubject here is a sample :
#Component({
selector: 'my-datalist',
template: `
<input type="text" list="searchUsers"
class="form-control with-danger-addon"
placeholder="Search for..."
(blur)="checkValidity()"
[(ngModel)]="query" (keyup)=filter()>
<datalist id="searchUsers" *ngIf="(filteredList | async)">
<option
*ngFor="let item of filteredList | async"
value={{item.FirstName}}></option>
</datalist>
`,
})
export class DataList {
data: string
query:string;
filteredList : Subject = new BehaviorSubject()
// fake data that could be changed coz i use Observable.of in filter to simulate
// async call
users = [
{
FirstName: 'Hannah',
LastName: 'Lie',
Username: 'abcd'
},
{
FirstName: 'Hamid',
LastName: 'Kam',
Username: 'efgh'
}
];
filter() {
if (this.query.length > 2 !== "") {
Observable.of(this.users).map(list => {
return list.filter(el => {
if(el["FirstName"].toLowerCase().search(this.query.toLowerCase()) > -1 ||
el["LastName"].toLowerCase().search(this.query.toLowerCase()) > -1 ||
el["Username"].toLowerCase().search(this.query.toLowerCase()) > -1)
{
return true;
}
})
}).subscribe(item => {
this.filteredList.next(item)
})
return
}
this.filteredList.next([]])
}
checkValidity() {
console.info('checkValidity')
}
}
full code here

Angular 2: Get Values of Multiple Checked Checkboxes

My problem is really simple: I have a list of checkboxes like this:
<div class="form-group">
<label for="options">Options :</label>
<label *ngFor="#option of options" class="form-control">
<input type="checkbox" name="options" value="option" /> {{option}}
</label>
</div>
And I would like to send an array of the selected options, something like:
[option1, option5, option8] if options 1, 5 and 8 are selected. This array is part of a JSON that I would like to send via an HTTP PUT request.
Thanks for your help!
Here's a simple way using ngModel (final Angular 2)
<!-- my.component.html -->
<div class="form-group">
<label for="options">Options:</label>
<div *ngFor="let option of options">
<label>
<input type="checkbox"
name="options"
value="{{option.value}}"
[(ngModel)]="option.checked"/>
{{option.name}}
</label>
</div>
</div>
// my.component.ts
#Component({ moduleId:module.id, templateUrl:'my.component.html'})
export class MyComponent {
options = [
{name:'OptionA', value:'1', checked:true},
{name:'OptionB', value:'2', checked:false},
{name:'OptionC', value:'3', checked:true}
]
get selectedOptions() { // right now: ['1','3']
return this.options
.filter(opt => opt.checked)
.map(opt => opt.value)
}
}
I have find a solution thanks to Gunter! Here is my whole code if it could help anyone:
<div class="form-group">
<label for="options">Options :</label>
<div *ngFor="#option of options; #i = index">
<label>
<input type="checkbox"
name="options"
value="{{option}}"
[checked]="options.indexOf(option) >= 0"
(change)="updateCheckedOptions(option, $event)"/>
{{option}}
</label>
</div>
</div>
Here are the 3 objects I'm using:
options = ['OptionA', 'OptionB', 'OptionC'];
optionsMap = {
OptionA: false,
OptionB: false,
OptionC: false,
};
optionsChecked = [];
And there are 3 useful methods:
1. To initiate optionsMap:
initOptionsMap() {
for (var x = 0; x<this.order.options.length; x++) {
this.optionsMap[this.options[x]] = true;
}
}
2. to update the optionsMap:
updateCheckedOptions(option, event) {
this.optionsMap[option] = event.target.checked;
}
3. to convert optionsMap into optionsChecked and store it in options before sending the POST request:
updateOptions() {
for(var x in this.optionsMap) {
if(this.optionsMap[x]) {
this.optionsChecked.push(x);
}
}
this.options = this.optionsChecked;
this.optionsChecked = [];
}
create a list like :-
this.xyzlist = [
{
id: 1,
value: 'option1'
},
{
id: 2,
value: 'option2'
}
];
Html :-
<div class="checkbox" *ngFor="let list of xyzlist">
<label>
<input formControlName="interestSectors" type="checkbox" value="{{list.id}}" (change)="onCheckboxChange(list,$event)">{{list.value}}</label>
</div>
then in it's component ts :-
onCheckboxChange(option, event) {
if(event.target.checked) {
this.checkedList.push(option.id);
} else {
for(var i=0 ; i < this.xyzlist.length; i++) {
if(this.checkedList[i] == option.id) {
this.checkedList.splice(i,1);
}
}
}
console.log(this.checkedList);
}
<input type="checkbox" name="options" value="option" (change)="updateChecked(option, $event)" />
export class MyComponent {
checked: boolean[] = [];
updateChecked(option, event) {
this.checked[option]=event; // or `event.target.value` not sure what this event looks like
}
}
I have encountered the same problem and now I have an answer I like more (may be you too). I have bounded each checkbox to an array index.
First I defined an Object like this:
SelectionStatusOfMutants: any = {};
Then the checkboxes are like this:
<input *ngFor="let Mutant of Mutants" type="checkbox"
[(ngModel)]="SelectionStatusOfMutants[Mutant.Id]" [value]="Mutant.Id" />
As you know objects in JS are arrays with arbitrary indices. So the result are being fetched so simple:
Count selected ones like this:
let count = 0;
Object.keys(SelectionStatusOfMutants).forEach((item, index) => {
if (SelectionStatusOfMutants[item])
count++;
});
And similar to that fetch selected ones like this:
let selecteds = Object.keys(SelectionStatusOfMutants).filter((item, index) => {
return SelectionStatusOfMutants[item];
});
You see?! Very simple very beautiful. TG.
Here's a solution without map, 'checked' properties and FormControl.
app.component.html:
<div *ngFor="let item of options">
<input type="checkbox"
(change)="onChange($event.target.checked, item)"
[checked]="checked(item)"
>
{{item}}
</div>
app.component.ts:
options = ["1", "2", "3", "4", "5"]
selected = ["1", "2", "5"]
// check if the item are selected
checked(item){
if(this.selected.indexOf(item) != -1){
return true;
}
}
// when checkbox change, add/remove the item from the array
onChange(checked, item){
if(checked){
this.selected.push(item);
} else {
this.selected.splice(this.selected.indexOf(item), 1)
}
}
DEMO
I hope this would help someone who has the same problem.
templet.html
<form [formGroup] = "myForm" (ngSubmit) = "confirmFlights(myForm.value)">
<ng-template ngFor [ngForOf]="flightList" let-flight let-i="index" >
<input type="checkbox" [value]="flight.id" formControlName="flightid"
(change)="flightids[i]=[$event.target.checked,$event.target.getAttribute('value')]" >
</ng-template>
</form>
component.ts
flightids array will have another arrays like this
[ [ true, 'id_1'], [ false, 'id_2'], [ true, 'id_3']...]
here true means user checked it, false means user checked then unchecked it.
The items that user have never checked will not be inserted to the array.
flightids = [];
confirmFlights(value){
//console.log(this.flightids);
let confirmList = [];
this.flightids.forEach(id => {
if(id[0]) // here, true means that user checked the item
confirmList.push(this.flightList.find(x => x.id === id[1]));
});
//console.log(confirmList);
}
In Angular 2+ to 9 using Typescript
Source Link
we can use an object to bind multiple Checkbox
checkboxesDataList = [
{
id: 'C001',
label: 'Photography',
isChecked: true
},
{
id: 'C002',
label: 'Writing',
isChecked: true
},
{
id: 'C003',
label: 'Painting',
isChecked: true
},
{
id: 'C004',
label: 'Knitting',
isChecked: false
},
{
id: 'C004',
label: 'Dancing',
isChecked: false
},
{
id: 'C005',
label: 'Gardening',
isChecked: true
},
{
id: 'C006',
label: 'Drawing',
isChecked: true
},
{
id: 'C007',
label: 'Gyming',
isChecked: false
},
{
id: 'C008',
label: 'Cooking',
isChecked: true
},
{
id: 'C009',
label: 'Scrapbooking',
isChecked: false
},
{
id: 'C010',
label: 'Origami',
isChecked: false
}
]
In HTML Template use
<ul class="checkbox-items">
<li *ngFor="let item of checkboxesDataList">
<input type="checkbox" [(ngModel)]="item.isChecked" (change)="changeSelection()">{{item.label}}
</li>
</ul>
To get selected checkboxes, add the following method in class
// Selected item
fetchSelectedItems() {
this.selectedItemsList = this.checkboxesDataList.filter((value, index) => {
return value.isChecked
});
}
// IDs of selected item
fetchCheckedIDs() {
this.checkedIDs = []
this.checkboxesDataList.forEach((value, index) => {
if (value.isChecked) {
this.checkedIDs.push(value.id);
}
});
}
I have just simplified little bit for those whose are using list of
value Object.
XYZ.Comonent.html
<div class="form-group">
<label for="options">Options :</label>
<div *ngFor="let option of xyzlist">
<label>
<input type="checkbox"
name="options"
value="{{option.Id}}"
(change)="onClicked(option, $event)"/>
{{option.Id}}-- {{option.checked}}
</label>
</div>
<button type="submit">Submit</button>
</div>
** XYZ.Component.ts**.
create a list -- xyzlist.
assign values, I am passing values from Java in this list.
Values are Int-Id, boolean -checked (Can Pass in Component.ts).
Now to get value in Componenet.ts.
xyzlist;//Just created a list
onClicked(option, event) {
console.log("event " + this.xyzlist.length);
console.log("event checked" + event.target.checked);
console.log("event checked" + event.target.value);
for (var i = 0; i < this.xyzlist.length; i++) {
console.log("test --- " + this.xyzlist[i].Id;
if (this.xyzlist[i].Id == event.target.value) {
this.xyzlist[i].checked = event.target.checked;
}
console.log("after update of checkbox" + this.xyzlist[i].checked);
}
I just faced this issue, and decided to make everything work with as less variables as i can, to keep workspace clean. Here is example of my code
<input type="checkbox" (change)="changeModel($event, modelArr, option.value)" [checked]="modelArr.includes(option.value)" />
Method, which called on change is pushing value in model, or removing it.
public changeModel(ev, list, val) {
if (ev.target.checked) {
list.push(val);
} else {
let i = list.indexOf(val);
list.splice(i, 1);
}
}
#ccwasden solution above works for me with a small change, each checkbox must have a unique name otherwise binding wont works
<div class="form-group">
<label for="options">Options:</label>
<div *ngFor="let option of options; let i = index">
<label>
<input type="checkbox"
name="options_{{i}}"
value="{{option.value}}"
[(ngModel)]="option.checked"/>
{{option.name}}
</label>
</div>
</div>
// my.component.ts
#Component({ moduleId:module.id, templateUrl:'my.component.html'})
export class MyComponent {
options = [
{name:'OptionA', value:'1', checked:true},
{name:'OptionB', value:'2', checked:false},
{name:'OptionC', value:'3', checked:true}
]
get selectedOptions() { // right now: ['1','3']
return this.options
.filter(opt => opt.checked)
.map(opt => opt.value)
}
}
and also make sur to import FormsModule in your main module
import { FormsModule } from '#angular/forms';
imports: [
FormsModule
],
Since I spent a long time solving a similar problem, I'm answering to share my experience.
My problem was the same, to know, getting many checkboxes value after a specified event has been triggered.
I tried a lot of solutions but for me the sexiest is using ViewChildren.
import { ViewChildren, QueryList } from '#angular/core';
/** Get handle on cmp tags in the template */
#ViewChildren('cmp') components: QueryList<any>;
ngAfterViewInit(){
// print array of CustomComponent objects
console.log(this.components.toArray());
}
Found here: https://stackoverflow.com/a/40165639/4775727
Potential other solutions for ref, there are a lot of similar topic, none of them purpose this solution...:
Angular 6: How to build a simple multiple checkbox to be checked/unchecked by the user?
Angular 6 How To Get Values From Multiple Checkboxes and Send in From
Angular how to get the multiple checkbox value?
Angular 2: Get Values of Multiple Checked Checkboxes
https://medium.com/#vladguleaev/reusable-angular-create-multiple-checkbox-group-component-84f0e4727677
https://netbasal.com/handling-multiple-checkboxes-in-angular-forms-57eb8e846d21
https://medium.com/#shlomiassaf/the-angular-template-variable-you-are-missing-return-of-the-var-6b573ec9fdc
https://www.bennadel.com/blog/3205-using-form-controls-without-formsmodule-or-ngmodel-in-angular-2-4-1.htm
How to get checkbox value in angular 5 app
Angular 2: Get Values of Multiple Checked Checkboxes
Filter by checkbox in angular 5
How to access multiple checkbox values in Angular 4/5