Skip to content

Commit

Permalink
fix: apply nullable checks for async inputs (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
kylecannon committed Jan 18, 2021
1 parent 66ed9b9 commit 4b9dc22
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 16 deletions.
4 changes: 2 additions & 2 deletions apps/responsive-app-e2e/src/integration/app.spec.ts
Expand Up @@ -39,7 +39,7 @@ describe('responsive-app', () => {
});

it('should show links and info on desktop', () => {
getNavigationLinks().should('have.length', 5);
getNavigationLinks().should('have.length', 6);
cy.get('h2').contains('Select user profile!');
});

Expand All @@ -51,7 +51,7 @@ describe('responsive-app', () => {

it('should show links on desktop profile', () => {
cy.visit('/3');
getNavigationLinks().should('have.length', 5);
getNavigationLinks().should('have.length', 6);
});

it('should not show back button on desktop profile', () => {
Expand Down
8 changes: 8 additions & 0 deletions apps/responsive-app/src/app/app.component.html
Expand Up @@ -48,6 +48,14 @@
linkActive="mat-list-single-selected-option"
>Profile 5</a
>
<a
mat-list-item
[linkTo]="'../6' | valueToAsyncValue | async"
[linkActive]="
'mat-list-single-selected-option' | valueToAsyncValue | async
"
>Profile 6 (Async)</a
>
</mat-nav-list>
</mat-grid-tile>
<mat-grid-tile style="background-color: lightcoral;">
Expand Down
2 changes: 2 additions & 0 deletions apps/responsive-app/src/app/app.module.ts
Expand Up @@ -14,6 +14,7 @@ import { MediaDirective } from './use-media/use-media.directive';
import { SelectUserComponent } from './select-user/select-user.component';
import { UserProfileComponent } from './user-profile/user-profile.component';
import { UserListComponent } from './user-list/user-list.component';
import { ValueToAsyncValuePipe } from './value-to-async-value.pipe';

@NgModule({
declarations: [
Expand All @@ -22,6 +23,7 @@ import { UserListComponent } from './user-list/user-list.component';
SelectUserComponent,
UserProfileComponent,
UserListComponent,
ValueToAsyncValuePipe,
],
imports: [
BrowserModule,
Expand Down
12 changes: 12 additions & 0 deletions apps/responsive-app/src/app/value-to-async-value.pipe.ts
@@ -0,0 +1,12 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';

@Pipe({
name: 'valueToAsyncValue',
})
export class ValueToAsyncValuePipe implements PipeTransform {
transform(value: string): Observable<string> {
return of(value).pipe(delay(10));
}
}
21 changes: 11 additions & 10 deletions libs/router/src/lib/link-active.directive.ts
Expand Up @@ -15,6 +15,7 @@ import { LinkTo } from './link-to.directive';
import { Router } from './router.service';
import { combineLatest, of, Subject, Subscription } from 'rxjs';
import { map, mapTo, startWith, takeUntil } from 'rxjs/operators';
import { filterNullable } from './operators/filter-nullable.operator';

export interface LinkActiveOptions {
exact: boolean;
Expand All @@ -39,8 +40,8 @@ export class LinkActive implements AfterContentInit, OnDestroy, OnChanges {
@ContentChildren(LinkTo, { descendants: true }) public links: QueryList<
LinkTo
>;
@Input('linkActive') activeClass = 'active';
@Input() activeOptions: LinkActiveOptions;
@Input('linkActive') activeClass: string | null = 'active';
@Input() activeOptions?: LinkActiveOptions | null;
private _activeOptions: LinkActiveOptions = { exact: true };
private _destroy$ = new Subject();
private _linksSub!: Subscription;
Expand Down Expand Up @@ -83,16 +84,20 @@ export class LinkActive implements AfterContentInit, OnDestroy, OnChanges {
.map((link) =>
link.hrefUpdated.pipe(
startWith(link.linkHref),
mapTo(link.linkHref)
mapTo(link.linkHref),
filterNullable()
)
)
: [];

const link$ = this.link
? this.link.hrefUpdated.pipe(
startWith(this.link.linkHref),
mapTo(this.link.linkHref)
mapTo(this.link.linkHref),
filterNullable()
)
: of('');

const router$ = this.router.url$.pipe(
map((path) => this.router.getExternalUrl(path || '/'))
);
Expand All @@ -109,14 +114,10 @@ export class LinkActive implements AfterContentInit, OnDestroy, OnChanges {
checkActive(linkHrefs: string[], path: string) {
const active = linkHrefs.reduce((isActive, current) => {
const [href] = current.split('?');

if (this._activeOptions.exact) {
isActive = isActive ? isActive : href === path;
} else {
isActive = isActive ? isActive : path.startsWith(href);
return isActive ? isActive : href === path;
}

return isActive;
return isActive ? isActive : path.startsWith(href);
}, false);

this.updateClasses(active);
Expand Down
14 changes: 10 additions & 4 deletions libs/router/src/lib/link-to.directive.ts
Expand Up @@ -23,19 +23,22 @@ const DEFAULT_TARGET = '_self';
@Directive({ selector: 'a[linkTo]' })
export class LinkTo {
@Input() target = DEFAULT_TARGET;
@HostBinding('href') linkHref: string;
@HostBinding('href') linkHref?: string | null;

@Input() set linkTo(href: string) {
@Input() set linkTo(href: string | null | undefined) {
if (href === null || href === undefined) {
return;
}
this._href = href;
this._updateHref();
}

@Input() set queryParams(params: Params) {
@Input() set queryParams(params: Params | null | undefined) {
this._query = params;
this._updateHref();
}

@Input() set fragment(hash: string) {
@Input() set fragment(hash: string | null | undefined) {
this._hash = hash;
this._updateHref();
}
Expand All @@ -54,6 +57,9 @@ export class LinkTo {
*/
@HostListener('click', ['$event'])
onClick(event: any) {
if (!this._href) {
return;
}
if (!this._comboClick(event) && this.target === DEFAULT_TARGET) {
this.router.go(this._href, this._query, this._hash);

Expand Down
9 changes: 9 additions & 0 deletions libs/router/src/lib/operators/filter-nullable.operator.ts
@@ -0,0 +1,9 @@
import { Observable } from 'rxjs';
import { filter } from 'rxjs/operators';

export function isNotNullable<T>(it: T): it is NonNullable<T> {
return it !== null && it !== undefined;
}

export const filterNullable = <T>() => (source: Observable<T>) =>
source.pipe(filter(isNotNullable));

0 comments on commit 4b9dc22

Please sign in to comment.