Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,68 @@ Or as Observable:
```angular2html
isLoggedIn$ = this.store.select(selectIsLoggedIn);
```
### Automatic assets public path (`assets/...`)

If your custom module/add-on is hosted under a dynamic base URL, plain template URLs like:

```html
<img src="assets/images/logo.png" />
```
may break, because the browser resolves them relative to the host page.

To fix this, we provide:

src/app/services/assets-public-path.directive.ts

This directive automatically rewrites any src / href that starts with assets/ (or /assets/) to:

```js
__webpack_public_path__ + 'assets/...'
```
Import the directive in a component (Standalone)
Add the directive to the component imports:

```js
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { AssetsPublicPathDirective } from '../services/assets-public-path.directive';

@Component({
selector: 'custom-example',
standalone: true,
templateUrl: './example.component.html',
styleUrls: ['./example.component.scss'],
imports: [CommonModule, AssetsPublicPathDirective],
})
export class ExampleComponent {}
```
If the component is not standalone (NgModule-based), import and export the directive from a shared module, and include that module where your components are declared.

Use it in HTML
After the directive is imported, you can use plain assets/... paths in templates:


```html
<!-- Images -->
<img src="assets/images/logo.png" alt="Logo">

<!-- Icons / SVG -->
<img src="assets/homepage/clock.svg" alt="Clock">

<!-- Links to files -->
<a href="assets/files/help.pdf">Help</a>
```
Supported attributes/elements (common cases):

img[src]

source[src]

script[src]

link[href]

a[href]

### Accessing app router

Expand Down
44 changes: 44 additions & 0 deletions src/app/services/assets-public-path.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Directive, ElementRef, Input, OnChanges, Renderer2 } from '@angular/core';

declare const __webpack_public_path__: string;

@Directive({
selector: 'img[src],source[src],link[href],script[src],a[href]',
standalone: true,
})
export class AssetsPublicPathDirective implements OnChanges {
@Input() src?: string;
@Input() href?: string;

constructor(private el: ElementRef, private r: Renderer2) {}

ngOnChanges(): void {
// Handle [src] / src and [href] / href
const tag = (this.el.nativeElement.tagName || '').toLowerCase();
const attr = tag === 'link' || tag === 'a' ? 'href' : 'src';
const val = attr === 'href' ? (this.href ?? this.el.nativeElement.getAttribute('href')) : (this.src ?? this.el.nativeElement.getAttribute('src'));

if (!val) return;

const rewritten = this.rewriteIfAssets(val);
if (rewritten !== val) {
this.r.setAttribute(this.el.nativeElement, attr, rewritten);
}
}

private rewriteIfAssets(url: string): string {
// Don’t touch absolute URLs, data:, blob:, etc.
if (/^(https?:)?\/\//i.test(url) || /^data:|^blob:/i.test(url)) return url;

// Normalize
const clean = url.startsWith('/') ? url.slice(1) : url;

if (clean.startsWith('assets/')) {
const base = (typeof __webpack_public_path__ === 'string' ? __webpack_public_path__ : '') || '';
const baseFixed = base && !base.endsWith('/') ? base + '/' : base;
return baseFixed + clean;
}

return url;
}
}