Angular 6 + Bootstrap 4 Select all and Deselect all Checkboxes - javascript

I'm having an issue trying to get Bootstrap 4 Checkboxes working with a select all and deselect all option in angular 6+. I can get it to work when I use the original code here:
http://www.angulartutorial.net/2017/04/select-all-deselect-all-checkbox.html
But the issue is Bootstrap uses a different event to click their checkboxes. Does anyone have a solution for this?
<div class="form-check">
<input class="form-check-input" type="checkbox" (change)="selectAll()">
<label class="form-check-label">
Select All
</label>
</div>
<div class="form-check" *ngFor="let n of names">
<input class="form-check-input" type="checkbox" value="{{n.name}}" [(ngModel)]="selectedNames" (change)="checkIfAllSelected()">
<label class="form-check-label">
{{n.name}}
</label>
</div>
And the TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-checkbox',
templateUrl: './checkbox.component.html',
styleUrls: ['./checkbox.component.scss']
})
export class CheckboxComponent implements OnInit {
title = 'Checkbox';
names: any;
selectedAll: any;
constructor() {
this.title = "Select all/Deselect all checkbox - Angular 2";
this.names = [
{ name: 'Prashobh', selected: false },
{ name: 'Abraham', selected: false },
{ name: 'Anil', selected: false },
{ name: 'Sam', selected: false },
{ name: 'Natasha', selected: false },
{ name: 'Marry', selected: false },
{ name: 'Zian', selected: false },
{ name: 'karan', selected: false },
]
}
selectAll() {
for (var i = 0; i < this.names.length; i++) {
this.names[i].selected = this.selectedAll;
}
}
checkIfAllSelected() {
this.selectedAll = this.names.every(function(item:any) {
return item.selected == true;
})
}
ngOnInit() {
}
}

this should do it
Here is a plnkr: https://next.plnkr.co/edit/ypGmwE32Xn1bgbqd?preview
HTML:
<div class="form-check">
<input class="form-check-input" type="checkbox" (change)="selectAll()" [checked]="selectedAll">
<label class="form-check-label">
Select All
</label>
</div>
<div class="form-check" *ngFor="let n of names">
<input class="form-check-input" type="checkbox" value="{{n.name}}" [(ngModel)]="n.selected" (change)="checkIfAllSelected()">
<label class="form-check-label">
{{n.name}}
</label>
</div>
TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-checkbox',
templateUrl: './checkbox.component.html',
styleUrls: ['./checkbox.component.scss']
})
export class CheckboxComponent implements OnInit {
title = 'Checkbox';
names: any;
selectedAll: any;
selectedNames: any;
constructor() {
this.title = "Select all/Deselect all checkbox - Angular 2";
this.names = [
{ name: 'Prashobh', selected: false },
{ name: 'Abraham', selected: false },
{ name: 'Anil', selected: false },
{ name: 'Sam', selected: false },
{ name: 'Natasha', selected: false },
{ name: 'Marry', selected: false },
{ name: 'Zian', selected: false },
{ name: 'karan', selected: false },
]
}
selectAll() {
this.selectedAll = !this.selectedAll;
for (var i = 0; i < this.names.length; i++) {
this.names[i].selected = this.selectedAll;
}
}
checkIfAllSelected() {
var totalSelected = 0;
for (var i = 0; i < this.names.length; i++) {
if(this.names[i].selected) totalSelected++;
}
this.selectedAll = totalSelected === this.names.length;
return true;
}
ngOnInit() {
}
}

I am not sure bootstrap has any special logic for event binding in checkbox. I suppose that is missing in your code. for binding see following snippet:
<form [formGroup]="form">
<div class="form-check" formArrayName="unitArr">
<input class="form-check-input" type="checkbox" [checked]="checkAllSelected()"
(click)="selectAll($event.target.checked)" id="select-all">
<label class="form-check-label" for="select-all">
Select All
</label>
</div>
<div class="form-check" *ngFor="let n of names; let i = index;" >
<input class="form-check-input" type="checkbox" value="{{n.name}}" [(ngModel)]="selectedNames" (change)="checkIfAllSelected()" [attr.id]="'check' + i">
<label class="form-check-label" [attr.for]="'check' + i">
{{n.name}}
</label>
</div>
</form>
checkAllSelected() {
return this.form.controls.unitArr.controls.every(x => x.value == true)
}
selectAll(isChecked) {
if isChecked
this.form.controls.unitArr.controls.map(x => x.patchValue(true))
else
this.form.controls.unitArr.controls.map(x => x.patchValue(false))
}
the "id" of input has to be mapped to "label" with "for". Not sure if you have any special requirement, but this is very basic HTML concept. Please give it a try, and see if your problem is solved.
Edit : Please note, I am not familiar with Angular6 concepts, however above code does work with Angular 2. You may check if any of the above points help you anyhow. All the best!

