Skip to content

Commit

Permalink
feat(common): introduce NgSwitchContinue
Browse files Browse the repository at this point in the history
  • Loading branch information
trotyl committed Mar 30, 2018
1 parent ae3f57b commit a130993
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Angular extensions powered by community.

Package Name | Features
------------------------- | -------------------------------------------
`@angular-contrib/common` | [`<ng-host>`][NgHost], [`ngForIn`][NgForIn]
`@angular-contrib/common` | [`<ng-host>`][NgHost], [`ngForIn`][NgForIn], [`ngSwitchCaseContinue`][NgSwitchContinue]

## Usage

Expand Down Expand Up @@ -56,3 +56,4 @@ class AppComponent { }

[NgForIn]: https://github.com/trotyl/angular-contrib/tree/master/packages/common/for-in
[NgHost]: https://github.com/trotyl/angular-contrib/tree/master/packages/common/host
[NgSwitchContinue]: https://github.com/trotyl/angular-contrib/tree/master/packages/common/switch-continue
1 change: 1 addition & 0 deletions packages/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './for-in/index';
export * from './host/index';
export * from './switch-continue/index';
39 changes: 39 additions & 0 deletions packages/common/switch-continue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# NgSwitchContinue

Helper directive for matching multiple cases in `NgSwitch`.

## Type

**Directive**

## Provenance

+ https://github.com/angular/angular/issues/19824

## NgModule

`@angular-contrib/common#SwitchContinueModule`

## Usage

Adds aditional `[ngSwitchCaseContinue]="true"` to `ngSwitchCase`:

```typescript
@Component({
template: `
<ng-container [ngSwitch]="value">
<div *ngSwitchCase="0; continue: true">A</div>
<div *ngSwitchCase="1; continue: true">B</div>
<div *ngSwitchCase="2; continue: false">C</div>
<div *ngSwitchDefault>D</div>
</ng-container>
`
})
class MyComponent {
value = 0;
}
```

## Note

+ Using explicit `continue` rather than `break` for compatibility;
2 changes: 2 additions & 0 deletions packages/common/switch-continue/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './switch-continue';
export * from './switch-continue.module';
8 changes: 8 additions & 0 deletions packages/common/switch-continue/switch-continue.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { NgModule } from '@angular/core';
import { NgSwitchCasePatcher, NgSwitchDefaultPatcher, NgSwitchPatcher } from './switch-continue';

@NgModule({
declarations: [ NgSwitchPatcher, NgSwitchCasePatcher, NgSwitchDefaultPatcher ],
exports: [ NgSwitchPatcher, NgSwitchCasePatcher, NgSwitchDefaultPatcher ],
})
export class SwitchContinueModule { }
83 changes: 83 additions & 0 deletions packages/common/switch-continue/switch-continue.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { CommonModule } from '@angular/common';
import { Component, ElementRef, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SwitchContinueModule } from './switch-continue.module';

describe('ngSwitchCaseContinue', () => {
let fixture: ComponentFixture<TestComponent>;
let component: TestComponent;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
imports: [CommonModule, SwitchContinueModule],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
});

it('should display continued cases', () => {
fixture.detectChanges();
expect(component.textContent).toBe(`01`);

fixture.detectChanges();
expect(component.textContent).toBe(`01`);
});

it('should display non-continued cases', () => {
component.value = 1;

fixture.detectChanges();
expect(component.textContent).toBe(`1`);

fixture.detectChanges();
expect(component.textContent).toBe(`1`);
});

it('should display default-continued cases', () => {
component.value = 2;

fixture.detectChanges();
expect(component.textContent).toBe(`2+`);

fixture.detectChanges();
expect(component.textContent).toBe(`2+`);
});

it('should display default case', () => {
component.value = 3;

fixture.detectChanges();
expect(component.textContent).toBe(`+`);

fixture.detectChanges();
expect(component.textContent).toBe(`+`);
});

});

@Component({
selector: 'test-cmp',
template: `
<div #container>
<ng-container [ngSwitch]="value">
<div *ngSwitchCase="0; continue: true">0</div>
<div *ngSwitchCase="1; continue: false">1</div>
<div *ngSwitchCase="2; continue: true">2</div>
<div *ngSwitchDefault>+</div>
</ng-container>
</div>
`,
})
class TestComponent {
@ViewChild('container') container: ElementRef;

value = 0;

get textContent(): string {
return this.container.nativeElement.textContent.replace(/\s/g, '');
}
}
73 changes: 73 additions & 0 deletions packages/common/switch-continue/switch-continue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Directive, DoCheck, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef } from '@angular/core';

const NG_SWITCH_CONTINUE_PATCHED = '__ng_contrib_switch_continue_patched__';

@Directive({
selector: '[ngSwitch]',
})
export class NgSwitchPatcher implements DoCheck {
@Input() ngSwitch: any;

continue: boolean = false;

ngDoCheck(): void {
this.continue = false;
}

matchCase(value: any): boolean {
// tslint:disable-next-line:triple-equals
return value == this.ngSwitch;
}
}

@Directive({
selector: '[ngSwitchCase]',
})
export class NgSwitchCasePatcher implements DoCheck {
@Input() ngSwitchCase: any;
@Input() ngSwitchCaseContinue: boolean = false;

private created = false;

constructor(private vcRef: ViewContainerRef, private template: TemplateRef<any>, private host: NgSwitchPatcher) { }

ngDoCheck(): void {
if (this.host.matchCase(this.ngSwitchCase) && this.ngSwitchCaseContinue) {
this.host.continue = true;
} else if (this.host.continue) {
if (!this.created) {
this.vcRef.createEmbeddedView(this.template);
this.created = true;
}
this.host.continue = this.ngSwitchCaseContinue;
} else {
if (this.created) {
this.vcRef.clear();
this.created = false;
}
}
}
}

@Directive({
selector: '[ngSwitchDefault]',
})
export class NgSwitchDefaultPatcher implements DoCheck {
private created = false;

constructor(private vcRef: ViewContainerRef, private template: TemplateRef<any>, private host: NgSwitchPatcher) { }

ngDoCheck(): void {
if (this.host.continue) {
if (!this.created) {
this.vcRef.createEmbeddedView(this.template);
this.created = true;
}
} else {
if (this.created) {
this.vcRef.clear();
this.created = false;
}
}
}
}
3 changes: 2 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
"ignore-params",
"ignore-properties"
],
"no-misused-new": true,
"no-non-null-assertion": true,
Expand Down

0 comments on commit a130993

Please sign in to comment.