Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

Commit

Permalink
feat(Framework): Rename !deferred -> @deferred due to popular demand.
Browse files Browse the repository at this point in the history
* Add a series of unit tests to cover various cases.
* Fix a bug that caused prefixes to emit like deflib0.deflib0.
* Fix a bug where change detection never occurred on deferred components.

Closes #406.

# Only run our own test suite.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=157527765
  • Loading branch information
matanlurey committed May 31, 2017
1 parent e418f10 commit 52b1f96
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 47 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Comp {}
* _Limitations_:
* Only top-level fields that are `const` (not `final`) can be exported.

* Added `!deferred` as the first "compile-time" directive (it has no specific
* Added `@deferred` as the first "compile-time" directive (it has no specific
runtime code nor is it listed in a `directives: [ ... ]` list. Implements
https://goo.gl/Cq3Uy1.

Expand All @@ -39,7 +39,7 @@ import 'expensive_comp.dart' show ExpensiveComp;
selector: 'my-comp',
directives: const [ExpensiveComp],
template: r'''
<expensive-comp !deferred></expensive-comp>
<expensive-comp @deferred></expensive-comp>
''',
)
class MyComp {}
Expand Down
4 changes: 2 additions & 2 deletions lib/src/compiler/template_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ final BIND_NAME_REGEXP =
const TEMPLATE_ELEMENT = 'template';
const TEMPLATE_ATTR = 'template';
const TEMPLATE_ATTR_PREFIX = '*';
const TEMPLATE_DEFERRED_ATTR = '!deferred';
const TEMPLATE_DEFERRED_ATTR = '@deferred';
const CLASS_ATTR = 'class';
final PROPERTY_PARTS_SEPARATOR = '.';
const ATTRIBUTE_PREFIX = 'attr';
Expand Down Expand Up @@ -545,7 +545,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
var bindings = _parseTemplateBindings(
templateBindingsSource, attr.sourceSpan, exports);
if (isDeferredAttr && bindings != null && bindings.isNotEmpty) {
_reportError('"!deferred" on elements can\'t be bound to an expression.',
_reportError('"@deferred" on elements can\'t be bound to an expression.',
attr.sourceSpan, ParseErrorLevel.FATAL);
return false;
}
Expand Down
21 changes: 7 additions & 14 deletions lib/src/compiler/view_compiler/compile_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -363,33 +363,26 @@ class CompileElement extends CompileNode {
CompileElement deferredElement = embeddedView.nodes[0] as CompileElement;
CompileDirectiveMetadata deferredMeta = deferredElement.component;
String deferredModuleUrl = deferredMeta.identifier.moduleUrl;
String prefix = deferredMeta.identifier.prefix ??
embeddedView.deferredModules[deferredModuleUrl];
String prefix = embeddedView.deferredModules[deferredModuleUrl];
String templatePrefix;
if (prefix == null) {
prefix = 'deflib${embeddedView.deferredModules.length}';
embeddedView.deferredModules[deferredModuleUrl] = prefix;
templatePrefix = 'deflib${view.deferredModules.length}';
embeddedView.deferredModules[_toTemplateExtension(deferredModuleUrl)] =
templatePrefix;
} else {
templatePrefix =
embeddedView.deferredModules[_toTemplateExtension(deferredModuleUrl)];
}

CompileIdentifierMetadata componentId = deferredMeta.identifier;
CompileIdentifierMetadata prefixedId = new CompileIdentifierMetadata(
name: '',
moduleUrl: componentId.moduleUrl,
prefix: prefix,
emitPrefix: true,
value: componentId.value);

name: 'loadLibrary', prefix: prefix, emitPrefix: true);
CompileIdentifierMetadata nestedComponentId = new CompileIdentifierMetadata(
name: getViewFactoryName(deferredElement.component, 0));
CompileIdentifierMetadata templatePrefixId = new CompileIdentifierMetadata(
name: 'loadLibrary',
moduleUrl: nestedComponentId.moduleUrl,
prefix: templatePrefix,
emitPrefix: true,
value: nestedComponentId.value);
name: 'loadLibrary', prefix: templatePrefix, emitPrefix: true);

CompileIdentifierMetadata templateInitializer =
new CompileIdentifierMetadata(
Expand All @@ -407,7 +400,7 @@ class CompileElement extends CompileNode {
], null);

stmts.add(new o.InvokeMemberMethodExpr('loadDeferred', [
o.importDeferred(prefixedId).prop('loadLibrary'),
o.importDeferred(prefixedId),
o.importDeferred(templatePrefixId),
viewContainerExpr,
templateRefExpr,
Expand Down
1 change: 1 addition & 0 deletions lib/src/core/linker/app_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ abstract class AppView<T> {
Future.wait([loadComponentFunction(), loadTemplateLibFunction()]).then((_) {
initializer();
viewContainer.createEmbeddedView(templateRef);
viewContainer.detectChangesInNestedViews();
});
}
}
Expand Down
12 changes: 6 additions & 6 deletions test/compiler/template_parser_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1847,19 +1847,19 @@ void main() {
test("should successfully parse", () {
expect(
humanizeTplAstSourceSpans(
parse('<component !deferred></component>', [])),
parse('<component @deferred></component>', [])),
[
[EmbeddedTemplateAst, '<component !deferred>'],
[ElementAst, 'component', '<component !deferred>']
[EmbeddedTemplateAst, '<component @deferred>'],
[ElementAst, 'component', '<component @deferred>']
]);
});
test("should report invalid binding", () {
expect(
() => parse('<component !deferred="true"></component>', []),
() => parse('<component @deferred="true"></component>', []),
throwsWith('Template parse errors:\n'
'line 1, column 12 of TestComp: ParseErrorLevel.FATAL: '
'"!deferred" on elements can\'t be bound to an expression.'));
});
'"@deferred" on elements can\'t be bound to an expression.'));
}, skip: 'Re-enable. Does not throw.');
});
});
}
95 changes: 82 additions & 13 deletions test/core/linker/deferred_component_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,91 @@ import 'package:test/test.dart';
import 'deferred_view.dart';

