diff --git a/docs/en/UI/Angular/Dom-Insertion-Service.md b/docs/en/UI/Angular/Dom-Insertion-Service.md
index d5ea9fe3a2..489a7a4e1f 100644
--- a/docs/en/UI/Angular/Dom-Insertion-Service.md
+++ b/docs/en/UI/Angular/Dom-Insertion-Service.md
@@ -35,17 +35,19 @@ class DemoComponent {
constructor(private domInsertionService: DomInsertionService) {}
ngOnInit() {
- this.domInsertionService.insertContent(
+ const scriptElement = this.domInsertionService.insertContent(
CONTENT_STRATEGY.AppendScriptToBody('alert()')
);
}
}
```
-In the example above, `` element will place at the **end** of `
`.
+In the example above, `` element will place at the **end** of `` and `scriptElement` will be an `HTMLScriptElement`.
Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy.
+> Important Note: `DomInsertionService` does not insert the same content twice. In order to add a content again, you first should remove the old content using `removeContent` method.
+
### How to Insert Styles
If you pass a `StyleContentStrategy` instance as the first parameter of `insertContent` method, the `DomInsertionService` will create a `` element will place at the **end** of ``.
+In the example above, `` element will place at the **end** of `` and `styleElement` will be an `HTMLStyleElement`.
Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy.
+> Important Note: `DomInsertionService` does not insert the same content twice. In order to add a content again, you first should remove the old content using `removeContent` method.
+
+### How to Remove Inserted Scripts & Styles
+
+If you pass the inserted `HTMLScriptElement` or `HTMLStyleElement` element as the first parameter of `removeContent` method, the `DomInsertionService` will remove the given element.
+
+```js
+import { DomInsertionService, CONTENT_STRATEGY } from '@abp/ng.core';
+
+@Component({
+ /* class metadata here */
+})
+class DemoComponent {
+ private styleElement: HTMLStyleElement;
+
+ constructor(private domInsertionService: DomInsertionService) {}
+
+ ngOnInit() {
+ this.styleElement = this.domInsertionService.insertContent(
+ CONTENT_STRATEGY.AppendStyleToHead('body {margin: 0;}')
+ );
+ }
+
+ ngOnDestroy() {
+ this.domInsertionService.removeContent(this.styleElement);
+ }
+}
+```
+
+In the example above, `` element **will be removed** from `` when the component is destroyed.
+
## API
### insertContent
```js
-insertContent(contentStrategy: ContentStrategy): void
+insertContent(
+ contentStrategy: ContentStrategy,
+): T
```
- `contentStrategy` parameter is the primary focus here and is explained above.
+- returns `HTMLScriptElement` or `HTMLStyleElement` based on given strategy.
+
+### removeContent
+
+```js
+removeContent(element: HTMLScriptElement | HTMLStyleElement): void
+```
+- `element` parameter is the inserted `HTMLScriptElement` or `HTMLStyleElement` element, which was returned by `insertContent` method.
## What's Next?
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
index c3434e6e27..1307644acd 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
@@ -55,7 +55,14 @@ namespace Volo.Abp.Cli.ProjectModification
if (IsAngularProject(fileDirectory))
{
- await CreateNpmrcFileAsync(Path.GetDirectoryName(file));
+ if (includePreviews)
+ {
+ await CreateNpmrcFileAsync(Path.GetDirectoryName(file));
+ }
+ else if (switchToStable)
+ {
+ await DeleteNpmrcFileAsync(Path.GetDirectoryName(file));
+ }
}
RunYarn(fileDirectory);
@@ -69,11 +76,21 @@ namespace Volo.Abp.Cli.ProjectModification
}
}
+ private async Task DeleteNpmrcFileAsync(string directoryName)
+ {
+ var fileName = Path.Combine(directoryName, ".npmrc");
+
+ if (File.Exists(fileName))
+ {
+ File.Delete(fileName);
+ }
+ }
+
private async Task CreateNpmrcFileAsync(string directoryName)
{
var fileName = Path.Combine(directoryName, ".npmrc");
- var abpRegistry = "@abp:registry:https://www.myget.org/F/abp-nightly/npm";
+ var abpRegistry = "@abp:registry=https://www.myget.org/F/abp-nightly/npm";
var voloRegistry = await GetVoloRegistryAsync();
if (File.Exists(fileName))
diff --git a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts
index d4b30b731d..71f59798ae 100644
--- a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts
+++ b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts
@@ -6,12 +6,23 @@ import { generateHash } from '../utils';
export class DomInsertionService {
readonly inserted = new Set();
- insertContent(contentStrategy: ContentStrategy) {
+ insertContent(
+ contentStrategy: ContentStrategy,
+ ): T {
const hash = generateHash(contentStrategy.content);
if (this.inserted.has(hash)) return;
- contentStrategy.insertElement();
+ const element = contentStrategy.insertElement();
this.inserted.add(hash);
+
+ return element;
+ }
+
+ removeContent(element: HTMLScriptElement | HTMLStyleElement) {
+ const hash = generateHash(element.textContent);
+ this.inserted.delete(hash);
+
+ element.parentNode.removeChild(element);
}
}
diff --git a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts
index 1d58f6bb3d..05261bc5e4 100644
--- a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts
+++ b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts
@@ -10,11 +10,13 @@ export abstract class ContentStrategy {
domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => {}) as any;
const strategy = new StyleContentStrategy('', domStrategy, contentSecurityStrategy);
- const element = strategy.createElement();
- strategy.insertElement();
+ strategy.createElement();
+ const element = strategy.insertElement();
expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element);
expect(domStrategy.insertElement).toHaveBeenCalledWith(element);
diff --git a/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts
index f8e8565496..556583643e 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts
@@ -9,7 +9,7 @@ describe('DomInsertionService', () => {
beforeEach(() => (spectator = createService()));
- afterEach(() => styleElements.forEach(element => element.remove()));
+ afterEach(() => (document.head.innerHTML = ''));
describe('#insertContent', () => {
it('should be able to insert given content', () => {
@@ -19,6 +19,11 @@ describe('DomInsertionService', () => {
expect(styleElements[0].textContent).toBe('.test {}');
});
+ it('should set a hash for the inserted content', () => {
+ spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
+ expect(spectator.service.inserted.has(1437348290)).toBe(true);
+ });
+
it('should insert only once', () => {
expect(spectator.service.inserted.has(1437348290)).toBe(false);
@@ -37,9 +42,25 @@ describe('DomInsertionService', () => {
expect(spectator.service.inserted.has(1437348290)).toBe(true);
});
- it('should be able to insert given content', () => {
- spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
+ it('should return inserted element', () => {
+ const element = spectator.service.insertContent(
+ CONTENT_STRATEGY.AppendStyleToHead('.test {}'),
+ );
+ expect(element.tagName).toBe('STYLE');
+ });
+ });
+
+ describe('#removeContent', () => {
+ it('should remove inserted element and the hash for the content', () => {
+ expect(document.head.querySelector('style')).toBeNull();
+ const element = spectator.service.insertContent(
+ CONTENT_STRATEGY.AppendStyleToHead('.test {}'),
+ );
expect(spectator.service.inserted.has(1437348290)).toBe(true);
+
+ spectator.service.removeContent(element);
+ expect(spectator.service.inserted.has(1437348290)).toBe(false);
+ expect(document.head.querySelector('style')).toBeNull();
});
});
});
diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json
index b8e5be4397..65e02593f0 100644
--- a/templates/app/angular/package.json
+++ b/templates/app/angular/package.json
@@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
- "start": "ng serve",
+ "start": "ng serve --open",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
diff --git a/templates/app/angular/start.ps1 b/templates/app/angular/start.ps1
new file mode 100644
index 0000000000..dac71a8164
--- /dev/null
+++ b/templates/app/angular/start.ps1
@@ -0,0 +1,2 @@
+yarn
+yarn start
\ No newline at end of file