Skip to content

Commit 58e110d

Browse files
committed
ngScope directive
1 parent e43a417 commit 58e110d

File tree

10 files changed

+133
-9
lines changed

10 files changed

+133
-9
lines changed

src/angular.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ export class Angular {
216216
* @param {ng.InjectorService} $injector
217217
*/
218218
(scope, el, compile, $injector) => {
219+
this.$rootScope = scope;
219220
// ng-route deps
220221
this.$injector = $injector; // TODO refactor away as this as this prevents multiple apps from being used
221222

@@ -297,6 +298,17 @@ export class Angular {
297298
this.bootstrap(appElement, module ? [module] : [], config);
298299
}
299300
}
301+
302+
/**
303+
* @param {string} name
304+
* @returns {ProxyHandler<ng.Scope>}
305+
*/
306+
getNamedScope(name) {
307+
const scope = this.$rootScope.$searchByName(name);
308+
if (scope) {
309+
return scope.$proxy;
310+
}
311+
}
300312
}
301313

302314
/**

src/angular.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ describe("module loader", () => {
271271
expect(myModule2).not.toBe(gotModule);
272272
});
273273

274-
it("allows creates an instance on NgModule", () => {
274+
it("creates an instance on NgModule", () => {
275275
angular.module("myModule", []);
276276
const gotModule = angular.module("myModule");
277277
expect(gotModule).toBeInstanceOf(NgModule);

src/core/controller/controller.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class ControllerProvider {
7070
"$injector",
7171

7272
/**
73-
* @param {import("../../core/di/internal-injector.js").InjectorService} $injector
73+
* @param {ng.InjectorService} $injector
7474
* @returns {import("./interface.ts").ControllerService} A service function that creates controllers.
7575
*/
7676
($injector) => {

src/core/di/ng-module/ng-module.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ describe("NgModule", () => {
1818
it("can be instantiated", () => {
1919
expect(ngModule).toBeDefined();
2020
expect(ngModule.name).toBeDefined();
21+
expect(ngModule.name).toEqual("test");
2122
expect(ngModule.requires).toEqual(["otherModule"]);
2223
});
2324

src/core/scope/scope.js

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ let $exceptionHandler;
3535

3636
export const $postUpdateQueue = [];
3737

38+
export let rootScope;
39+
3840
export class RootScopeProvider {
3941
constructor() {
40-
this.rootScope = createScope();
42+
rootScope = this.rootScope = createScope();
4143
}
4244

4345
$get = [
@@ -239,6 +241,8 @@ export class Scope {
239241

240242
this.scheduled = [];
241243

244+
this.$scopename = undefined;
245+
242246
/** @private */
243247
this.propertyMap = {
244248
$watch: this.$watch.bind(this),
@@ -250,18 +254,20 @@ export class Scope {
250254
$apply: this.$apply.bind(this),
251255
$postUpdate: this.$postUpdate.bind(this),
252256
$isRoot: this.#isRoot.bind(this),
253-
$proxy: this.$proxy,
254257
$on: this.$on.bind(this),
255258
$emit: this.$emit.bind(this),
256259
$broadcast: this.$broadcast.bind(this),
257260
$transcluded: this.$transcluded.bind(this),
258261
$handler: /** @type {Scope} */ (this),
262+
$merge: this.$merge.bind(this),
263+
$getById: this.$getById.bind(this),
264+
$searchByName: this.$searchByName.bind(this),
265+
$proxy: this.$proxy,
259266
$parent: this.$parent,
260267
$root: this.$root,
261268
$children: this.$children,
262269
$id: this.$id,
263-
$merge: this.$merge.bind(this),
264-
$getById: this.$getById.bind(this),
270+
$scopename: this.$scopename,
265271
};
266272
}
267273

@@ -277,8 +283,14 @@ export class Scope {
277283
*/
278284
set(target, property, value, proxy) {
279285
if (property === "undefined") {
280-
throw new Error("Attempting to set undefined property");
286+
return false;
287+
}
288+
289+
if (property === "$scopename") {
290+
this.$scopename = value;
291+
return true;
281292
}
293+
282294
if (
283295
(target.constructor?.$nonscope &&
284296
Array.isArray(target.constructor.$nonscope) &&
@@ -496,9 +508,9 @@ export class Scope {
496508
* @returns {*} - The value of the property or a method if accessing `watch` or `sync`.
497509
*/
498510
get(target, property, proxy) {
511+
if (property === "$scopename" && this.$scopename) return this.$scopename;
499512
if (property === "$$watchersCount") return calculateWatcherCount(this);
500513
if (property === isProxySymbol) return true;
501-
502514
if (target[property] && isProxy(target[property])) {
503515
this.$proxy = target[property];
504516
} else {
@@ -527,7 +539,6 @@ export class Scope {
527539
this.#scheduleListener(this.scheduled);
528540
}
529541
}
530-
531542
if (hasOwn(this.propertyMap, property)) {
532543
this.$target = target;
533544
return this.propertyMap[property];
@@ -1272,6 +1283,26 @@ export class Scope {
12721283
return res;
12731284
}
12741285
}
1286+
1287+
$searchByName(name) {
1288+
const getByName = (scope, name) => {
1289+
if (scope.$scopename === name) {
1290+
return scope;
1291+
} else {
1292+
let res = undefined;
1293+
for (const child of scope.$children) {
1294+
let found = getByName(child, name);
1295+
if (found) {
1296+
res = found;
1297+
break;
1298+
}
1299+
}
1300+
return res;
1301+
}
1302+
};
1303+
1304+
return getByName(this.$root, name);
1305+
}
12751306
}
12761307

12771308
/*------------- Private helpers -------------*/

src/directive/scope/scope.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>AngularTS Test Runner</title>
6+
7+
<link rel="shortcut icon" type="image/png" href="/images/favicon.ico" />
8+
<link rel="stylesheet" href="/jasmine/jasmine.css" />
9+
<link rel="stylesheet" href="/public/jasmine-helper.css" />
10+
<script src="/jasmine/jasmine.js"></script>
11+
<script src="/jasmine/jasmine-html.js"></script>
12+
<script src="/jasmine/boot0.js"></script>
13+
<script src="/jasmine/boot1.js"></script>
14+
<script type="module" src="/src/directive/scope/scope.spec.js"></script>
15+
</head>
16+
<body>
17+
<div id="app"></div>
18+
</body>
19+
</html>

src/directive/scope/scope.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @return {ng.Directive}
3+
*/
4+
export function ngScopeDirective() {
5+
return {
6+
scope: false,
7+
async link($scope, _, $attrs) {
8+
$scope.$scopename = $attrs.ngScope;
9+
},
10+
};
11+
}

src/directive/scope/scope.spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Angular } from "../../angular.js";
2+
import { dealoc } from "../../shared/dom.js";
3+
4+
describe("ngScopeDirective", () => {
5+
let $compile, $rootScope;
6+
7+
beforeEach(() => {
8+
window.angular = new Angular();
9+
window.angular.module("test", []);
10+
dealoc(document.getElementById("app"));
11+
let injector = window.angular.bootstrap(document.getElementById("app"), [
12+
"test",
13+
]);
14+
injector.invoke((_$compile_, _$rootScope_) => {
15+
$compile = _$compile_;
16+
$rootScope = _$rootScope_;
17+
});
18+
});
19+
20+
it("should set $scope.$scopename from the ng-scope attribute", async () => {
21+
const scope = $rootScope.$new();
22+
$compile('<div ng-scope="myName"></div>')(scope);
23+
24+
expect(scope.$scopename).toBe("myName");
25+
});
26+
27+
it("should not create an isolate scope", () => {
28+
const scope = $rootScope.$new();
29+
scope.testVal = 42;
30+
31+
const element = $compile('<div ng-scope="x"></div>')(scope);
32+
33+
expect(window.angular.getScope(element)).toBe(scope); // same scope
34+
expect(window.angular.getScope(element).testVal).toBe(42);
35+
});
36+
});

src/directive/scope/scope.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
const TEST_URL = "src/directive/scope/scope.html";
4+
5+
test("unit tests contain no errors", async ({ page }) => {
6+
await page.goto(TEST_URL);
7+
await page.content();
8+
await page.waitForTimeout(1000);
9+
await expect(page.locator(".jasmine-overall-result")).toHaveText(
10+
/ 0 failures/,
11+
);
12+
});

src/ng.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ import { SseProvider } from "./services/sse/sse.js";
135135
import { ngViewportDirective } from "./directive/viewport/viewport.js";
136136
import { ngWorkerDirective } from "./directive/worker/worker.js";
137137
import { ngWasmDirective } from "./directive/wasm/wasm.js";
138+
import { ngScopeDirective } from "./directive/scope/scope.js";
138139

139140
/**
140141
* Initializes core `ng` module.
@@ -217,6 +218,7 @@ export function registerNgModule(angular) {
217218
ngViewport: ngViewportDirective,
218219
ngWasm: ngWasmDirective,
219220
ngWorker: ngWorkerDirective,
221+
ngScope: ngScopeDirective,
220222
})
221223
.directive({
222224
input: hiddenInputBrowserCacheDirective,

0 commit comments

Comments
 (0)