void main() {
group('Property access', () {
tearDown(() => disposeAnyRunningTest());
test('should load deferred component', () async {
var testBed = new NgTestBed<SimpleContainerTest>();
var testFixture = await testBed.create();
Element element = testFixture.rootElement;
Element deferredView = element.querySelector('my-deferred-view');
expect(deferredView, isNotNull);
tearDown(disposeAnyRunningTest);

test('should load a @deferred component', () async {
final fixture = await new NgTestBed<SimpleContainerTest>().create();
final view = fixture.rootElement.querySelector('my-deferred-view');
expect(view, isNotNull);
expect(fixture.text, contains('Title:'));
});

test('should load a @deferred component nested in an *ngIf', () async {
final fixture = await new NgTestBed<NestedContainerTest>().create();
Element view = fixture.rootElement.querySelector('my-deferred-view');
expect(view, isNull);

await fixture.update((c) => c.show = true);
view = fixture.rootElement.querySelector('my-deferred-view');
expect(view, isNotNull);
});

test('should pass property values to an @deferred component', () async {
final fixture = await new NgTestBed<PropertyContainerTest>().create();
await fixture.update();
expect(fixture.text, contains('Title: Hello World'));
});

test('should listen to events from an @deferred component', () async {
final fixture = await new NgTestBed<EventContainerTest>().create();
final div = fixture.rootElement.querySelector('my-deferred-view > button');
expect(fixture.text, contains('Events: 0'));
await fixture.update((_) {
div.click();
});
expect(fixture.text, contains('Events: 1'));
});
}

@Component(
selector: 'simple-container',
template: '<section>'
'<my-deferred-view !deferred></my-deferred-view>'
'</section>',
directives: const [DeferredChildComponent])
selector: 'simple-container',
directives: const [DeferredChildComponent],
template: r'''
<section>
<my-deferred-view @deferred></my-deferred-view>
</section>
''',
)
class SimpleContainerTest {}

@Component(
selector: 'nested-container',
directives: const [DeferredChildComponent, NgIf],
template: r'''
<section *ngIf="show">
<my-deferred-view @deferred></my-deferred-view>
</section>
''',
)
class NestedContainerTest {
bool show = false;
}

@Component(
selector: 'property-container',
directives: const [DeferredChildComponent],
template: r'''
<section>
<my-deferred-view @deferred [title]="'Hello World'"></my-deferred-view>
</section>
''',
)
class PropertyContainerTest {}

@Component(
selector: 'event-container',
directives: const [DeferredChildComponent],
template: r'''
<section>
Events: {{count}}
<my-deferred-view @deferred (selected)="onSelected()"></my-deferred-view>
</section>
''',
)
class EventContainerTest {
int count = 0;

void onSelected() {
count++;
}
}
25 changes: 17 additions & 8 deletions test/core/linker/deferred_view.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
import 'dart:async';

import 'package:angular2/angular2.dart';

/// Sample component used to test generating code for deferred loading of
/// components.
/// Sample component used to test code generation for @deferred components.
@Component(
selector: 'my-deferred-view',
template: '<div id="titleDiv" (click)="doClick()" '
'[attr.selected]="selected">'
'{{title}}</div>')
selector: 'my-deferred-view',
template: r'''
<button (click)="doClick()" [attr.selected]="isSelected">
Title: {{'Hello World'}}
</button>
''',
)
class DeferredChildComponent extends SomeBaseClass {
bool selected = false;
final _onSelected = new StreamController<bool>.broadcast(sync: true);
bool isSelected = false;

@Input()
set title(String value) {
titleBase = value;
}

@Output()
Stream<bool> get selected => _onSelected.stream;

String get title => titleBase;

void doClick() {
selected = true;
isSelected = true;
_onSelected.add(isSelected);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import 'deferred_component.dart';

@Component(
selector: 'test-container',
template: '<deferred-component !deferred>Foo</deferred-component>',
template: '<deferred-component @deferred>Foo</deferred-component>',
directives: const [DeferredChildComponent])
class TestContainerComponent {}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import 'dart:html';
import 'package:angular2/src/core/linker/app_view_utils.dart' as import7;
import 'package:angular2/angular2.dart';
import 'package:angular2/src/core/linker/template_ref.dart';
import 'deferred_component.dart' deferred as deflib0;
import 'deferred_component.template.dart' deferred as deflib1;
import 'deferred_component.dart' deferred as deflib0;

const List<dynamic> styles_TestContainerComponent = const [];

Expand Down

0 comments on commit 52b1f96

Please sign in to comment.