diff --git a/goldens/public-api/common/index.md b/goldens/public-api/common/index.md index ef74915281b2a..a59371b0e2aa8 100644 --- a/goldens/public-api/common/index.md +++ b/goldens/public-api/common/index.md @@ -55,7 +55,7 @@ export class CommonModule { // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public @@ -407,7 +407,7 @@ export class NgClass implements DoCheck { // (undocumented) ngDoCheck(): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -430,7 +430,7 @@ export class NgComponentOutlet implements OnChanges, OnDestroy { // (undocumented) ngOnDestroy(): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -446,7 +446,7 @@ export class NgForOf = NgIterable> implements DoCh get ngForTrackBy(): TrackByFunction; static ngTemplateContextGuard>(dir: NgForOf, ctx: any): ctx is NgForOfContext; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngFor][ngForOf]", never, { "ngForOf": "ngForOf"; "ngForTrackBy": "ngForTrackBy"; "ngForTemplate": "ngForTemplate"; }, {}, never, never, false>; + static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngFor][ngForOf]", never, { "ngForOf": "ngForOf"; "ngForTrackBy": "ngForTrackBy"; "ngForTemplate": "ngForTemplate"; }, {}, never, never, true>; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration, never>; } @@ -481,7 +481,7 @@ export class NgIf { static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext>; static ngTemplateGuard_ngIf: 'binding'; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngIf]", never, { "ngIf": "ngIf"; "ngIfThen": "ngIfThen"; "ngIfElse": "ngIfElse"; }, {}, never, never, false>; + static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngIf]", never, { "ngIf": "ngIf"; "ngIfThen": "ngIfThen"; "ngIfElse": "ngIfElse"; }, {}, never, never, true>; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration, never>; } @@ -525,7 +525,7 @@ export class NgPlural { // (undocumented) set ngPlural(value: number); // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -536,7 +536,7 @@ export class NgPluralCase { // (undocumented) value: string; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -551,7 +551,7 @@ export class NgStyle implements DoCheck { [klass: string]: any; } | null); // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -561,7 +561,7 @@ export class NgSwitch { // (undocumented) set ngSwitch(newValue: any); // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -572,7 +572,7 @@ export class NgSwitchCase implements DoCheck { ngDoCheck(): void; ngSwitchCase: any; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -581,7 +581,7 @@ export class NgSwitchCase implements DoCheck { export class NgSwitchDefault { constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, ngSwitch: NgSwitch); // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -595,7 +595,7 @@ export class NgTemplateOutlet implements OnChanges { ngTemplateOutletContext: Object | null; ngTemplateOutletInjector: Injector | null; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } diff --git a/packages/common/src/common_module.ts b/packages/common/src/common_module.ts index 1b8265b7799a2..b8cc78e2295ca 100644 --- a/packages/common/src/common_module.ts +++ b/packages/common/src/common_module.ts @@ -21,16 +21,10 @@ import {COMMON_PIPES} from './pipes/index'; * Re-exported by `BrowserModule`, which is included automatically in the root * `AppModule` when you create a new app with the CLI `new` command. * - * * The `providers` options configure the NgModule's injector to provide - * localization dependencies to members. - * * The `exports` options make the declared directives and pipes available for import - * by other NgModules. - * * @publicApi */ @NgModule({ - imports: [COMMON_PIPES], - declarations: [COMMON_DIRECTIVES], + imports: [COMMON_DIRECTIVES, COMMON_PIPES], exports: [COMMON_DIRECTIVES, COMMON_PIPES], }) export class CommonModule { diff --git a/packages/common/src/directives/ng_class.ts b/packages/common/src/directives/ng_class.ts index 8b8c69d3b3fcf..9c9d815b18de8 100644 --- a/packages/common/src/directives/ng_class.ts +++ b/packages/common/src/directives/ng_class.ts @@ -37,7 +37,10 @@ type NgClassSupportedTypes = string[]|Set|{[klass: string]: any}|null|un * * @publicApi */ -@Directive({selector: '[ngClass]'}) +@Directive({ + selector: '[ngClass]', + standalone: true, +}) export class NgClass implements DoCheck { private _iterableDiffer: IterableDiffer|null = null; private _keyValueDiffer: KeyValueDiffer|null = null; diff --git a/packages/common/src/directives/ng_component_outlet.ts b/packages/common/src/directives/ng_component_outlet.ts index 15060c109181f..4f5fb64dbc623 100644 --- a/packages/common/src/directives/ng_component_outlet.ts +++ b/packages/common/src/directives/ng_component_outlet.ts @@ -68,7 +68,10 @@ import {ComponentRef, createNgModuleRef, Directive, Injector, Input, NgModuleFac * @publicApi * @ngModule CommonModule */ -@Directive({selector: '[ngComponentOutlet]'}) +@Directive({ + selector: '[ngComponentOutlet]', + standalone: true, +}) export class NgComponentOutlet implements OnChanges, OnDestroy { @Input() ngComponentOutlet: Type|null = null; diff --git a/packages/common/src/directives/ng_for_of.ts b/packages/common/src/directives/ng_for_of.ts index 32bbb2cb2108f..e0938ac1eb2d4 100644 --- a/packages/common/src/directives/ng_for_of.ts +++ b/packages/common/src/directives/ng_for_of.ts @@ -129,7 +129,10 @@ export class NgForOfContext = NgIterable> { * @ngModule CommonModule * @publicApi */ -@Directive({selector: '[ngFor][ngForOf]'}) +@Directive({ + selector: '[ngFor][ngForOf]', + standalone: true, +}) export class NgForOf = NgIterable> implements DoCheck { /** * The value of the iterable expression, which can be used as a diff --git a/packages/common/src/directives/ng_if.ts b/packages/common/src/directives/ng_if.ts index fec23963eeed2..830d63c2f7469 100644 --- a/packages/common/src/directives/ng_if.ts +++ b/packages/common/src/directives/ng_if.ts @@ -148,7 +148,10 @@ import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef, ɵstri * @ngModule CommonModule * @publicApi */ -@Directive({selector: '[ngIf]'}) +@Directive({ + selector: '[ngIf]', + standalone: true, +}) export class NgIf { private _context: NgIfContext = new NgIfContext(); private _thenTemplateRef: TemplateRef>|null = null; diff --git a/packages/common/src/directives/ng_plural.ts b/packages/common/src/directives/ng_plural.ts index fbd824472411c..3e40841a37ca6 100644 --- a/packages/common/src/directives/ng_plural.ts +++ b/packages/common/src/directives/ng_plural.ts @@ -44,7 +44,10 @@ import {SwitchView} from './ng_switch'; * * @publicApi */ -@Directive({selector: '[ngPlural]'}) +@Directive({ + selector: '[ngPlural]', + standalone: true, +}) export class NgPlural { // TODO(issue/24571): remove '!'. private _switchValue!: number; @@ -104,7 +107,10 @@ export class NgPlural { * * @publicApi */ -@Directive({selector: '[ngPluralCase]'}) +@Directive({ + selector: '[ngPluralCase]', + standalone: true, +}) export class NgPluralCase { constructor( @Attribute('ngPluralCase') public value: string, template: TemplateRef, diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index e58b3a89c587f..c73be426495a6 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -44,7 +44,10 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChanges, KeyValueDiffer, * * @publicApi */ -@Directive({selector: '[ngStyle]'}) +@Directive({ + selector: '[ngStyle]', + standalone: true, +}) export class NgStyle implements DoCheck { private _ngStyle: {[key: string]: string}|null = null; private _differ: KeyValueDiffer|null = null; diff --git a/packages/common/src/directives/ng_switch.ts b/packages/common/src/directives/ng_switch.ts index a17aa58392d54..a0cba16afb1f5 100644 --- a/packages/common/src/directives/ng_switch.ts +++ b/packages/common/src/directives/ng_switch.ts @@ -101,7 +101,10 @@ export class SwitchView { * @see [Structural Directives](guide/structural-directives) * */ -@Directive({selector: '[ngSwitch]'}) +@Directive({ + selector: '[ngSwitch]', + standalone: true, +}) export class NgSwitch { // TODO(issue/24571): remove '!'. private _defaultViews!: SwitchView[]; @@ -189,7 +192,10 @@ export class NgSwitch { * @see `NgSwitchDefault` * */ -@Directive({selector: '[ngSwitchCase]'}) +@Directive({ + selector: '[ngSwitchCase]', + standalone: true, +}) export class NgSwitchCase implements DoCheck { private _view: SwitchView; /** @@ -231,7 +237,10 @@ export class NgSwitchCase implements DoCheck { * @see `NgSwitchCase` * */ -@Directive({selector: '[ngSwitchDefault]'}) +@Directive({ + selector: '[ngSwitchDefault]', + standalone: true, +}) export class NgSwitchDefault { constructor( viewContainer: ViewContainerRef, templateRef: TemplateRef, diff --git a/packages/common/src/directives/ng_template_outlet.ts b/packages/common/src/directives/ng_template_outlet.ts index ebb2a951b081e..bc77de6372008 100644 --- a/packages/common/src/directives/ng_template_outlet.ts +++ b/packages/common/src/directives/ng_template_outlet.ts @@ -32,7 +32,10 @@ import {Directive, EmbeddedViewRef, Injector, Input, OnChanges, SimpleChanges, T * * @publicApi */ -@Directive({selector: '[ngTemplateOutlet]'}) +@Directive({ + selector: '[ngTemplateOutlet]', + standalone: true, +}) export class NgTemplateOutlet implements OnChanges { private _viewRef: EmbeddedViewRef|null = null; diff --git a/packages/common/test/directives/ng_class_spec.ts b/packages/common/test/directives/ng_class_spec.ts index 66bd7b93dfe7c..353e272244068 100644 --- a/packages/common/test/directives/ng_class_spec.ts +++ b/packages/common/test/directives/ng_class_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {NgClass} from '@angular/common'; import {Component} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; @@ -391,6 +392,23 @@ import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; expect(leading.className).toBe('foo'); expect(trailing.className).toBe('foo'); }); + + it('should be available as a standalone directive', () => { + @Component({ + selector: 'test-component', + imports: [NgClass], + template: `
`, + standalone: true, + }) + class TestComponent { + applyClasses = true; + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expect(fixture.nativeElement.firstChild.className).toBe('foo'); + }); }); }); } diff --git a/packages/common/test/directives/ng_component_outlet_spec.ts b/packages/common/test/directives/ng_component_outlet_spec.ts index 854c85e27ff67..e1d08c7a13156 100644 --- a/packages/common/test/directives/ng_component_outlet_spec.ts +++ b/packages/common/test/directives/ng_component_outlet_spec.ts @@ -267,6 +267,32 @@ describe('insert/remove', () => { expect(fixture.nativeElement).toHaveText('Value: child'); })); + + it('should be available as a standalone directive', () => { + @Component({ + standalone: true, + template: 'Hello World', + }) + class HelloWorldComp { + } + + @Component({ + selector: 'test-component', + imports: [NgComponentOutlet], + template: ` + + `, + standalone: true, + }) + class TestComponent { + component = HelloWorldComp; + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expect(fixture.nativeElement.textContent).toBe('Hello World'); + }); }); const TEST_TOKEN = new InjectionToken('TestToken'); diff --git a/packages/common/test/directives/ng_for_spec.ts b/packages/common/test/directives/ng_for_spec.ts index 549010ff8aee8..20e84b6a8bd14 100644 --- a/packages/common/test/directives/ng_for_spec.ts +++ b/packages/common/test/directives/ng_for_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule} from '@angular/common'; +import {CommonModule, NgForOf} from '@angular/common'; import {Component} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; @@ -380,6 +380,25 @@ let thisArg: any; detectChangesAndExpectText('efh'); })); }); + + it('should be available as a standalone directive', () => { + @Component({ + selector: 'test-component', + imports: [NgForOf], + template: ` + {{ item }}| + `, + standalone: true, + }) + class TestComponent { + items = [1, 2, 3]; + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expect(fixture.nativeElement.textContent).toBe('1|2|3|'); + }); }); } diff --git a/packages/common/test/directives/ng_if_spec.ts b/packages/common/test/directives/ng_if_spec.ts index 01f5d1e5a198f..1839d76b6d458 100644 --- a/packages/common/test/directives/ng_if_spec.ts +++ b/packages/common/test/directives/ng_if_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule, ɵgetDOM as getDOM} from '@angular/common'; +import {CommonModule, NgIf, ɵgetDOM as getDOM} from '@angular/common'; import {Component} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; @@ -250,6 +250,26 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('false'); })); + + it('should be available as a standalone directive', () => { + @Component({ + selector: 'test-component', + imports: [NgIf], + template: ` +
Hello
+
World
+ `, + standalone: true, + }) + class TestComponent { + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expect(fixture.nativeElement.textContent).toBe('Hello'); + expect(fixture.nativeElement.textContent).not.toBe('World'); + }); }); describe('Type guarding', () => { diff --git a/packages/common/test/directives/ng_plural_spec.ts b/packages/common/test/directives/ng_plural_spec.ts index 7d6ab99295035..a383cb4365a06 100644 --- a/packages/common/test/directives/ng_plural_spec.ts +++ b/packages/common/test/directives/ng_plural_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule, NgLocalization} from '@angular/common'; +import {CommonModule, NgLocalization, NgPlural, NgPluralCase} from '@angular/common'; import {Component, Injectable} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -138,6 +138,26 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; detectChangesAndExpectText('you have a few messages.'); })); }); + + it('should be available as a standalone directive', () => { + @Component({ + selector: 'test-component', + imports: [NgPlural, NgPluralCase], + template: '
    ' + + '
  • no messages
  • ' + + '
  • one message
  • ' + + '
', + standalone: true, + }) + class TestComponent { + switchValue = 1; + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expect(fixture.nativeElement.textContent).toBe('one message'); + }); } @Injectable() diff --git a/packages/common/test/directives/ng_style_spec.ts b/packages/common/test/directives/ng_style_spec.ts index 0d7db4e50e017..d0e0de300ba7f 100644 --- a/packages/common/test/directives/ng_style_spec.ts +++ b/packages/common/test/directives/ng_style_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule} from '@angular/common'; +import {CommonModule, NgStyle} from '@angular/common'; import {Component} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; @@ -210,6 +210,23 @@ import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; const target: HTMLElement = fixture.nativeElement.querySelector('div'); expect(getComputedStyle(target).getPropertyValue('width')).toEqual('100px'); }); + + it('should be available as a standalone directive', () => { + @Component({ + selector: 'test-component', + imports: [NgStyle], + template: `
`, + standalone: true, + }) + class TestComponent { + expr = 400; + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expectNativeEl(fixture).toHaveCssStyle({'width': '400px'}); + }); }); } diff --git a/packages/common/test/directives/ng_switch_spec.ts b/packages/common/test/directives/ng_switch_spec.ts index a0498d227ec3b..f7148cabfd434 100644 --- a/packages/common/test/directives/ng_switch_spec.ts +++ b/packages/common/test/directives/ng_switch_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule} from '@angular/common'; +import {CommonModule, NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common'; import {Attribute, Component, Directive, TemplateRef, ViewChild,} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -121,6 +121,33 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); }); + it('should be available as standalone directives', () => { + @Component({ + selector: 'test-component', + imports: [NgSwitch, NgSwitchCase, NgSwitchDefault], + template: '
    ' + + '
  • when a
  • ' + + '
  • when default
  • ' + + '
', + standalone: true, + }) + class TestComponent { + switchValue = 'a'; + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('when a'); + + fixture.componentInstance.switchValue = 'b'; + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('when default'); + + fixture.componentInstance.switchValue = 'c'; + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('when default'); + }); + describe('corner cases', () => { it('should not create the default case if another case matches', () => { const log: string[] = []; diff --git a/packages/common/test/directives/ng_template_outlet_spec.ts b/packages/common/test/directives/ng_template_outlet_spec.ts index 561d79dc81360..785cccbdaf37c 100644 --- a/packages/common/test/directives/ng_template_outlet_spec.ts +++ b/packages/common/test/directives/ng_template_outlet_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule} from '@angular/common'; +import {CommonModule, NgTemplateOutlet} from '@angular/common'; import {Component, ContentChildren, Directive, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, OnDestroy, Provider, QueryList, TemplateRef} from '@angular/core'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -299,6 +299,25 @@ describe('NgTemplateOutlet', () => { Injector.create({providers: [{provide: templateToken, useValue: 'world'}]}); detectChangesAndExpectText('Hello world'); })); + + it('should be available as a standalone directive', () => { + @Component({ + selector: 'test-component', + imports: [NgTemplateOutlet], + template: ` + Hello World + + `, + standalone: true, + }) + class TestComponent { + } + + const fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + expect(fixture.nativeElement.textContent).toBe('Hello World'); + }); }); const templateToken = new InjectionToken('templateToken');