
This commit fixes a bug in which we do testing for completions. Subsequently, this exposes another bug in our implementation whereby suggestions are not provided in "ngFor" where there should have been. Currently, multiple test cases are grouped together in a single template. This requires the template to be somewhat complete so that test cases that depend on variables declared earlier would pass. Consider the following example: ``` template: ` <div *ngFor="let ~{for-person}person of ~{for-people}people"> <span>Name: {{~{for-interp-person}person.~{for-interp-name}name}}</span> <span>Age: {{person.~{for-interp-age}age}}</span> </div>`, ``` In order to test `~{for-interp-person}`, `people` has to be included after `~{for-people}`. This means the test case for `~{for-people}` is not reflective of the actual use case because the variable is already there! In real case, the expression would be incomplete, and our implementation failed to take that into account. This commit breaks such test into individual tests, and fix the bugs in the underlying implementation. PR Close #34473
166 lines
3.5 KiB
TypeScript
166 lines
3.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {Component, Directive, EventEmitter, Input, Output} from '@angular/core';
|
|
|
|
import {Hero} from './app.component';
|
|
|
|
@Component({
|
|
template: `
|
|
<h1>
|
|
Some <~{incomplete-open-lt}a~{incomplete-open-a} ~{incomplete-open-attr} text
|
|
</h1>`,
|
|
})
|
|
export class CaseIncompleteOpen {
|
|
}
|
|
|
|
@Component({
|
|
template: '<h1>Some <a> ~{missing-closing} text</h1>',
|
|
})
|
|
export class CaseMissingClosing {
|
|
}
|
|
|
|
@Component({
|
|
template: '<h1>Some <unknown ~{unknown-element}> text</h1>',
|
|
})
|
|
export class CaseUnknown {
|
|
}
|
|
|
|
@Component({
|
|
template: '<h1>{{data | ~{before-pipe}lowe~{in-pipe}rcase~{after-pipe} }}',
|
|
})
|
|
export class Pipes {
|
|
data = 'Some string';
|
|
}
|
|
|
|
@Component({
|
|
template: '<h1 h~{no-value-attribute}></h1>',
|
|
})
|
|
export class NoValueAttribute {
|
|
}
|
|
|
|
|
|
@Component({
|
|
template: '<h1 model="~{attribute-binding-model}test"></h1>',
|
|
})
|
|
export class AttributeBinding {
|
|
test: string = 'test';
|
|
}
|
|
|
|
@Component({
|
|
template: '<h1 [model]="~{property-binding-model}test"></h1>',
|
|
})
|
|
export class PropertyBinding {
|
|
test: string = 'test';
|
|
}
|
|
|
|
@Component({
|
|
template: '<h1 (model)="~{event-binding-model}modelChanged()"></h1>',
|
|
})
|
|
export class EventBinding {
|
|
test: string = 'test';
|
|
|
|
modelChanged() {}
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<h1 [(model)]="~{two-way-binding-model}test"></h1>
|
|
<input ~{two-way-binding-input}></input>`,
|
|
})
|
|
export class TwoWayBinding {
|
|
test: string = 'test';
|
|
}
|
|
|
|
@Directive({
|
|
selector: '[string-model]',
|
|
})
|
|
export class StringModel {
|
|
@Input() model: string = 'model';
|
|
@Output() modelChange: EventEmitter<string> = new EventEmitter();
|
|
}
|
|
|
|
@Directive({
|
|
selector: '[number-model]',
|
|
})
|
|
export class NumberModel {
|
|
@Input('inputAlias') model: number = 0;
|
|
@Output('outputAlias') modelChange: EventEmitter<number> = new EventEmitter();
|
|
}
|
|
|
|
interface Person {
|
|
name: string;
|
|
age: number;
|
|
street: string;
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<div *ngFor="let person of people | async">
|
|
{{person.~{async-person-name}name}}
|
|
</div>
|
|
<div *ngIf="promisedPerson | async as person">
|
|
{{person.~{promised-person-name}name}}
|
|
</div>
|
|
`,
|
|
})
|
|
export class AsyncForUsingComponent {
|
|
people: Promise<Person[]> = Promise.resolve([]);
|
|
promisedPerson: Promise<Person> = Promise.resolve({
|
|
name: 'John Doe',
|
|
age: 42,
|
|
street: '123 Angular Ln',
|
|
});
|
|
}
|
|
|
|
@Component({
|
|
template: `
|
|
<div #div>
|
|
<test-comp #test1>
|
|
{{~{test-comp-content}}}
|
|
{{test1.~{test-comp-after-test}name}}
|
|
{{div.~{test-comp-after-div}.innerText}}
|
|
</test-comp>
|
|
</div>
|
|
<test-comp #test2></test-comp>`,
|
|
})
|
|
export class References {
|
|
}
|
|
|
|
/*BeginTestComponent*/ @Component({
|
|
selector: 'test-comp',
|
|
template: '<div>Testing: {{name}}</div>',
|
|
})
|
|
export class TestComponent {
|
|
@Input('tcName') name = 'test';
|
|
@Output('test') testEvent = new EventEmitter();
|
|
} /*EndTestComponent*/
|
|
|
|
@Component({
|
|
templateUrl: 'test.ng',
|
|
})
|
|
export class TemplateReference {
|
|
title = 'Some title';
|
|
hero: Hero = {id: 1, name: 'Windstorm'};
|
|
heroes: Hero[] = [this.hero];
|
|
tupleArray: [string, Hero] = ['test', this.hero];
|
|
league: Hero[][] = [this.heroes];
|
|
heroesByName: {[name: string]: Hero} = {};
|
|
primitiveIndexType: {[name: string]: string} = {};
|
|
anyValue: any;
|
|
myClick(event: any) {}
|
|
}
|
|
|
|
@Component({
|
|
template: '{{~{empty-interpolation}}}',
|
|
})
|
|
export class EmptyInterpolation {
|
|
title = 'Some title';
|
|
subTitle = 'Some sub title';
|
|
}
|