Skip to content

Commit 491bf10

Browse files
authored
fix(ngx-selecto): reduce change detection cycles and teardown event listeners once the view is removed (#134)
1 parent 0d1624d commit 491bf10

File tree

8 files changed

+52
-178
lines changed

8 files changed

+52
-178
lines changed

packages/ngx-selecto/README.md

+2-119
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,3 @@
1+
# ngx-selecto
12

2-
<p align="middle" ><img src="https://daybrush.com/selecto/images/logo.png" /></p>
3-
<h2 align="middle">Angular Selecto</h2>
4-
<p align="middle">
5-
<a href="https://www.npmjs.com/package/ngx-selecto" target="_blank"><img src="https://img.shields.io/npm/v/ngx-selecto.svg?style=flat-square&color=007acc&label=version" alt="npm version" /></a>
6-
<img src="https://img.shields.io/badge/language-typescript-blue.svg?style=flat-square"/>
7-
<a href="https://github.com/daybrush/selecto/blob/master/LICENSE" target="_blank"><img src="https://img.shields.io/github/license/daybrush/selecto.svg?style=flat-square&label=license&color=08CE5D"/></a>
8-
<a href="https://github.com/daybrush/selecto/tree/master/packages/react-selecto" target="_blank"><img alt="React" src="https://img.shields.io/static/v1.svg?label=&message=React&style=flat-square&color=61daeb"></a>
9-
<a href="https://github.com/daybrush/selecto/tree/master/packages/preact-selecto" target="_blank"><img alt="Preact" src="https://img.shields.io/static/v1.svg?label=&message=Preact&style=flat-square&color=673ab8"></a>
10-
<a href="https://github.com/daybrush/selecto/tree/master/packages/ngx-selecto" target="_blank"><img alt="Angular" src="https://img.shields.io/static/v1.svg?label=&message=Angular&style=flat-square&color=C82B38"></a>
11-
<a href="https://github.com/daybrush/selecto/tree/master/packages/vue-selecto" target="_blank"><img
12-
alt="Vue"
13-
src="https://img.shields.io/static/v1.svg?label=&message=Vue&style=flat-square&color=3fb984"></a>
14-
<a href="https://github.com/daybrush/selecto/tree/master/packages/svelte-selecto" target="_blank"><img
15-
alt="Svelte"
16-
src="https://img.shields.io/static/v1.svg?label=&message=Svelte&style=flat-square&color=C82B38"></a>
17-
<a href="https://github.com/daybrush/selecto/tree/master/packages/lit-selecto" target="_blank"><img
18-
alt="Lit"
19-
src="https://img.shields.io/static/v1.svg?label=&message=Lit&style=flat-square&color=4E8EE0"></a>
20-
</p>
21-
<p align="middle">Angular Selecto is an Angular Component that allows you to select elements in the drag area using the mouse or touch.</p>
22-
23-
<p align="middle">
24-
<a href="https://daybrush.com/selecto" target="_blank"><strong>Demo</strong></a> /
25-
<a href="https://daybrush.com/selecto/release/latest/doc/" target="_blank"><strong>API</strong></a> /
26-
<a href="https://github.com/daybrush/scena" target="_blank"><strong>Main Project</strong></a>
27-
</p>
28-
29-
## ⚙️ Installation
30-
### npm
31-
```bash
32-
$ npm install ngx-selecto
33-
```
34-
35-
## 🚀 How to use
36-
```js
37-
import { BrowserModule } from '@angular/platform-browser';
38-
import { NgModule } from '@angular/core';
39-
import { AppComponent } from './app.component';
40-
import { NgxSelectoComponent, NgxSelectoModule } from "ngx-selecto";
41-
42-
@NgModule({
43-
declarations: [
44-
AppComponent,
45-
NgxSelectoComponent,
46-
],
47-
imports: [
48-
BrowserModule,
49-
// NgxSelectoModule,
50-
],
51-
providers: [],
52-
bootstrap: [AppComponent]
53-
})
54-
export class AppModule { }
55-
```
56-
### Template
57-
```html
58-
<ngx-selecto
59-
[container]="document.body"
60-
dragContainer=".elements"
61-
[selectableTargets]='[".target", document.querySelector(".target2")]'
62-
[selectByClick]="true"
63-
[selectFromInside]="true"
64-
[continueSelect]="false"
65-
[toggleContinueSelect]="'shift'"
66-
[keyContainer]="window"
67-
[hitRate]="100"
68-
(dragStart)="onDragStart($event)"
69-
(selectStart)="onSelectStart($event)"
70-
(select)="onSelect($event)"
71-
(selectEnd)="onSelectEnd($event)"
72-
></ngx-selecto>
73-
```
74-
75-
## ⚙️ Developments
76-
### `ng serve`
77-
78-
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
79-
80-
## ⭐️ Show Your Support
81-
Please give a ⭐️ if this project helped you!
82-
83-
84-
## 👏 Contributing
85-
86-
If you have any questions or requests or want to contribute to `selecto` or other packages, please write the [issue](https://github.com/daybrush/selecto/issues) or give me a Pull Request freely.
87-
88-
## 🐞 Bug Report
89-
90-
If you find a bug, please report to us opening a new [Issue](https://github.com/daybrush/selecto/issues) on GitHub.
91-
92-
93-
## 📝 License
94-
95-
This project is [MIT](https://github.com/daybrush/selecto/blob/master/LICENSE) licensed.
96-
97-
```
98-
MIT License
99-
100-
Copyright (c) 2020 Daybrush
101-
102-
Permission is hereby granted, free of charge, to any person obtaining a copy
103-
of this software and associated documentation files (the "Software"), to deal
104-
in the Software without restriction, including without limitation the rights
105-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
106-
copies of the Software, and to permit persons to whom the Software is
107-
furnished to do so, subject to the following conditions:
108-
109-
The above copyright notice and this permission notice shall be included in all
110-
copies or substantial portions of the Software.
111-
112-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
113-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
114-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
115-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
116-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
117-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
118-
SOFTWARE.
119-
```
120-
3+
See [readme](./projects/ngx-selecto/README.md) for more info.

packages/ngx-selecto/projects/ngx-selecto/src/lib/ngx-selecto.component.ts

+33-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
11
import {
2-
Component, ElementRef,
3-
AfterViewInit, OnDestroy, OnChanges, SimpleChanges, ViewChild, Input, Output, EventEmitter,
2+
Component,
3+
ElementRef,
4+
AfterViewInit,
5+
OnDestroy,
6+
OnChanges,
7+
SimpleChanges,
8+
ViewChild,
9+
EventEmitter,
10+
NgZone,
411
} from '@angular/core';
12+
import { Subject, fromEvent } from 'rxjs';
13+
import { takeUntil } from 'rxjs/operators';
514
import VanillaSelecto, {
6-
CLASS_NAME, OPTIONS, SelectoOptions, PROPERTIES, EVENTS,
15+
CLASS_NAME,
16+
OPTIONS,
17+
SelectoOptions,
18+
PROPERTIES,
19+
EVENTS,
720
} from 'selecto';
21+
822
import { ANGULAR_SELECTO_INPUTS, ANGULAR_SELECTO_OUTPUTS } from './consts';
923
import { NgxSelectoInterface } from './ngx-selecto.interface';
1024

@@ -15,23 +29,24 @@ import { NgxSelectoInterface } from './ngx-selecto.interface';
1529
`,
1630
inputs: ANGULAR_SELECTO_INPUTS,
1731
outputs: ANGULAR_SELECTO_OUTPUTS,
18-
styles: []
1932
})
2033
export class NgxSelectoComponent
2134
extends NgxSelectoInterface
2235
implements OnDestroy, AfterViewInit, OnChanges {
23-
@ViewChild('el', { static: false }) elRef!: ElementRef;
36+
@ViewChild('el', { static: true }) elRef!: ElementRef<HTMLElement>;
2437

2538
public selectionClassName = CLASS_NAME;
2639

27-
constructor() {
40+
private destroy$ = new Subject<void>();
41+
42+
constructor(private ngZone: NgZone) {
2843
super();
44+
2945
EVENTS.forEach(name => {
3046
(this as any)[name] = new EventEmitter();
3147
});
3248
}
3349

34-
3550
ngAfterViewInit(): void {
3651
const options: Partial<SelectoOptions> = {};
3752

@@ -40,19 +55,24 @@ export class NgxSelectoComponent
4055
(options as any)[name] = this[name];
4156
}
4257
});
43-
this.selecto = new VanillaSelecto({
58+
59+
this.selecto = this.ngZone.runOutsideAngular(() => new VanillaSelecto({
4460
...options,
4561
portalContainer: this.elRef.nativeElement,
46-
});
62+
}));
4763

4864
const selecto = this.selecto;
4965

5066
EVENTS.forEach(name => {
51-
selecto.on(name, e => {
52-
this[name].emit(e as any);
67+
fromEvent(selecto, name).pipe(takeUntil(this.destroy$)).subscribe(event => {
68+
const emitter = this[name];
69+
if (emitter && (emitter.observed || emitter.observers.length > 0)) {
70+
this.ngZone.run(() => emitter.emit(event as any));
71+
}
5372
});
5473
});
5574
}
75+
5676
ngOnChanges(changes: SimpleChanges): void {
5777
const selecto = this.selecto;
5878

@@ -71,7 +91,9 @@ export class NgxSelectoComponent
7191
(selecto as any)[name] = currentValue;
7292
}
7393
}
94+
7495
ngOnDestroy() {
96+
this.destroy$.next();
7597
this.selecto.destroy();
7698
}
7799
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
import { NgModule } from '@angular/core';
22
import { NgxSelectoComponent } from './ngx-selecto.component';
33

4-
5-
64
@NgModule({
75
declarations: [NgxSelectoComponent],
8-
imports: [
9-
],
10-
exports: [NgxSelectoComponent]
6+
exports: [NgxSelectoComponent],
117
})
12-
export class NgxSelectoModule { }
8+
export class NgxSelectoModule {}

packages/ngx-selecto/projects/ngx-selecto/src/lib/ngx-selecto.service.spec.ts

-16
This file was deleted.

packages/ngx-selecto/projects/ngx-selecto/src/lib/ngx-selecto.service.ts

-9
This file was deleted.

packages/ngx-selecto/projects/ngx-selecto/src/public-api.ts

-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
* Public API Surface of ngx-selecto
33
*/
44

5-
export * from './lib/ngx-selecto.service';
65
export * from './lib/ngx-selecto.component';
76
export * from './lib/ngx-selecto.module';

packages/ngx-selecto/src/app/app.component.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
11
import { Component } from '@angular/core';
2-
import { OnSelectEnd, OnSelect } from '../../projects/ngx-selecto/src/public-api';
2+
import { OnKeyEvent, OnSelect, OnSelectEnd } from 'selecto';
3+
34
@Component({
45
selector: 'app-root',
56
templateUrl: './app.component.html',
6-
styleUrls: ['./app.component.css']
7+
styleUrls: ['./app.component.css'],
78
})
89
export class AppComponent {
910
dragContainer = window;
10-
onKeydown() {
11+
12+
onKeydown(event: OnKeyEvent) {
1113
document.querySelector('.button')!.classList.add('selected');
1214
}
13-
onKeyup() {
15+
16+
onKeyup(event: OnKeyEvent) {
1417
document.querySelector('.button')!.classList.remove('selected');
1518
}
19+
1620
onSelectStart(e: OnSelect) {
1721
console.log('start', e);
18-
e.added.forEach(el => {
22+
e.added.forEach((el) => {
1923
el.classList.add('selected');
2024
});
21-
e.removed.forEach(el => {
25+
e.removed.forEach((el) => {
2226
el.classList.remove('selected');
2327
});
2428
}
29+
2530
onSelectEnd(e: OnSelectEnd) {
2631
console.log('end', e);
27-
e.afterAdded.forEach(el => {
32+
e.afterAdded.forEach((el) => {
2833
el.classList.add('selected');
2934
});
30-
e.afterRemoved.forEach(el => {
35+
e.afterRemoved.forEach((el) => {
3136
el.classList.remove('selected');
3237
});
3338
}

packages/ngx-selecto/tsconfig.json

+2-8
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@
1212
"noFallthroughCasesInSwitch": true,
1313
"sourceMap": true,
1414
"paths": {
15-
"ngx-selecto": [
16-
"dist/ngx-selecto/ngx-selecto",
17-
"dist/ngx-selecto"
18-
]
15+
"ngx-selecto": ["projects/ngx-selecto/src/public-api.ts"]
1916
},
2017
"declaration": false,
2118
"downlevelIteration": true,
@@ -24,10 +21,7 @@
2421
"importHelpers": true,
2522
"target": "es2017",
2623
"module": "es2020",
27-
"lib": [
28-
"es2020",
29-
"dom"
30-
]
24+
"lib": ["es2020", "dom"]
3125
},
3226
"angularCompilerOptions": {
3327
"enableI18nLegacyMessageIdFormat": false,

0 commit comments

Comments
 (0)