Skip to content

Commit e118a55

Browse files
feat: adding validation for required input fields
1 parent cc493a7 commit e118a55

File tree

6 files changed

+108
-15
lines changed

6 files changed

+108
-15
lines changed

CHANGELOG.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased][]
99

10+
### Added
11+
12+
- Adding validation for @Input attributes that needs internal manipulation. After these changes:
13+
- if `count` is not a numeric value, it will use the default value as `1`
14+
- if `animation` is not a valid attribute, it will use the default value as `progress`
15+
- PS: The other values alredy have a fallback, so nothing to worry here
16+
17+
### Updated
18+
19+
- Adding `ngOnChange` to validate `count` input in case of changes via binding
20+
1021
## [2.8.0][] - 2021-02-18
1122

1223
### Fixed
@@ -387,7 +398,5 @@ Now we can define the animation we want to use in `<ngx-skeleton-loader>` compon
387398
[2.6.2]: https://github.com/willmendesneto/ngx-skeleton-loader/tree/v2.6.2
388399
[unreleased]: https://github.com/willmendesneto/ngx-skeleton-loader/compare/v2.7.0...HEAD
389400
[2.7.0]: https://github.com/willmendesneto/ngx-skeleton-loader/tree/v2.7.0
390-
391-
392-
[Unreleased]: https://github.com/willmendesneto/ngx-skeleton-loader/compare/v2.8.0...HEAD
393-
[2.8.0]: https://github.com/willmendesneto/ngx-skeleton-loader/tree/v2.8.0
401+
[unreleased]: https://github.com/willmendesneto/ngx-skeleton-loader/compare/v2.8.0...HEAD
402+
[2.8.0]: https://github.com/willmendesneto/ngx-skeleton-loader/tree/v2.8.0

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"bundlesize": [
5050
{
5151
"path": "./dist/ngx-skeleton-loader/bundles/ngx-skeleton-loader.umd.min.js",
52-
"maxSize": "1.50KB"
52+
"maxSize": "1.6KB"
5353
}
5454
],
5555
"dependencies": {

projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component';
3939
<ngx-skeleton-loader animation="invalid-option"></ngx-skeleton-loader>
4040
</div>
4141
42+
<div class="skeletons-count-invalid-option">
43+
<ngx-skeleton-loader [count]="invalidValueIncount"></ngx-skeleton-loader>
44+
</div>
45+
4246
<div class="skeletons-with-count">
4347
<ngx-skeleton-loader count="2"></ngx-skeleton-loader>
4448
</div>
@@ -56,6 +60,7 @@ import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component';
5660
})
5761
class ContainerComponent {
5862
animationWithFalsePassedViaBinding = false;
63+
invalidValueIncount = 'two';
5964
}
6065