Related

edgesData.forEach is not a function in Angular

import { Component, AfterViewInit, ElementRef, ViewChild } from '#angular/core';
import { Network, DataSet, DataView} from 'vis';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements AfterViewInit {
#ViewChild('network', {static: false}) el: ElementRef;
#ViewChild('nodeFilterSelect', {static:false}) nodeFilter: ElementRef;
#ViewChild('edgesFilter', {static: false}) edgeFilter: ElementRef;
private networkInstance: any;
startNetwork(data){
const container = this.el.nativeElement;
this.networkInstance = new Network(container, data, {});
}
ngAfterViewInit() {
const nodes = new DataSet<any>([
{ id: 1, label: 'Eric Cartman', age: 'kid', gender: 'male' },
{ id: 2, label: 'Stan Marsh', age: 'kid', gender: 'male' },
{ id: 3, label: 'Wendy Testaburger', age: 'kid', gender: 'female' },
{ id: 4, label: 'Mr Mackey', age: 'adult', gender: 'male' },
{ id: 5, label: 'Sharon Marsh', age: 'adult', gender: 'female' }
]);
const edges = new DataSet<any>([
{ from: 1, to: 2, relation: 'friend', arrows: 'to, from', color: { color: 'red'} },
{ from: 1, to: 3, relation: 'friend', arrows: 'to, from', color: { color: 'red'} },
{ from: 2, to: 3, relation: 'friend', arrows: 'to, from', color: { color: 'red'} },
{ from: 5, to: 2, relation: 'parent', arrows: 'to', color: { color: 'green'} },
{ from: 4, to: 1, relation: 'teacher', arrows: 'to', color: { color: 'blue'} },
{ from: 4, to: 2, relation: 'teacher', arrows: 'to', color: { color: 'blue'} },
{ from: 4, to: 3, relation: 'teacher', arrows: 'to', color: { color: 'blue'} },
]);
/**
* filter values are updated in the outer scope.
* in order to apply filters to new values, DataView.refresh() should be called
*/
let nodeFilterValue = ''
const edgesFilterValues = {
friend: true,
teacher: true,
parent: true
}
/*
filter function should return true or false
based on whether item in DataView satisfies a given condition.
*/
const nodesFilter = (node) => {
if (nodeFilterValue === '') {
return true
}
switch(nodeFilterValue) {
case('kid'):
return node.age === 'kid'
case('adult'):
return node.age === 'adult'
case('male'):
return node.gender === 'male'
case('female'):
return node.gender === 'female'
default:
return true
}
}
const edgesFilter = (edge) => {
return edgesFilterValues[edge.relation]
}
const nodesView = new DataView(nodes, {filter: nodesFilter})
const edgesView = new DataView(edges, {filter: nodesFilter})
this.nodeFilter.nativeElement.addEventListener('change', (e) => {
// set new value to filter variable
nodeFilterValue = e.target.value
/*
refresh DataView,
so that its filter function is re-calculated with the new variable
*/
nodesView.refresh()
})
const selectors = this.edgeFilter.nativeElement.querySelectorAll('label')
console.log(selectors)
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
this.startNetwork({ nodes: nodesView, edges: edgesView })
}
}
For codes above I encountered a error saying edgesData.forEach is not a function in Angular. I think this error came from this code snippet:
const selectors = this.edgeFilter.nativeElement.querySelectorAll('label')
console.log(selectors)
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
Actually what I want to do is to add event listener to my three input values. the html like:
<div>
<label>
Filter nodes
<select #nodeFilterSelect>
<option value=''>All characters</option>
<option value='kid'>kids</option>
<option value='adult'>adults</option>
<option value='male'>male</option>
<option value='female'>female</option>
</select>
</label>
<br>
<br>
<label #edgesFilter>
Filter edges
<div>
<label>
<input type='checkbox' value='parent' checked>
Is <span style="color:green">parent</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='teacher' checked>
Is <span style="color:blue">teacher</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='friend' checked>
Is <span style="color:red">friend</span> of
</label>
</div>
</label>
</div>
<div #network>
</div>
what happened here, can any body explain for a little bit? I think I used 'foreach' in a wrong way, I googled a lot, but still confused about how to loop through and add the listeners.
Also I tried to use for loop instead of foreach:
const selectors = this.edgeFilter.nativeElement.querySelectorAll('input')
for(const selector of selectors){
console.log(selector)
selector.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
}
Still got error saying :
ERROR TypeError: selector.forEach is not a function
at TestComponent.ngAfterViewInit (main.js:294)
at callProviderLifecycles (vendor.js:64080)
at callElementProvidersLifecycles (vendor.js:64045)
at callLifecycleHooksChildrenFirst (vendor.js:64027)
at checkAndUpdateView (vendor.js:74910)
at callViewAction (vendor.js:75266)
at execComponentViewsAction (vendor.js:75194)
at checkAndUpdateView (vendor.js:74907)
at callWithDebugContext (vendor.js:76241)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (vendor.js:75823)
I just realize this is a problem of visjs, i need to install #type/vis
You are actually adding the event to label elements, that is not going to work. The change event works on input, select or textarea.
I would say that it doesn't look the Angular way to me, but maybe I am not seeing the whole picture. I would do something like this, it is just the part of the controls and events,
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
filterNodes = '';
selectChange () {
console.log(`filterNodes: ${this.filterNodes}`);
}
chkChange(evt) {
const { value, checked } = evt.target;
console.log(`${value}: ${checked}`);
}
}
<div>
<label>
Filter nodes
<select [(ngModel)]="filterNodes"
(change)="selectChange()">
<option value=''>All characters</option>
<option value='kid'>kids</option>
<option value='adult'>adults</option>
<option value='male'>male</option>
<option value='female'>female</option>
</select>
</label>
<br>
<br>
<label>
Filter edges
<div>
<label>
<input type='checkbox' value='parent' checked
(change)="chkChange($event)">
Is <span style="color:green">parent</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='teacher' checked
(change)="chkChange($event)">
Is <span style="color:blue">teacher</span> of
</label>
</div>
<div>
<label>
<input type='checkbox' value='friend' checked
(change)="chkChange($event)">
Is <span style="color:red">friend</span> of
</label>
</div>
</label>
</div>
this.edgeFilter.nativeElement.querySelectorAll('label')
above given line will return, the type NodeList[], So you can convert NodeList[] into the array by
this.edgeFilter.nativeElement.querySelectorAll('label')
Try this, code snippet
const selectors = [].slice.call(this.edgeFilter.nativeElement.querySelectorAll('label'), 0);
console.log(selectors)
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target
edgesFilterValues[value] = checked
edgesView.refresh()
}))
querySelecterAll returns a NodeList. So instead of for(const selector of selectors){ you can directly iterate on selectors with selectors.forEach. So, that part should be:
const selectors = this.edgeFilter.nativeElement.querySelectorAll('input')
selectors.forEach(filter => filter.addEventListener('change', (e) => {
const { value, checked } = e.target;
edgesFilterValues[value] = checked;
edgesView.refresh();
}))

How to set checked attribute to radio in litelement

I would like to know how to set checked to radio button using litelement.
I have a object and for each object options, radio button is created.
For example, for id=SG two radio buttons are created,
if no checked, set bank as default checked
else set corresponding selected radio value as checked.
I got stuck in litelement.
const obj= [{
id: "SG",
options: ["bank", "credit"]
},
{
id: "TH",
options: ["bank"]
}
];
render(){
${obj.map((e)=>{
return html`
<form>
${obj.options.map((option_value)=>{
return html`
<input class="form-check-input" name="sending-${option_value}" type="radio" id="provider-send-${option_value}" value=${option_value} ?checked=${option_value=="bank"} > // not working
<label class="form-check-label">
${option_value}
</label><br>
`})}
</form>
})`;
}
Expected Output:
Set checked to corresponding radio selected
If no checked, set bank as default checked
This sets the checked attribute to true if the option is bank:
import { LitElement, html } from 'lit-element';
class TestElement extends LitElement {
static get properties() {
return {
countries: {
type: Array,
},
};
}
constructor() {
super();
this.countries = [
{
id: 'SG',
options: ['bank', 'credit'],
},
{
id: 'TH',
options: ['bank'],
},
{
id: 'MY',
options: ['credit'],
}
];
}
render() {
return html`
${this.countries.map(country => html`
<fieldset>
<legend>${country.id}</legend>
<form>
${country.options.map(option => html`
<input
id="provider-send-${option}"
name="sending-${country.id}"
type="radio"
class="form-check-input"
value="${option}"
?checked=${option === 'bank'}
>
<label class="form-check-label">${option}</label>
<br>
`)}
</form>
</fieldset>
`)}
`;
}
}
customElements.define('test-element', TestElement);
Looks like you just missed mapping the actual obj (country in my snippet).
Also, in order to change the selected radio, the name should be the same for all radios in a group. Your code is setting a different name to each radio.

Vue js v-if condicional rendering on a shared toggle button

//PARENT COMPONENT
<template>
....
<div class="input-wrapper">//Toggle button container
<label class="input-label">
SELECT YES OR NOT
</label>
<toggle //child component, toggle button
:options="shipping"
/>
</div>
<div
v-if="destiny[0].value"
class="input-wrapper">
<label class="input-label">
IF YES THIS CONTAINER WILL BE DISPLAYED
</label>
<toggle
:options="Options"
/>
</div>
.....
</template>
<script>
import Toggle from "....";
export default {
components: {
Toggle,
},
data: function () {
return {
destiny: [{
label: 'Yes',
value: true
},
{
label: 'No',
value: false
}
],
Options: [{
label: 'A',
value: 'a'
},
{
label: 'B',
value: 'b'
},
{
label: 'C',
value: 'c'
}]
}
}
}
</script>
///CHILD COMPONENT
<template>
<div class="toggle">
<button
v-for="option in options"
:key="option.value"
:class="{
active: option.value === value
}"
class="btn"
#click="() => toggleHandler(option.value)">{{ option.label }} .
</button>
</div>
</template>
<script>
export default {
props: {
options: {
type: Array,
required: true
}
},
data: function () {
return {
value: this.options[0].value
}
},
methods: {
toggleHandler (value) {
this.$emit('input', value)
this.value = value
}
}
}
</script>
There is toggle with to options YES or NOT, if yes is selected the child component will be rendered otherwise will keep hide.
I'm trying to use a conditional in order to display a child component into a parent component using directives v-if or v-show, but I could not find the way to send the boolean value from the child component to the parent component.
Hope this helps!!
// CHILD
Vue.component('child', {
template: '<div>TOGGLE:- <input type="checkbox" #click="emit"/></div>',
data() {
return {
checked: false
};
},
methods: {
emit: function() {
this.checked = !this.checked;
this.$emit('event_child', this.checked);
}
}
});
// PARENT
var vm = new Vue({
el: '#app',
data: function() {
return {
toggleStatus: false
}
},
methods: {
eventChild: function(checked) {
this.toggleStatus = checked;
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="app">
<child v-on:event_child="eventChild"></child>
<div id="toggle">TOGGLE STATUS => {{toggleStatus}}</div>
</div>

How to delete the selected input values

I am using angular 6 application and i am trying to make a multiple select using input box without any third party plugin, jquery, datalist, select box and it is pure input box, typescript based.
HTML:
<div class="autocomplete">
<input name="suggestion" type="text" placeholder="User" (click)="suggest()" [formControl]="typeahead">
<div class="autocomplete-items" *ngIf="show">
<div *ngFor="let s of suggestions" (click)="selectSuggestion(s)">{{ s }}</div>
</div>
</div>
TS:
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
suggestions: string [] = [];
suggestion: string;
show: boolean;
typeahead: FormControl = new FormControl();
fieldHistory: string [] = [];
suggest() {
this.suggestions = this.users;
this.show = true;
}
selectSuggestion(s) {
this.suggestion = "";
this.fieldHistory.push(s)
for (let i = 0; i < this.fieldHistory.length; i++)
this.suggestion = this.suggestion + " " + this.fieldHistory[i];
this.typeahead.patchValue(this.suggestion);
this.show = false;
}
users = ['First User', 'Second User', 'Third User', 'Fourth User'];
}
Here i need to delete the selected values like the angular material chips, User is able to select multiple values but he also can delete the wrongly selected values.
How can i make a delete option for each individual items to delete the wrongly selected values inside the input box?
Stackblitz link with multi select option https://stackblitz.com/edit/angular-dndhgv
Any edit in the above link to make the multi select with delete option would also be much more appreciable..
Please try this.
component.ts
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
suggestions: string [] = [];
suggestion: string = '';
show: boolean;
typeahead: FormControl = new FormControl();
fieldHistory: string [] = [];
suggest() {
this.suggestions = this.users;
this.show = true;
}
selectSuggestion(s,status) {
this.suggestion = '';
if(status){
this.fieldHistory.push(s);
this.typeahead.patchValue(this.fieldHistory);
}else{
this.fieldHistory.forEach((element,index) => {
if(element == s){
this.fieldHistory.splice(index,1);
}
});
this.typeahead.patchValue(this.fieldHistory);
}
}
users = ['First User', 'Second User', 'Third User', 'Fourth User'];
}
Html
<div class="autocomplete">
<input name="suggestion" type="text" placeholder="User" (click)="suggest()" [formControl]="typeahead">
<div class="autocomplete-items" *ngFor="let s of suggestions">
<input type="checkbox" name='{{s}}' (click)="selectSuggestion(s,$event.target.checked)" />{{s}}
</div>
</div>
I'm not an Angular developer, but i tried to do solution.
Chosen phrases from suggested are storing in "chosen" variable. You can type something and divide it by "," to store it in "chosen" like in angular material chips.
Stackblitz
Maybe you should use a selected field for your users object, as following :
users = [
{
name: 'First User',
selected: false
},
{
name: 'Second User',
selected: false
},
{
name: 'Third User',
selected: false
},
{
name: 'Fourth User',
selected: false
}
]
The new html would be:
<div class="autocomplete">
<div (click)="showChoices()" style="border: solid 1px; display: flex">
<span *ngIf="!selectedUsers.length">Users</span>
<div *ngFor="let user of selectedUsers">
{{user.name}} <a style="cursor: pointer" (click)="unselectUser(user)">x</a>
</div>
</div>
<div class="autocomplete-items" *ngIf="show">
<div *ngFor="let user of users" [ngClass]="user.selected ? 'selected-suggestion' : ''" (click)="selectUser(user)">{{user.name}}</div>
</div>
</div>
And the .ts :
selectedUsers: { name: string, selected: boolean }[] = [];
show: boolean = false;
selectUser(user: { name: string, selected: boolean }) {
if (!user.selected) {
user.selected = true;
}
this.selectedUsers = this.users.filter((u) => u.selected);
console.log(this.selectedUsers)
}
unselectUser(user: { name: string, selected: boolean }) {
if (user.selected) {
user.selected = false;
}
this.selectedUsers = this.users.filter((u) => u.selected);
console.log(this.selectedUsers)
}
showChoices() {
if (this.selectedUsers.length) {
return;
}
this.show = !this.show;
}
Here is the working stackblitz.

Angular 5 - Uncheck all checkboxes function is not affecting view

I'm trying to include a reset button on a Reactive form in Angular 5. For all form fields, the reset is working perfectly except for the multiple checkboxes, which are dynamically created.
Actually the reset apparently happens for the checkboxes as well, but the result is not reflected in the view.
service.component.html
<form [formGroup]="f" (ngSubmit)="submit()">
<input type="hidden" id="$key" formControlName="$key">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" formControlName="name">
</div>
<br/>
<p>Professionals</p>
<div formArrayName="prof">
<div *ngFor="let p of professionals | async; let i = index">
<label class="form-check-label">
<input class="form-check-input" type="checkbox (change)="onChange({name: p.name, id: p.$key}, $event.target.checked)" [checked]="f.controls.prof.value.indexOf(p.name) > -1"/>{{ p.name }}</label>
</div>
<pre>{{ f.value | json }}</pre>
</div>
<br/>
<button class="btn btn-success" type="submit" [disabled]="f?.invalid">Save</button>
<button class="btn btn-secondary" type="button" (click)="resetForm($event.target.checked)">Reset</button>
</form>
service.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormControl, FormGroup, Validators, FormArray } from '#angular/forms'
import { AngularFireAuth } from 'angularfire2/auth';
import { Router, ActivatedRoute } from '#angular/router';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable} from 'angularfire2/database';
import { Service } from './service';
export class ServiceComponent implements OnInit {
f: FormGroup;
userId: string;
$key: string;
value: any;
services: FirebaseListObservable<Service[]>;
service: FirebaseObjectObservable<Service>;
professionals: FirebaseListObservable<Service[]>;
profs: FirebaseListObservable<Service[]>;
constructor(private db: AngularFireDatabase,
private afAuth: AngularFireAuth,
private route: ActivatedRoute,
private router: Router,
private fb: FormBuilder) {
this.afAuth.authState.subscribe(user => {
if(user) this.userId = user.uid
this.services = db.list(`services/${this.userId}`);
})
this.afAuth.authState.subscribe(user => {
if(user) this.userId = user.uid
this.professionals = this.db.list(`professionals/${this.userId}`);
})
}
ngOnInit() {
// build the form
this.f = this.fb.group({
$key: new FormControl(null),
name: this.fb.control('', Validators.required),
prof: this.fb.array([], Validators.required)
})
}
onChange(name:string, isChecked: boolean) {
const profArr = <FormArray>this.f.controls.prof;
if(isChecked) {
profArr.push(new FormControl(name));
console.log(profArr.value);
} else {
let index = profArr.controls.findIndex(x => x.value == name)
profArr.removeAt(index);
console.log(profArr.value);
}
}
resetForm(){
let profArr = <FormArray>this.f.controls.prof;
this.f.controls.name.setValue('');
profArr.controls.map(x => x.patchValue(false));
this.f.controls.$key.setValue(null);
}
}
service.ts
export class Service {
$key: string;
name: string;
professionals: string[];
}
The result of the code above, displayed by line <pre> {{f.value | json}} </ pre> is:
When I fill out the form:
{
"$key": null,
"name": "Test service",
"prof": [
{
"name": "Ana Marques",
"id": "-LEZwqy3cI3ZoYykonWX"
},
{
"name": "Pedro Campos",
"id": "-LEZz8ksgp_kItb1u7RE"
}
]
}
When I click on Reset button:
{
"$key": null,
"name": "",
"prof": [
false,
false
]
}
But checkboxes are still selected:
What is missing?
I would stop using FormControls to handle what is basically state.
You have some code which loads the professionals property of the component. Just add to that data a checked property and change the type of professionals to Service[]:
this.db.list(`professionals/${this.userId}`)
.subscribe(professionals => {
professionals.forEach(p => p.checked = false);
this.professionals = professional;
});
Btw, you don't have a checked property on your Service type, so either you extend it or transform professionals in something else (i.e. a CheckableService).
The template becomes:
<div *ngFor="let p of professionals; let i = index">
<label class="form-check-label">
<input class="form-check-input" type="checkbox (change)="onChange(p, $event.target.checked)" [checked]="p.checked"/>{{ p.name }}</label>
</div>
And the onChange method becomes:
onChange(professional: Service, isChecked: boolean) {
professional.checked = isChecked;
this.profArr = this.professionals.filter(p => p.checked);
}
It seems a lot cleaner to me (you will need to adjust for the checked parameter not being in the Service type, but the code is simply adaptable). No messing with controls, only data cleanly flowing through your component.
You are not referencing your checkboxes. Give them a name using the index.
<div formArrayName="prof">
<div *ngFor="let p of professionals | async; let i = index">
<label class="form-check-label">
<input [formControlName]="i" class="form-check-input" type="checkbox (change)="onChange({name: p.name, id: p.$key}, $event.target.checked)" [checked]="f.controls.prof.value.indexOf(p.name) > -1"/>{{ p.name }}</label>
</div>
<pre>{{ f.value | json }}</pre>
</div>
This is my checkall checkbox
<input type="checkbox" value="a" (click)="checkAll" [checked]="checkAll">
This i a regular checkbox, i used this whithin an ngfor
<input type="checkbox" value="a" (click)="check(object)" name="checkbox" [checked]="true">
And the checkall checkboxes function
let elements = document.getElementsByTagName('input');
if (this.checkAll) {
this.checkAll = false;
for (let i = 0; i < elements.length; i++) {
if (elements[i].type == 'checkbox') {
elements[i].checked = false;
}
}
}
else....the other way

Categories

Resources