Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit ffc3b51

Browse files
rkirovchirayuk
authored andcommitted
feat(ScopeAware): introduce ScopeAware abstract class
Components that implement the ScopeAware scope setter, will get scope set during compilation. Currently, there is little incentive to use this, because Scope can be injected in the Components. However, after PR/1269 Scope would not be injectable and this would be the only way for components to obtain scope. Introducing this API earlier allows for clients to start using it and not break when PR/1269 lands. Closes #1360
1 parent c90fe06 commit ffc3b51

File tree

6 files changed

+56
-1
lines changed

6 files changed

+56
-1
lines changed

lib/core/module.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export "package:angular/core/module_internal.dart" show
7777
PrototypeMap,
7878
RootScope,
7979
Scope,
80+
ScopeAware,
8081
ScopeDigestTTL,
8182
ScopeEvent,
8283
ScopeStats,

lib/core/scope.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,36 @@ class ScopeLocals implements Map {
109109
dynamic putIfAbsent(key, fn) => _scope.putIfAbsent(key, fn);
110110
}
111111

112+
/**
113+
* When a [Component] or the root context class implements [ScopeAware] the scope setter will be
114+
* called to set the [Scope] on this component.
115+
*
116+
* Typically classes implementing [ScopeAware] will declare a `Scope scope` property which will get
117+
* initialized after the [Scope] is available. For this reason the `scope` property will not be
118+
* initialized during the execution of the constructor - it will be immediately after.
119+
*
120+
* However, if you need to execute some code as soon as the scope is available you should implement
121+
* a `scope` setter:
122+
*
123+
* @Component(...)
124+
* class MyComponent implements ScopeAware {
125+
* Watch watch;
126+
*
127+
* MyComponent(Dependency myDep) {
128+
* // It is an error to add a Scope / RootScope argument to the ctor and will result in a DI
129+
* // circular dependency error - the scope is never accessible in the class constructor
130+
* }
131+
*
132+
* void set scope(Scope scope) {
133+
* // This setter gets called to initialize the scope
134+
* watch = scope.rootScope.watch("expression", (v, p) => ...);
135+
* }
136+
* }
137+
*/
138+
abstract class ScopeAware {
139+
void set scope(Scope scope);
140+
}
141+
112142
/**
113143
* [Scope] represents a collection of [watch]es [observer]s, and a [context] for the watchers,
114144
* observers and [eval]uations. Scopes structure loosely mimics the DOM structure. Scopes and

lib/core_dom/shadow_dom_component_factory.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
170170
}
171171

172172
var controller = shadowInjector.getByKey(_ref.typeKey);
173+
if (controller is ScopeAware) controller.scope = shadowScope;
173174
BoundComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
174175
shadowScope.context[_component.publishAs] = controller;
175176

lib/core_dom/transcluding_component_factory.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ class BoundTranscludingComponentFactory implements BoundComponentFactory {
153153

154154
var controller = childInjector.getByKey(_ref.typeKey);
155155
shadowScope.context[component.publishAs] = controller;
156+
shadowScope.context[component.publishAs] = controller;
157+
if (controller is ScopeAware) controller.scope = shadowScope;
156158
BoundComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
157159
return controller;
158160
};

test/angular_spec.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ main() {
152152
"angular.core_internal.Interpolate",
153153
"angular.core_internal.RootScope",
154154
"angular.core_internal.Scope",
155+
"angular.core_internal.ScopeAware",
155156
"angular.core_internal.ScopeDigestTTL",
156157
"angular.core_internal.ScopeEvent",
157158
"angular.core_internal.ScopeStats",

test/core_dom/compiler_spec.dart

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ void main() {
7878
..bind(MyChildController)
7979
..bind(MyScopeModifyingController)
8080
..bind(SameNameDecorator)
81-
..bind(SameNameTransclude);
81+
..bind(SameNameTransclude)
82+
..bind(ScopeAwareComponent);
8283
});
8384

8485
beforeEach((TestBed tb) => _ = tb);
@@ -928,6 +929,14 @@ void main() {
928929

929930
expect(element.text).toContain('my data');
930931
});
932+
933+
it('should call scope setter on ScopeAware components', async((TestBed _, Logger log) {
934+
var element = _.compile('<scope-aware-cmp></scope-aware-cmp>');
935+
936+
_.rootScope.apply();
937+
938+
expect(log.result()).toEqual('Scope set');
939+
}));
931940
});
932941

933942

@@ -1392,3 +1401,14 @@ class SameNameDecorator {
13921401
scope.context['sameDecorator'] = this;
13931402
}
13941403
}
1404+
1405+
@Component(
1406+
selector: 'scope-aware-cmp'
1407+
)
1408+
class ScopeAwareComponent implements ScopeAware {
1409+
Logger log;
1410+
ScopeAwareComponent(this.log) {}
1411+
void set scope(Scope scope) {
1412+
log('Scope set');
1413+
}
1414+
}

0 commit comments

Comments
 (0)