fix(ivy): support ICUs with pipes (#34198)

Prior to this commit, i18n runtime code failed with the exception saying that no provider was found for ChangeDetectorRef for a pipe used in ICU. The problem happened because the underlying `createViewRef` function was not taking into account IcuContainer as a valid TNodeType. This commit updates the `createViewRef` function to return corresponding ViewRef for TNodeType.IcuContainer.

PR Close #34198
This commit is contained in:
Andrew Kushnir 2019-12-02 13:58:32 -08:00 committed by Miško Hevery
parent e315215983
commit 60b13d9948
2 changed files with 38 additions and 2 deletions

View File

@ -408,7 +408,7 @@ function createViewRef(tNode: TNode, lView: LView, isPipe: boolean): ViewEngine_
return new ViewRef(componentView, componentView); return new ViewRef(componentView, componentView);
} else if ( } else if (
tNode.type === TNodeType.Element || tNode.type === TNodeType.Container || tNode.type === TNodeType.Element || tNode.type === TNodeType.Container ||
tNode.type === TNodeType.ElementContainer) { tNode.type === TNodeType.ElementContainer || tNode.type === TNodeType.IcuContainer) {
// The LView represents the location where the injection is requested from. // The LView represents the location where the injection is requested from.
// We need to locate the containing LView (in case where the `lView` is an embedded view) // We need to locate the containing LView (in case where the `lView` is an embedded view)
const hostComponentView = lView[DECLARATION_COMPONENT_VIEW]; // look up const hostComponentView = lView[DECLARATION_COMPONENT_VIEW]; // look up

View File

@ -8,7 +8,7 @@
// Make the `$localize()` global function available to the compiled templates, and the direct calls // Make the `$localize()` global function available to the compiled templates, and the direct calls
// below. This would normally be done inside the application `polyfills.ts` file. // below. This would normally be done inside the application `polyfills.ts` file.
import '@angular/localize/init'; import '@angular/localize/init';
import {registerLocaleData} from '@angular/common'; import {CommonModule, registerLocaleData} from '@angular/common';
import localeRo from '@angular/common/locales/ro'; import localeRo from '@angular/common/locales/ro';
import {Component, ContentChild, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, Pipe, PipeTransform, NO_ERRORS_SCHEMA} from '@angular/core'; import {Component, ContentChild, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, Pipe, PipeTransform, NO_ERRORS_SCHEMA} from '@angular/core';
import {setDelayProjection} from '@angular/core/src/render3/instructions/projection'; import {setDelayProjection} from '@angular/core/src/render3/instructions/projection';
@ -18,6 +18,7 @@ import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {onlyInIvy} from '@angular/private/testing'; import {onlyInIvy} from '@angular/private/testing';
import {computeMsgId} from '@angular/compiler'; import {computeMsgId} from '@angular/compiler';
import {BehaviorSubject} from 'rxjs';
onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
@ -1198,6 +1199,41 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
// check that nested ICU is removed if root ICU case has changed // check that nested ICU is removed if root ICU case has changed
expect(fixture.nativeElement.textContent.trim()).toBe('-'); expect(fixture.nativeElement.textContent.trim()).toBe('-');
}); });
it('should support ICUs with pipes', () => {
loadTranslations({
idA: '{VAR_SELECT, select, 1 {{INTERPOLATION} article} 2 {deux articles}}',
});
@Component({
selector: 'app',
template: `
<div i18n="@@idA">{count$ | async, select, 1 {{{count$ | async}} item} 2 {two items}}</div>
`
})
class AppComponent {
count$ = new BehaviorSubject<number>(1);
}
TestBed.configureTestingModule({
imports: [CommonModule],
declarations: [AppComponent],
});
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toBe('1 article');
fixture.componentInstance.count$.next(3);
fixture.detectChanges();
// there is no ICU case for count=3, expecting empty content
expect(fixture.nativeElement.textContent.trim()).toBe('');
fixture.componentInstance.count$.next(2);
fixture.detectChanges();
// checking the second ICU case
expect(fixture.nativeElement.textContent.trim()).toBe('deux articles');
});
}); });
describe('should support attributes', () => { describe('should support attributes', () => {