diff --git a/README.md b/README.md
index 603cbbd..4869d68 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,8 @@ A library that allows href to understand Angular's router while retaining its de
2. Support scroll with the `#` attributes and let you configure the [scrolling logic](#scroll-logic)
3. Automatically append `rel="nooepener"` & `target="_blank"` to external link [if wished so](#installation)
4. Support using `href` with the html `button` [attribute](#directive)
+5. Enable easy `Scroll when ready` mechanism
+6. Let you transform text to well formatted `anchor`
## Demo
- https://stackblitz.com/~/github.com/rbalet/ngx-href
@@ -32,6 +34,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
* defaultOffset="0"
* navbarOffset="0"
* rel=undefined
+ * retryTimeout=undefined
* target="_self"
**/
ngxHrefModule.forRoot({}),
@@ -43,6 +46,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
defaultOffset:"30",
navbarOffset:"60",
rel:"noopener nofollow",
+ retryTimeout: 300,
target:"_blank",
}),
],
@@ -99,6 +103,14 @@ ngAfterContentInit(): void {
}
```
+### retryTimeout
+**Default:** `undefined`
+**Accepted value:** `number`
+
+Trigger a second `scrollTo` event after `retryTimeout` milliseconds.
+
+**Note:** This should be avoided, prefer playing with skeleton and fixed height
+
## External link
### Rel attribute
@@ -119,17 +131,15 @@ Can also be passed individually directly through html
```
-### target attribute
-
-
## Usage
-Wherever you plan to use the href directive
+Wherever you plan to use the href directive or pipe
```typescript
-import { ngxHrefModule } from 'ngx-href'
+import { NgxHrefDirective, ToAnchorPipe } from 'ngx-href'
imports: [
- ngxHrefModule,
+ NgxHrefDirective,
+ NgxHrefPipe,
]
```
@@ -166,6 +176,20 @@ Normal use
```
+### Pipe: _ToAnchorPipe_
+The `toAnchor` pipe let you
+1. transform an element ot a correct anchor
+example: `my Title $%` will be transform to `my-title`
+
+2. Emit that this anchor have been created, so that we can scroll to that element
+
+```html
+
+
+
+
+
+```
### Service
```typescript
@@ -187,6 +211,7 @@ Normal use
A title
```
+
## Authors and acknowledgment
* maintainer [Raphaël Balet](https://github.com/rbalet)
diff --git a/package.json b/package.json
index a332090..c472930 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ngx-href",
- "version": "17.1.2",
+ "version": "17.2.0",
"license": "MIT",
"author": "Raphael Balet",
"maintainers": [
diff --git a/projects/ngx-href-tester/src/app/app.module.ts b/projects/ngx-href-tester/src/app/app.module.ts
index fc41832..8a58229 100644
--- a/projects/ngx-href-tester/src/app/app.module.ts
+++ b/projects/ngx-href-tester/src/app/app.module.ts
@@ -43,6 +43,7 @@ export const routes: Routes = [
defaultOffset: 100,
defaultRelAttr: '',
defaultTargetAttr: '_blank',
+ retryTimeout: 300,
}),
],
bootstrap: [AppComponent],
diff --git a/projects/ngx-href/README.md b/projects/ngx-href/README.md
index 603cbbd..4869d68 100644
--- a/projects/ngx-href/README.md
+++ b/projects/ngx-href/README.md
@@ -11,6 +11,8 @@ A library that allows href to understand Angular's router while retaining its de
2. Support scroll with the `#` attributes and let you configure the [scrolling logic](#scroll-logic)
3. Automatically append `rel="nooepener"` & `target="_blank"` to external link [if wished so](#installation)
4. Support using `href` with the html `button` [attribute](#directive)
+5. Enable easy `Scroll when ready` mechanism
+6. Let you transform text to well formatted `anchor`
## Demo
- https://stackblitz.com/~/github.com/rbalet/ngx-href
@@ -32,6 +34,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
* defaultOffset="0"
* navbarOffset="0"
* rel=undefined
+ * retryTimeout=undefined
* target="_self"
**/
ngxHrefModule.forRoot({}),
@@ -43,6 +46,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
defaultOffset:"30",
navbarOffset:"60",
rel:"noopener nofollow",
+ retryTimeout: 300,
target:"_blank",
}),
],
@@ -99,6 +103,14 @@ ngAfterContentInit(): void {
}
```
+### retryTimeout
+**Default:** `undefined`
+**Accepted value:** `number`
+
+Trigger a second `scrollTo` event after `retryTimeout` milliseconds.
+
+**Note:** This should be avoided, prefer playing with skeleton and fixed height
+
## External link
### Rel attribute
@@ -119,17 +131,15 @@ Can also be passed individually directly through html
```
-### target attribute
-
-
## Usage
-Wherever you plan to use the href directive
+Wherever you plan to use the href directive or pipe
```typescript
-import { ngxHrefModule } from 'ngx-href'
+import { NgxHrefDirective, ToAnchorPipe } from 'ngx-href'
imports: [
- ngxHrefModule,
+ NgxHrefDirective,
+ NgxHrefPipe,
]
```
@@ -166,6 +176,20 @@ Normal use
```
+### Pipe: _ToAnchorPipe_
+The `toAnchor` pipe let you
+1. transform an element ot a correct anchor
+example: `my Title $%` will be transform to `my-title`
+
+2. Emit that this anchor have been created, so that we can scroll to that element
+
+```html
+
+
+
+
+
+```
### Service
```typescript
@@ -187,6 +211,7 @@ Normal use
A title
```
+
## Authors and acknowledgment
* maintainer [Raphaël Balet](https://github.com/rbalet)
diff --git a/projects/ngx-href/package.json b/projects/ngx-href/package.json
index 3070670..55034ec 100644
--- a/projects/ngx-href/package.json
+++ b/projects/ngx-href/package.json
@@ -1,6 +1,6 @@
{
"name": "ngx-href",
- "version": "17.1.2",
+ "version": "17.2.0",
"license": "MIT",
"author": {
"name": "Raphaël Balet",
diff --git a/projects/ngx-href/src/lib/href.interface.ts b/projects/ngx-href/src/lib/href.interface.ts
index 575560d..b613c3e 100644
--- a/projects/ngx-href/src/lib/href.interface.ts
+++ b/projects/ngx-href/src/lib/href.interface.ts
@@ -5,4 +5,5 @@ export interface NgxHrefServiceConfig {
defaultOffset?: number
defaultRelAttr?: string
defaultTargetAttr?: string
+ retryTimeout?: number
}
diff --git a/projects/ngx-href/src/lib/href.service.ts b/projects/ngx-href/src/lib/href.service.ts
index 30e7d9c..a3e9a1b 100644
--- a/projects/ngx-href/src/lib/href.service.ts
+++ b/projects/ngx-href/src/lib/href.service.ts
@@ -8,6 +8,7 @@ import { NgxHrefServiceConfig } from './href.interface'
})
export class NgxHrefService {
anchor$: BehaviorSubject = new BehaviorSubject(null)
+ loadedAnchor$: BehaviorSubject = new BehaviorSubject(null) // Trigger the scrollTo mechanism from outside
avoidSpam?: boolean
behavior!: ScrollBehavior
@@ -15,8 +16,9 @@ export class NgxHrefService {
navbarOffset!: number
defaultRelAttr?: string
defaultTargetAttr!: string
+ retryTimeout?: number
- private _actualAnchor = ''
+ private _actualAnchor?: string
constructor(@Inject(NgxHrefServiceProvider) _config: NgxHrefServiceConfig) {
this.avoidSpam = _config.avoidSpam
@@ -25,24 +27,29 @@ export class NgxHrefService {
this.navbarOffset = typeof _config.navbarOffset === 'number' ? _config.navbarOffset : 0
this.defaultRelAttr = _config.defaultRelAttr
this.defaultTargetAttr = _config.defaultTargetAttr || '_self'
+ this.retryTimeout = _config.retryTimeout
+
+ this.loadedAnchor$.subscribe((anchor) => {
+ if (anchor === this._actualAnchor) {
+ this.scrollTo(anchor, 9) // 9: triggered only once
+ }
+ })
}
scrollTo(anchor?: string, counter = 0) {
- if (!anchor) return
-
- const newAnchor = anchor.replace(/ /g, '')
-
- if (counter === 0) this.anchor$.next(newAnchor)
-
if (
+ !anchor ||
counter >= 10 || // Counter over, this element doesn't exist or the page is too slow
- (newAnchor === this._actualAnchor && counter === 0) // Multiple click on the same url
+ (anchor === this._actualAnchor && counter === 0) // Multiple click on the same url
)
return
- this._actualAnchor = newAnchor
+ if (counter === 0) {
+ this._actualAnchor = anchor
+ this.anchor$.next(anchor)
+ }
- const anchorRef = document.getElementById(newAnchor)
+ const anchorRef = document.getElementById(anchor)
if (anchorRef) {
const offsetPosition =
@@ -55,11 +62,21 @@ export class NgxHrefService {
behavior: this.behavior,
})
- this._actualAnchor = ''
+ if (this.retryTimeout)
+ setTimeout(() => {
+ window.scrollTo({
+ top: offsetPosition,
+ behavior: this.behavior,
+ })
+ }, this.retryTimeout)
+
+ this._actualAnchor = undefined
} else {
setTimeout(() => {
+ if (anchor !== this._actualAnchor) return
+
counter++
- this.scrollTo(newAnchor, counter)
+ this.scrollTo(anchor, counter)
}, 200)
}
}
diff --git a/projects/ngx-href/src/lib/to-anchor.pipe.ts b/projects/ngx-href/src/lib/to-anchor.pipe.ts
new file mode 100644
index 0000000..2aed563
--- /dev/null
+++ b/projects/ngx-href/src/lib/to-anchor.pipe.ts
@@ -0,0 +1,71 @@
+import { Pipe, PipeTransform } from '@angular/core'
+import { NgxHrefService } from './href.service'
+
+@Pipe({
+ standalone: true,
+ name: 'toAnchor',
+})
+export class ToAnchorPipe implements PipeTransform {
+ private _removedChars = [
+ ';',
+ ':',
+ '!',
+ '"',
+ '(',
+ ')',
+ '[',
+ ']',
+ '{',
+ '}',
+ '*',
+ '/',
+ '%',
+ '^',
+ '+',
+ '<',
+ '=',
+ '>',
+ '~',
+ ]
+
+ private _replacedChars: { [key: string]: string } = {
+ ' ': '-',
+ ',': '-',
+ "'": '-',
+ à: 'a',
+ â: 'a',
+ ã: 'a',
+ ä: 'ae',
+ ç: 'c',
+ é: 'e',
+ è: 'e',
+ ê: 'e',
+ ë: 'e',
+ î: 'i',
+ ï: 'i',
+ ñ: 'n',
+ ô: 'o',
+ ö: 'oe',
+ ß: 'ss',
+ û: 'u',
+ ü: 'ue',
+ }
+
+ constructor(private _ngxHrefService: NgxHrefService) {}
+
+ transform(id: string, emit = true): string {
+ if (!id) return ''
+
+ let anchor = id.toLocaleLowerCase()
+ Object.entries(this._replacedChars).forEach(([specialChar, replacement]) => {
+ anchor = anchor.split(specialChar).join(replacement)
+ })
+ this._removedChars.forEach((char) => {
+ anchor = anchor.split(char).join('')
+ })
+
+ if (emit) this._ngxHrefService.loadedAnchor$.next(anchor)
+
+ return anchor
+ }
+}
diff --git a/projects/ngx-href/src/public-api.ts b/projects/ngx-href/src/public-api.ts
index 1e8bd9f..6ed8374 100644
--- a/projects/ngx-href/src/public-api.ts
+++ b/projects/ngx-href/src/public-api.ts
@@ -5,3 +5,4 @@
export * from './lib/href.directive'
export * from './lib/href.module'
export * from './lib/href.service'
+export * from './lib/to-anchor.pipe'