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

Commit 181f014

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 9f55fbf commit 181f014

File tree

6 files changed

+55
-1
lines changed

6 files changed

+55
-1
lines changed

lib/core/module.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export "package:angular/core/module_internal.dart" show
7676
PrototypeMap,
7777
RootScope,
7878
Scope,
79+
ScopeAware,
7980
ScopeDigestTTL,
8081
ScopeEvent,
8182
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
@@ -187,6 +187,7 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
187187
}
188188

189189
var controller = shadowInjector.getByKey(_ref.typeKey);
190+
if (controller is ScopeAware) controller.scope = shadowScope;
190191
BoundComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
191192
shadowScope.context[_component.publishAs] = controller;
192193

lib/core_dom/transcluding_component_factory.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ class BoundTranscludingComponentFactory implements BoundComponentFactory {
122122

123123
var controller = childInjector.getByKey(_ref.typeKey);
124124
shadowScope.context[_component.publishAs] = controller;
125+
if (controller is ScopeAware) controller.scope = shadowScope;
125126
BoundComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
126127

127128
if (_viewFactoryFuture != null && _viewFactory == null) {

test/angular_spec.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ main() {
151151
"angular.core_internal.Interpolate",
152152
"angular.core_internal.RootScope",
153153
"angular.core_internal.Scope",
154+
"angular.core_internal.ScopeAware",
154155
"angular.core_internal.ScopeDigestTTL",
155156
"angular.core_internal.ScopeEvent",
156157
"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)