Skip to content

Commit

Permalink
fix: support 'strictTemplates' flag for public API (#3623)
Browse files Browse the repository at this point in the history
Fixes the following use-cases for the public APIs:

1. Boolean `@Input`s like `disabled` where value is not required:

```html
<input ngbButton disabled></input>
```

by adding

```ts
static ngAcceptInputType_disabled: boolean | '';
```

2. All union types like `'vertical' | 'horizontal'`:

```
// template
<nav ngbNav [orientation]="orientation"></nav>

// component
orientation = 'vertical';
```
by adding:

```ts
static ngAcceptInputType_orientation: string;
```

3. Cases where the directive selector matches the input with the optional value

```html
<button [ngbPanelToggle]="p"></button>
<button ngbPanelToggle></button>
```

by adding:

```ts
static ngAcceptInputType_ngbPanelToggle: NgbPanel | '';
```

Also makes all internal library templates to work with `strictTemplates`.

Fixes #3619
  • Loading branch information
maxokorokov committed Feb 27, 2020
1 parent ad01993 commit eef5422
Show file tree
Hide file tree
Showing 14 changed files with 44 additions and 10 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"scripts": {
"preinstall": "node misc/preinstall.js",
"postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points",
"build": "yarn ngb:build && yarn demo:build",
"build": "yarn ngb:build-ivy && yarn ngb:build && yarn demo:build",
"test": "yarn check-format && yarn ngb:lint && yarn ngb:test",
"tdd": "yarn ngb:tdd",
"e2e": "yarn e2e-app:lint && yarn ngb:e2e && yarn demo:e2e",
Expand All @@ -32,6 +32,7 @@
"ngb:tdd": "ng test ng-bootstrap --source-map false",
"ngb:e2e": "ng e2e e2e-app",
"ngb:e2e-noserve": "ng e2e e2e-app -c noserve",
"ngb:build-ivy": "ng build ng-bootstrap",
"ngb:build": "ng build ng-bootstrap --prod && yarn ngb:static",
"demo:serve": "ng serve demo --host 0.0.0.0",
"demo:docs": "ts-node --project misc/tsconfig.json misc/generate-docs.ts",
Expand Down
2 changes: 2 additions & 0 deletions src/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ export class NgbAccordion implements AfterContentChecked {
}
})
export class NgbPanelToggle {
static ngAcceptInputType_ngbPanelToggle: NgbPanel | '';

@Input()
set ngbPanelToggle(panel: NgbPanel) {
if (panel) {
Expand Down
2 changes: 2 additions & 0 deletions src/buttons/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const NGB_CHECKBOX_VALUE_ACCESSOR = {
providers: [NGB_CHECKBOX_VALUE_ACCESSOR]
})
export class NgbCheckBox implements ControlValueAccessor {
static ngAcceptInputType_disabled: boolean | '';

checked;

/**
Expand Down
2 changes: 2 additions & 0 deletions src/buttons/radio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export class NgbRadioGroup implements ControlValueAccessor {
}
})
export class NgbRadio implements OnDestroy {
static ngAcceptInputType_disabled: boolean | '';

private _checked: boolean;
private _disabled: boolean;
private _value: any = null;
Expand Down
5 changes: 5 additions & 0 deletions src/datepicker/datepicker-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ const NGB_DATEPICKER_VALIDATOR = {
})
export class NgbInputDatepicker implements OnChanges,
OnDestroy, ControlValueAccessor, Validator {
static ngAcceptInputType_autoClose: boolean | string;
static ngAcceptInputType_disabled: boolean | '';
static ngAcceptInputType_navigation: string;
static ngAcceptInputType_outsideDays: string;

private _cRef: ComponentRef<NgbDatepicker> = null;
private _disabled = false;
private _elWithFocus = null;
Expand Down
4 changes: 2 additions & 2 deletions src/datepicker/datepicker-navigation-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ import {NgbDatepickerI18n} from './datepicker-i18n';
class="custom-select"
i18n-aria-label="@@ngb.datepicker.select-month" aria-label="Select month"
i18n-title="@@ngb.datepicker.select-month" title="Select month"
(change)="changeMonth($event.target.value)">
(change)="changeMonth($any($event).target.value)">
<option *ngFor="let m of months" [attr.aria-label]="i18n.getMonthFullName(m, date?.year)"
[value]="m">{{ i18n.getMonthShortName(m, date?.year) }}</option>
</select><select #year
[disabled]="disabled"
class="custom-select"
i18n-aria-label="@@ngb.datepicker.select-year" aria-label="Select year"
i18n-title="@@ngb.datepicker.select-year" title="Select year"
(change)="changeYear($event.target.value)">
(change)="changeYear($any($event).target.value)">
<option *ngFor="let y of years" [value]="y">{{ i18n.getYearNumerals(y) }}</option>
</select>
`
Expand Down
4 changes: 4 additions & 0 deletions src/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ export class NgbDatepickerContent {
})
export class NgbDatepicker implements OnDestroy,
OnChanges, OnInit, ControlValueAccessor {
static ngAcceptInputType_autoClose: boolean | string;
static ngAcceptInputType_navigation: string;
static ngAcceptInputType_outsideDays: string;

model: DatepickerViewModel;

@ViewChild('defaultDayTemplate', {static: true}) private _defaultDayTemplate: TemplateRef<DayTemplateContext>;
Expand Down
5 changes: 5 additions & 0 deletions src/dropdown/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export class NgbNavbar {
*/
@Directive({selector: '[ngbDropdownItem]', host: {'class': 'dropdown-item', '[class.disabled]': 'disabled'}})
export class NgbDropdownItem {
static ngAcceptInputType_disabled: boolean | '';

private _disabled = false;

@Input()
Expand Down Expand Up @@ -130,6 +132,9 @@ export class NgbDropdownToggle extends NgbDropdownAnchor {
*/
@Directive({selector: '[ngbDropdown]', exportAs: 'ngbDropdown', host: {'[class.show]': 'isOpen()'}})
export class NgbDropdown implements AfterContentInit, OnDestroy {
static ngAcceptInputType_autoClose: boolean | string;
static ngAcceptInputType_display: string;

private _closed$ = new Subject<void>();
private _zoneSubscription: Subscription;
private _bodyContainer: HTMLElement;
Expand Down
3 changes: 3 additions & 0 deletions src/nav/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ export class NgbNavItem implements AfterContentChecked, OnInit {
}
})
export class NgbNav implements AfterContentInit {
static ngAcceptInputType_orientation: string;
static ngAcceptInputType_roles: boolean | string;

/**
* The id of the nav that should be active
*
Expand Down
4 changes: 3 additions & 1 deletion src/popover/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ let nextId = 0;
<div class="arrow"></div>
<h3 class="popover-header" *ngIf="title != null">
<ng-template #simpleTitle>{{title}}</ng-template>
<ng-template [ngTemplateOutlet]="isTitleTemplate() ? title : simpleTitle" [ngTemplateOutletContext]="context"></ng-template>
<ng-template [ngTemplateOutlet]="isTitleTemplate() ? $any(title) : simpleTitle" [ngTemplateOutletContext]="context"></ng-template>
</h3>
<div class="popover-body"><ng-content></ng-content></div>`,
styleUrls: ['./popover.scss']
Expand All @@ -61,6 +61,8 @@ export class NgbPopoverWindow {
*/
@Directive({selector: '[ngbPopover]', exportAs: 'ngbPopover'})
export class NgbPopover implements OnInit, OnDestroy, OnChanges {
static ngAcceptInputType_autoClose: boolean | string;

/**
* Indicates whether the popover should be closed on `Escape` key and inside/outside clicks:
*
Expand Down
3 changes: 3 additions & 0 deletions src/tabset/tabset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ export interface NgbTabChangeEvent {
`
})
export class NgbTabset implements AfterContentChecked {
static ngAcceptInputType_justify: string;
static ngAcceptInputType_orientation: string;

justifyClass: string;

@ContentChildren(NgbTab) tabs: QueryList<NgbTab>;
Expand Down
14 changes: 8 additions & 6 deletions src/timepicker/timepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
<input type="text" class="ngb-tp-input form-control" [class.form-control-sm]="isSmallSize"
[class.form-control-lg]="isLargeSize"
maxlength="2" inputmode="numeric" placeholder="HH" i18n-placeholder="@@ngb.timepicker.HH"
[value]="formatHour(model?.hour)" (change)="updateHour($event.target.value)"
[value]="formatHour(model?.hour)" (change)="updateHour($any($event).target.value)"
[readOnly]="readonlyInputs" [disabled]="disabled" aria-label="Hours" i18n-aria-label="@@ngb.timepicker.hours"
(input)="formatInput($event.target)"
(input)="formatInput($any($event).target)"
(keydown.ArrowUp)="changeHour(hourStep); $event.preventDefault()"
(keydown.ArrowDown)="changeHour(-hourStep); $event.preventDefault()">
<button *ngIf="spinners" tabindex="-1" type="button" (click)="changeHour(-hourStep)"
Expand All @@ -65,9 +65,9 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
</button>
<input type="text" class="ngb-tp-input form-control" [class.form-control-sm]="isSmallSize" [class.form-control-lg]="isLargeSize"
maxlength="2" inputmode="numeric" placeholder="MM" i18n-placeholder="@@ngb.timepicker.MM"
[value]="formatMinSec(model?.minute)" (change)="updateMinute($event.target.value)"
[value]="formatMinSec(model?.minute)" (change)="updateMinute($any($event).target.value)"
[readOnly]="readonlyInputs" [disabled]="disabled" aria-label="Minutes" i18n-aria-label="@@ngb.timepicker.minutes"
(input)="formatInput($event.target)"
(input)="formatInput($any($event).target)"
(keydown.ArrowUp)="changeMinute(minuteStep); $event.preventDefault()"
(keydown.ArrowDown)="changeMinute(-minuteStep); $event.preventDefault()">
<button *ngIf="spinners" tabindex="-1" type="button" (click)="changeMinute(-minuteStep)"
Expand All @@ -87,9 +87,9 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
</button>
<input type="text" class="ngb-tp-input form-control" [class.form-control-sm]="isSmallSize" [class.form-control-lg]="isLargeSize"
maxlength="2" inputmode="numeric" placeholder="SS" i18n-placeholder="@@ngb.timepicker.SS"
[value]="formatMinSec(model?.second)" (change)="updateSecond($event.target.value)"
[value]="formatMinSec(model?.second)" (change)="updateSecond($any($event).target.value)"
[readOnly]="readonlyInputs" [disabled]="disabled" aria-label="Seconds" i18n-aria-label="@@ngb.timepicker.seconds"
(input)="formatInput($event.target)"
(input)="formatInput($any($event).target)"
(keydown.ArrowUp)="changeSecond(secondStep); $event.preventDefault()"
(keydown.ArrowDown)="changeSecond(-secondStep); $event.preventDefault()">
<button *ngIf="spinners" tabindex="-1" type="button" (click)="changeSecond(-secondStep)"
Expand All @@ -115,6 +115,8 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
})
export class NgbTimepicker implements ControlValueAccessor,
OnChanges {
static ngAcceptInputType_size: string;

disabled: boolean;
model: NgbTime;

Expand Down
2 changes: 2 additions & 0 deletions src/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export class NgbTooltipWindow {
*/
@Directive({selector: '[ngbTooltip]', exportAs: 'ngbTooltip'})
export class NgbTooltip implements OnInit, OnDestroy, OnChanges {
static ngAcceptInputType_autoClose: boolean | string;

/**
* Indicates whether the tooltip should be closed on `Escape` key and inside/outside clicks:
*
Expand Down
1 change: 1 addition & 0 deletions src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
]
},
"angularCompilerOptions": {
"strictTemplates": true,
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true
Expand Down

0 comments on commit eef5422

Please sign in to comment.