6166
describe('NgxSkeletonLoaderComponent', () => {
@@ -73,21 +78,31 @@ describe('NgxSkeletonLoaderComponent', () => {
7378
}),
7479
);
7580

81+
it('should console 2 errors if `animation` and `count` receives invalid options and is running in development mode', () => {
82+
expect(console.error).toHaveBeenCalledTimes(2);
83+
});
84+
7685
it('should console errors if `animation` is an invalid option and is running in development mode', () => {
77-
expect(console.error).toHaveBeenCalledTimes(1);
7886
expect(console.error).toHaveBeenCalledWith(
7987
// tslint:disable-next-line: max-line-length
8088
`\`NgxSkeletonLoaderComponent\` need to receive 'animation' as: progress, progress-dark, pulse, false. Forcing default to "progress".`,
8189
);
8290
});
8391

92+
it('should console errors if `animation` is an invalid option and is running in development mode', () => {
93+
expect(console.error).toHaveBeenCalledWith(
94+
// tslint:disable-next-line: max-line-length
95+
`\`NgxSkeletonLoaderComponent\` need to receive 'count' a numeric value. Forcing default to "1".`,
96+
);
97+
});
98+
8499
it('should add all relevant WAI-ARIA `aria-` attributes in all ngx-skeleton-loader', () => {
85-
expect(fixture.nativeElement.querySelectorAll('[aria-busy="true"]').length).toBe(12);
86-
expect(fixture.nativeElement.querySelectorAll('[aria-valuemin="0"]').length).toBe(12);
87-
expect(fixture.nativeElement.querySelectorAll('[aria-valuemax="100"]').length).toBe(12);
88-
expect(fixture.nativeElement.querySelectorAll('[aria-valuetext]').length).toBe(12);
89-
expect(fixture.nativeElement.querySelectorAll('[role="progressbar"]').length).toBe(12);
90-
expect(fixture.nativeElement.querySelectorAll('[tabindex="0"]').length).toBe(12);
100+
expect(fixture.nativeElement.querySelectorAll('[aria-busy="true"]').length).toBe(13);
101+
expect(fixture.nativeElement.querySelectorAll('[aria-valuemin="0"]').length).toBe(13);
102+
expect(fixture.nativeElement.querySelectorAll('[aria-valuemax="100"]').length).toBe(13);
103+
expect(fixture.nativeElement.querySelectorAll('[aria-valuetext]').length).toBe(13);
104+
expect(fixture.nativeElement.querySelectorAll('[role="progressbar"]').length).toBe(13);
105+
expect(fixture.nativeElement.querySelectorAll('[tabindex="0"]').length).toBe(13);
91106
});
92107

93108
it('should use progress as default animation if `animation` is not passed as component attribute', () => {

projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import { Component, OnInit, Input, isDevMode, OnDestroy, AfterViewInit, ChangeDetectionStrategy } from '@angular/core';
1+
import {
2+
Component,
3+
OnInit,
4+
Input,
5+
isDevMode,
6+
OnDestroy,
7+
AfterViewInit,
8+
ChangeDetectionStrategy,
9+
OnChanges,
10+
SimpleChanges,
11+
} from '@angular/core';
212
import { start, end } from 'perf-marks/marks';
313

414
@Component({
@@ -7,7 +17,7 @@ import { start, end } from 'perf-marks/marks';
717
styleUrls: ['./ngx-skeleton-loader.scss'],
818
changeDetection: ChangeDetectionStrategy.OnPush,
919
})
10-
export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDestroy {
20+
export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
1121
// tslint:disable-next-line: variable-name
1222
static ngAcceptInputType_count: number | string;
1323
// tslint:disable-next-line: variable-name
@@ -37,7 +47,23 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest
3747
start('NgxSkeletonLoader:Rendered');
3848
start('NgxSkeletonLoader:Loaded');
3949

40-
this.items.length = +this.count;
50+
this.validateInputValues();
51+
}
52+
53+
private validateInputValues() {
54+
// Checking if it's receiving a numeric value (string having ONLY numbers or if it's a number)
55+
if (!/^\d+$/.test(`${this.count}`)) {
56+
// Shows error message only in Development
57+
if (isDevMode()) {
58+
console.error(
59+
`\`NgxSkeletonLoaderComponent\` need to receive 'count' a numeric value. Forcing default to "1".`,
60+
);
61+
}
62+
this.count = 1;
63+
}
64+
65+
this.items.length = this.count;
66+
4167
const allowedAnimations = ['progress', 'progress-dark', 'pulse', 'false'];
4268
if (allowedAnimations.indexOf(String(this.animation)) === -1) {
4369
// Shows error message only in Development
@@ -52,6 +78,22 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest
5278
}
5379
}
5480

81+
ngOnChanges(changes: SimpleChanges) {
82+
// Avoiding multiple calls for the same input in case there's no changes in the fields
83+
// Checking if the fields that require validation are available and if they were changed
84+
// In case were not changed, we stop the function. Otherwise, `validateInputValues` will be called.
85+
if (
86+
['count', 'animation'].find(
87+
key =>
88+
changes[key] && (changes[key].isFirstChange() || changes[key].previousValue === changes[key].currentValue),
89+
)
90+
) {
91+
return;
92+
}
93+
94+
this.validateInputValues();
95+
}
96+
5597
ngAfterViewInit() {
5698
end('NgxSkeletonLoader:Rendered');
5799
}

src/app/app.component.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ <h2>Line skeletons with theming - Changing Colors and Switching Animations</h2>
7676
Also, this example will be switching between `<b>pulse</b>` and
7777
`<b>progress-dark</b>` animations
7878
</p>
79+
<p>Current value: <b>{{animation}}</b></p>
80+
7981
<div class="item-with-background">
8082
<ngx-skeleton-loader
8183
count="5"
@@ -110,6 +112,22 @@ <h2>Circle skeletons with theming</h2>
110112
</ngx-skeleton-loader>
111113
</div>
112114

115+
<h2>Circle skeletons with mixing theming and `ngStyle` via `[theme]` input</h2>
116+
<p>Width and height will be switching between 50px and 100px every 5 seconds</p>
117+
<p>Current value: <b>{{widthHeightSizeInPixels}}px</b></p>
118+
<div class="item">
119+
<ngx-skeleton-loader
120+
count="5"
121+
appearance="circle"
122+
[theme]="{
123+
'width.px': widthHeightSizeInPixels,
124+
'height.px': widthHeightSizeInPixels,
125+
'border-radius': '10px'
126+
}"
127+
>
128+
</ngx-skeleton-loader>
129+
</div>
130+
113131
<h2>Facebook skeleton example</h2>
114132

115133
<div class="fb-item">
@@ -246,6 +264,13 @@ <h3>Skeleton using `progress-dark` animation</h3>
246264
></ngx-skeleton-loader>
247265
</div>
248266

267+
<h3>Skeleton switching values for `animation` and `count` @Input</h3>
268+
<p>Current values:</p>
269+
<ul>
270+
<li>Count: <b>{{count}}</b></li>
271+
<li>Animation: <b>{{animation}}</b></li>
272+
</ul>
273+
249274
<div class="item-with-background">
250275
<ngx-skeleton-loader
251276
[count]="count"

src/app/app.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class AppComponent implements OnInit, OnDestroy {
1111
animation = 'pulse';
1212
contentLoaded = false;
1313
count = 2;
14+
widthHeightSizeInPixels = 50;
1415

1516
intervalId: number | null = null;
1617

@@ -22,6 +23,7 @@ export class AppComponent implements OnInit, OnDestroy {
2223
this.intervalId = window.setInterval(() => {
2324
this.animation = this.animation === 'pulse' ? 'progress-dark' : 'pulse';
2425
this.count = this.count === 2 ? 5 : 2;
26+
this.widthHeightSizeInPixels = this.widthHeightSizeInPixels === 50 ? 100 : 50;
2527
}, 5000);
2628
}
2729

0 commit comments

Comments
 (0)