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();
}))
Related
I'm trying to create a question adder for my quiz. Each question has answers, containing IDs:
var questions = [
{
question: "1+1 is",
answers: [
{ id: 0, answer: "1", correct: false },
{ id: 1, answer: "0", correct: false },
{ id: 2, answer: "2", correct: false }
],
correct: [2],
selected: [],
false: [0, 1]
}]
but I don't know how to create an array of objects with IDs. I know that answercorrect, answerfalse1/2 are wrong, but what do I do instead?
Some HTML:
<label>Otázka: <input v-model="question" type="text"></label><br><br>
<label>Správná odpověď: <input v-model="answercorrect" type="text"></label><br><br>
<label>Odpověď: <input v-model="answerfalse" type="text"></label><br><br>
<label>Odpověď: <input v-model="answerfalse2" type="text"></label>
JS:
addQuestion()
{
if (this.question != "")
{
this.questions.push(this.question);
this.question = "";
this.questions.push(this.answers[this.answercorrect, this.answerfalse, this.answerfalse2]);
this.answercorrect = "";
this.answerfalse = "";
this.answerfalse2 = "";
}
}
I would create a function that generates a blank question object, containing an array of generated answer objects.
let answerId = 0;
let questionId = 0;
const createAnswer = () => ({ id: answerId++, answer: '', correct: false })
const createQuestion = () => ({
id: questionId++,
question: '',
answers: [createAnswer()],
})
A component would use those functions to add new questions and answers:
export default {
data() {
return {
questions: [createQuestion()],
};
},
methods: {
addQuestion() {
this.questions.push(createQuestion())
},
addAnswer(q) {
/**
* Since the `answers` object is part of the `questions` object,
* this takes a question as an argument, and adds a new `answer`
* object to its `answers` array.
*/
q.answers.push(createAnswer())
},
},
}
In the template, use v-for to render the questions, and use v-on button-click handlers that bind to the component's addQuestion() and addAnswer():
<template>
<div>
<button #click="addQuestion">Add question</button>
<fieldset class="question" v-for="q in questions" :key="q.id">
<legend>Question: <input v-model="q.question" type="text" /></legend>
<button #click="addAnswer(q)">Add answer</button>
<label class="answer" v-for="answer in q.answers" :key="answer.id">
Answer: <input type="text" v-model="answer.answer" />
Correct: <input type="checkbox" v-model="answer.correct" />
</label>
</fieldset>
</div>
</template>
demo
So I have a little situation that I am stuck with. I have an array of holidays that looks like so:
export const holidays = {
federal: [
{ name: "New Year's Day", selected: false },
{ name: 'Martin Luther King, Jr. Day', selected: false },
{ name: "George Washington's Birthday", selected: false },
{ name: 'Memorial Day', selected: false },
{ name: 'Independence Day', selected: false },
{ name: 'Labor Day', selected: false },
{ name: 'Columbus Day', selected: false },
{ name: 'Veterans Day', selected: false },
{ name: 'Thanksgiving Day', selected: false },
{ name: 'Christmas Day', selected: false }
],
other: [
{ name: 'Black Friday', selected: false },
{ name: 'Christmas Eve', selected: false },
{ name: "New Year's Eve", selected: false }
]
};
My goal is to render 2 lists of holidays - one with a Federal Holidays label, and the other with a Other Holidays label. I need to be able to select all the checkboxes with an Add all options, and I also need to be able to select the check boxes individually.
Right now, only my Add all functionality is working. Here is my code:
// CheckboxList component
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import camelCase from 'lodash';
import Checkbox from 'common/components/Checkbox';
class CheckList extends Component {
static propTypes = {
data: PropTypes.array,
id: PropTypes.string.isRequired
};
...
get checkboxList() {
const { data } = this.props;
const { checked } = this.state;
return data.map(item => (
<Checkbox
id={camelCase(item)}
key={camelCase(item)}
checked={checked}
label={item}
/>
));
}
handleSelectAllCheckboxToggle() {
this.setState(({ checked }) => ({ checked: !checked }));
}
render() {
const { id } = this.props;
return (
<div className={this.baseClass}>
<Checkbox
id={id}
label="Add all"
onChange={this.handleSelectAllCheckboxToggle}
/>
{this.checkboxList}
</div>
);
}
}
The above is a reusable component that basically renders checkboxes with labels depending on how many items are inside the data prop (array) that is passed into the component. This reusable component is then passed into a parent component which is going to render the checkbox list:
// HolidaySchedule component
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import camelCase from 'lodash/camelCase';
import { holidays } from 'modules/utilities/constants';
import CheckboxList from './CheckboxList';
import Panel from 'common/components/Panel';
class HolidaySchedule extends Component {
get holidaysList() {
return Object.keys(holidays).map(holiday => (
<CheckboxList
key={camelCase(holiday)}
data={this.holidaysData(holiday)}
id={`${holiday}Holidays`}
/>
));
}
holidaysData(type) {
return holidays[type].map(holiday => holiday.name);
}
render() {
return (
<Panel>
{this.holidaysList}
</Panel>
);
}
}
This all ends up rendering a list of checkboxes with the holidays as their labels:
Sorry for the kinda long and in-depth post, I just wanted to make sure I didn't leave anything out. The functionality when clicking Add all for each group of checkboxes (Federal or Other) works fine.
However, I do not know what to do in order to also add functionality where I can select the checkboxes individually. I have only gotten as far as being able to select only one checkbox at a time, and it deselects the previous one selected. I would like to be able to Add all to select all checkboxes, click one of the checkboxes to uncheck it and deselect the Add all checkbox, and also just select one checkbox at a time. Stumped!
If anyone took the time to go through all this, thank thank you already!! If anyone has any advice or direction, then thank you a million times more!!!!
Give a man a fish, and you feed him for a day. Teach a man to fish, and you feed him for a lifetime
Are you looking for something like this ? I suppose this is the logic that you are looking for.
I've wrote a checkbox list demo with select all function for you. Its just logic, nothing looking fancy.
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
const [holidays, setHolidays] = React.useState({
federal: [
{ name: "New Year's Day", selected: false },
{ name: "Martin Luther King, Jr. Day", selected: false },
{ name: "George Washington's Birthday", selected: false },
{ name: "Memorial Day", selected: false },
{ name: "Independence Day", selected: false },
{ name: "Labor Day", selected: false },
{ name: "Columbus Day", selected: false },
{ name: "Veterans Day", selected: false },
{ name: "Thanksgiving Day", selected: false },
{ name: "Christmas Day", selected: false }
],
other: [
{ name: "Black Friday", selected: false },
{ name: "Christmas Eve", selected: false },
{ name: "New Year's Eve", selected: false }
]
});
const handleOnChange = (e, type) => {
const { name, checked } = e.target;
const newHoliday = [...holidays[type]];
const index = newHoliday.findIndex(h => h.name === name);
if (index > -1) {
newHoliday[index] = { name, selected: checked };
}
setHolidays(h => ({ ...h, [type]: newHoliday }));
};
const handleOnSelectAll = (e, type) => {
const { checked } = e.target;
let newHoliday = [...holidays[type]];
if (!checked) {
newHoliday = newHoliday.map(opt => ({ ...opt, selected: false }));
} else {
newHoliday = newHoliday.map(opt => ({ ...opt, selected: true }));
}
setHolidays(h => ({ ...h, [type]: newHoliday }));
};
const renderCheckboxList = (options, type) =>
options.map(opt => (
<div>
<label>
<input
type="checkbox"
name={opt.name}
onChange={e => handleOnChange(e, type)}
checked={opt.selected}
/>
{opt.name}
</label>
</div>
));
const renderSelectAllCheckbox = type => (
<div>
<label>
<input
type="checkbox"
onChange={e => handleOnSelectAll(e, type)}
checked={holidays[type].every(opt => opt.selected)}
/>
{`Select All ${type}`}
</label>
</div>
);
return (
<section style={{ display: "flex", justifyContent: "space-around" }}>
<div>
<div>
<fieldset>
Federal Holidays
{renderSelectAllCheckbox("federal")}
{renderCheckboxList(holidays.federal, "federal")}
</fieldset>
</div>
<div>
<fieldset>
Other Holidays
{renderSelectAllCheckbox("other")}
{renderCheckboxList(holidays.other, "other")}
</fieldset>
</div>
</div>
<div>
State:
<pre>{JSON.stringify(holidays, null, 2)}</pre>
</div>
</section>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Some tips for you, if you want the final value to be in array form, you can use filter and map to get the name of the option.
Here is a working example: https://codesandbox.io/s/react-controlled-checkbox-list-f4t7g?fontsize=14&hidenavigation=1&theme=dark
Update (11/14/2019)
I've recreated another sandbox demo using React class. This time, I've created a component similar to yours (CheckboxList) that has name and onChange callback. Using these props allow you to update your parent holidays state.
You can find the working example here: https://codesandbox.io/s/react-class-controlled-checkbox-list-ejlfn?fontsize=14&hidenavigation=1&theme=dark
I think what you are missing is the onChange callback to update your parent state everytime there are changes made to the checkboxes. Your code are missing some important stuffs.
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.
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!
I'm using React and the CSSTransitionGroup component to switch between two sets of members in my app's state. Its state contains the members, each of which has a flag to say whether they're a real member of not. It also contains a flag to keep track of which type of member we're viewing:
this.state = {
viewMembers: true,
members: [
{
id: 1,
name: "Jim",
isMember: true
},
{
id: 2,
name: "John",
isMember: false
}
]
}
In my render function I map over this array, and only show members corresponding with the view state (i.e. if viewMembers is true, I only show members where isMember is true, and vice versa). For each member I return a table <tr>. The map function is wrapped in a CSSTransitionGroup tag to fade in the table rows. This all works fine - please see working code here: jsfiddle.net/d9cfh4zg/1/.
My issue is that it currently fades in the new state before fading out the old one, giving it a slightly janky quality. How can I allow existing rows to fade out before fading in the new ones?
try this:
const styles = {
fontFamily: "sans-serif"
};
const CSSTransitionGroup = React.addons.CSSTransitionGroup;
class App extends React.Component {
constructor() {
super();
this.state = {
viewMembers: true,
members: [
{
id: 1,
name: "Jim",
isMember: true
},
{
id: 2,
name: "John",
isMember: false
},
{
id: 3,
name: "Sarah",
isMember: false
},
{
id: 4,
name: "Mary",
isMember: true
}
]
};
this.refreshState = true;
}
changeViewState(state) {
this.refreshState = false;
setTimeout(() => {
if (state === "members") {
this.setState({ viewMembers: true });
if(!this.refreshState)
{
this.changeViewState(state);
this.refreshState = true;
}
} else {
this.setState({ viewMembers: false });
if(!this.refreshState)
{
this.changeViewState(state);
this.refreshState = true;
}
}
}, 500);
}
render() {
return (
<div style={styles}>
<h4>Members</h4>
<ul>
<li onClick={() => this.changeViewState("members")}>View Members</li>
<li onClick={() => this.changeViewState("non-members")}>
View Non-members
</li>
</ul>
<MembersTable
viewMembers={this.state.viewMembers}
members={this.state.members}
refreshState = {this.refreshState}
/>
</div>
);
}
}
const MembersTable = (props) =>
<table>
<thead>
<tr>
<td>
<strong>Id</strong>
</td>
<td>
<strong>Name</strong>
</td>
</tr>
</thead>
<CSSTransitionGroup
component="tbody"
transitionName="fade"
transitionAppear={true}
transitionAppearTimeout={500}
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
{props.members.map(member => {
if (
(props.viewMembers && member.isMember && props.refreshState) ||
(!props.viewMembers && !member.isMember && props.refreshState)
) {
return (
<tr key={member.id}>
<td>
{member.id}
</td>
<td>
{member.name}
</td>
</tr>
);
}
})}
</CSSTransitionGroup>
</table>;
ReactDOM.render(<App />, document.getElementById("root"));
I have added a refreshState variable and updated it in the setTimeout callback function which is added in the changeViewState function.
Here is the updated fiddle
hope this helps.