route pathmatch example child routing angular hashtag

routing - pathmatch - router outlet



Enrutamiento Angular2 con Hashtag para anclaje de página (19)

¡Este funciona para mí! Este ngPara que ancle dinámicamente la etiqueta, debe esperar a que se procesen

HTML:

<div #ngForComments *ngFor="let cm of Comments"> <a id="Comment_{{cm.id}}" fragment="Comment_{{cm.id}}" (click)="jumpToId()">{{cm.namae}} Reply</a> Blah Blah </div>

Mi archivo ts:

private fragment: string; @ViewChildren(''ngForComments'') AnchorComments: QueryList<any>; ngOnInit() { this.route.fragment.subscribe(fragment => { this.fragment = fragment; }); } ngAfterViewInit() { this.AnchorComments.changes.subscribe(t => { this.ngForRendred(); }) } ngForRendred() { this.jumpToId() } jumpToId() { let x = document.querySelector("#" + this.fragment); console.log(x) if (x){ x.scrollIntoView(); } }

¡No olvides importar ese ViewChildren , QueryList , etc. y agregar un constructor ActivatedRoute !!

Deseo agregar algunos enlaces en mi página Angular2, que al hacer clic, saltará a posiciones específicas dentro de esa página, como lo hacen los hashtags normales. Entonces los enlaces serían algo así como

/users/123#userInfo /users/123#userPhoto /users/123#userLikes

etc.

No creo que necesite HashLocationStrategy, ya que estoy bien con la forma normal de Angular2, pero si agrego directamente, el enlace realmente saltaría a la raíz, no a algún lugar de la misma página. Cualquier dirección es apreciada, gracias.


A diferencia de otras respuestas, también agregaría focus() junto con scrollIntoView() . También estoy usando setTimeout ya que salta a la parte superior de lo contrario al cambiar la URL. No estoy seguro de cuál fue el motivo, pero parece que setTimeout hace la solución.

Origen:

<a [routerLink] fragment="some-id" (click)="scrollIntoView(''some-id'')">Jump</a>

Destino:

<a id="some-id" tabindex="-1"></a>

Mecanografiado:

scrollIntoView(anchorHash) { setTimeout(() => { const anchor = document.getElementById(anchorHash); if (anchor) { anchor.focus(); anchor.scrollIntoView(); } }); }


Acabo de hacer que esto funcione en mi propio sitio web, así que pensé que valdría la pena publicar mi solución aquí.

<a [routerLink]="baseUrlGoesHere" fragment="nameOfYourAnchorGoesHere">Link Text!</a> <a name="nameOfYourAnchorGoesHere"></a> <div>They''re trying to anchor to me!</div>

Y luego, en su componente, asegúrese de incluir esto:

import { ActivatedRoute } from ''@angular/router''; constructor(private route: ActivatedRoute) { this.route.fragment.subscribe ( f => { const element = document.querySelector ( "#" + f ) if ( element ) element.scrollIntoView ( element ) }); }


Acabo de probar un complemento muy útil disponible en nmp - ngx-scroll-to , que funciona muy bien para mí. Sin embargo, está diseñado para Angular 4+, pero tal vez alguien encuentre útil esta respuesta.


Además de la answer de Kalyoyan, esta suscripción está vinculada al enrutador y permanecerá activa hasta que la página se actualice por completo. Al suscribirse a eventos de enrutador en un componente, asegúrese de darse de baja en ngOnDestroy:

import { OnDestroy } from ''@angular/core''; import { Router, NavigationEnd } from ''@angular/router''; import { Subscription } from "rxjs/Rx"; class MyAppComponent implements OnDestroy { private subscription: Subscription; constructor(router: Router) { this.subscription = router.events.subscribe(s => { if (s instanceof NavigationEnd) { const tree = router.parseUrl(router.url); if (tree.fragment) { const element = document.querySelector("#" + tree.fragment); if (element) { element.scrollIntoView(element); } } } }); } public ngOnDestroy() { this.subscription.unsubscribe(); } }


Aquí hay otra solución alternativa con referencia a la respuesta de JavierFuentes:

<a [routerLink]="[''self-route'', id]" fragment="some-element" (click)="gotoHashtag(''some-element'')">Jump to Element</a>

en script:

import {ActivatedRoute} from "@angular/router"; import {Subscription} from "rxjs/Subscription"; export class Links { private scrollExecuted: boolean = false; constructor(private route: ActivatedRoute) {} ngAfterViewChecked() { if (!this.scrollExecuted) { let routeFragmentSubscription: Subscription; routeFragmentSubscription = this.route.fragment.subscribe(fragment => { if (fragment) { let element = document.getElementById(fragment); if (element) { element.scrollIntoView(); this.scrollExecuted = true; // Free resources setTimeout( () => { console.log(''routeFragmentSubscription unsubscribe''); routeFragmentSubscription.unsubscribe(); }, 0); } } }); } } gotoHashtag(fragment: string) { const element = document.querySelector("#" + fragment); if (element) element.scrollIntoView(element); } }

Esto permite al usuario desplazarse directamente al elemento, si el usuario aterriza directamente en la página que tiene un hashtag en la URL.

Pero en este caso, he suscrito el Fragmento de ruta en ngAfterViewChecked pero se llama continuamente a ngAfterViewChecked() por cada ngDoCheck y no permite al usuario desplazarse hacia arriba, por lo que routeFragmentSubscription.unsubscribe se llama después de un tiempo de espera de 0 milis después de que se visualiza desplazado al elemento.

Además, el método gotoHashtag se define para desplazarse al elemento cuando el usuario hace clic específicamente en la etiqueta de anclaje.

Actualizar:

Si url tiene [routerLink]="[''self-route'', id]" consulta, [routerLink]="[''self-route'', id]" en el ancla no conservará las cadenas de consulta. Intenté seguir la solución para lo mismo:

<a (click)="gotoHashtag(''some-element'')">Jump to Element</a> constructor( private route: ActivatedRoute, private _router:Router) { } ... ... gotoHashtag(fragment: string) { let url = ''''; let urlWithSegments = this._router.url.split(''#''); if(urlWithSegments.length){ url = urlWithSegments[0]; } window.location.hash = fragment; const element = document.querySelector("#" + fragment); if (element) element.scrollIntoView(element); }


Aunque la respuesta de Günter es correcta, no cubre el "salto a" la parte de la etiqueta de anclaje .

Por lo tanto, adicionalmente a:

<a [routerLink]="[''somepath'']" fragment="Test">Jump to ''Test'' anchor </a>

this._router.navigate( [''/somepath'', id ], {fragment: ''test''});

... en el componente (padre) donde necesita un comportamiento de "salto a", agregue:

import { Router, NavigationEnd } from ''@angular/router''; class MyAppComponent { constructor(router: Router) { router.events.subscribe(s => { if (s instanceof NavigationEnd) { const tree = router.parseUrl(router.url); if (tree.fragment) { const element = document.querySelector("#" + tree.fragment); if (element) { element.scrollIntoView(true); } } } }); } }

¡Tenga en cuenta que esta es una solución alternativa ! Siga https://github.com/angular/angular/issues/6595 para futuras actualizaciones. ¡Créditos a Victor Savkin por proporcionar la solución!


Dado que la propiedad del fragmento todavía no proporciona desplazamiento de anclaje, esta solución me sirvió:

<div [routerLink]="[''somepath'']" fragment="Test"> <a href="#Test">Jump to ''Test'' anchor </a> </div>


Después de leer todas las soluciones, busqué un componente y encontré uno que hace exactamente lo que pedía la pregunta original: desplazarse para anclar enlaces. https://www.npmjs.com/package/ng2-scroll-to

Cuando lo instala, usa una sintaxis como:

// app.awesome.component.ts @Component({ ... template: `... <a scrollTo href="#main-section">Scroll to main section</a> <button scrollTo scrollTargetSelector="#test-section">Scroll to test section</a> <button scrollTo scrollableElementSelector="#container" scrollYTarget="0">Go top</a> <!-- Further content here --> <div id="container"> <section id="main-section">Bla bla bla</section> <section id="test-section">Bla bla bla</section> <div> ...`, }) export class AwesomeComponent { }

Me ha funcionado muy bien.


Las soluciones anteriores no funcionaron para mí ... Esta lo hizo:

Primero, prepare MyAppComponent para el desplazamiento automático en ngAfterViewChecked () ...

import { Component, OnInit, AfterViewChecked } from ''@angular/core''; import { ActivatedRoute } from ''@angular/router''; import { Subscription } from ''rxjs''; @Component( { [...] } ) export class MyAppComponent implements OnInit, AfterViewChecked { private scrollExecuted: boolean = false; constructor( private activatedRoute: ActivatedRoute ) {} ngAfterViewChecked() { if ( !this.scrollExecuted ) { let routeFragmentSubscription: Subscription; // Automatic scroll routeFragmentSubscription = this.activatedRoute.fragment .subscribe( fragment => { if ( fragment ) { let element = document.getElementById( fragment ); if ( element ) { element.scrollIntoView(); this.scrollExecuted = true; // Free resources setTimeout( () => { console.log( ''routeFragmentSubscription unsubscribe'' ); routeFragmentSubscription.unsubscribe(); }, 1000 ); } } } ); } } }

Luego, navegue hasta my-app-route enviando el hashtag prodID

import { Component } from ''@angular/core''; import { Router } from ''@angular/router''; @Component( { [...] } ) export class MyOtherComponent { constructor( private router: Router ) {} gotoHashtag( prodID: string ) { this.router.navigate( [ ''/my-app-route'' ], { fragment: prodID } ); } }


Ninguna de las respuestas anteriores me funcionó. En un último esfuerzo, probé en mi plantilla:

<a (click)="onClick()">From Here</a> <div id=''foobar''>To Here</div>

Con esto en mis .ts:

onClick(){ let x = document.querySelector("#foobar"); if (x){ x.scrollIntoView(); } }

Y funciona como se espera para los enlaces internos. Esto en realidad no usa etiquetas de anclaje, por lo que no tocaría la URL en absoluto.


Perdón por responder un poco tarde; Hay una función predefinida en la documentación de enrutamiento angular que nos ayuda a enrutar con un hashtag para anclar página, es decir, anchorScrolling: ''habilitado''

Paso-1: - Primero importe el RouterModule en el archivo app.module.ts: -

imports:[ BrowserModule, FormsModule, RouterModule.forRoot(routes,{ anchorScrolling: ''enabled'' }) ],

Paso 2: - Vaya a la página HTML, cree la navegación y agregue dos atributos importantes como [routerLink] y fragmente para hacer coincidir las respectivas ID Div :

<ul> <li> <a [routerLink] = "[''/'']" fragment="home"> Home </a></li> <li> <a [routerLink] = "[''/'']" fragment="about"> About Us </a></li> <li> <a [routerLink] = "[''/'']" fragment="contact"> Contact Us </a></li> </ul>

Paso 3: - Cree una sección / div haciendo coincidir el nombre de ID con el fragmento : -

<section id="home" class="home-section"> <h2> HOME SECTION </h2> </section> <section id="about" class="about-section"> <h2> ABOUT US SECTION </h2> </section> <section id="contact" class="contact-section"> <h2> CONTACT US SECTION </h2> </section>

Para su referencia, he agregado el siguiente ejemplo creando una pequeña demostración que ayuda a resolver su problema.

Demostración: https://routing-hashtag-page-anchors.stackblitz.io/


Probé la mayoría de estas soluciones, pero me encontré con problemas al irme y volver con otro fragmento que no funcionaría, así que hice algo un poco diferente que funciona al 100% y me deshago del hash feo en la URL.

tl; dr aquí hay una mejor manera de lo que he visto hasta ahora.

import { Component, OnInit, AfterViewChecked, OnDestroy } from ''@angular/core''; import { ActivatedRoute } from ''@angular/router''; import { Subscription } from ''rxjs/Subscription''; @Component({ selector: ''app-hero'', templateUrl: ''./hero.component.html'', styleUrls: [''./hero.component.scss''] }) export class HeroComponent implements OnInit, AfterViewChecked, OnDestroy { private fragment: string; fragSub: Subscription; constructor(private route: ActivatedRoute) { } ngOnInit() { this.fragSub = this.route.fragment.subscribe( fragment => { this.fragment = fragment; }) } ngAfterViewChecked(): void { try { document.querySelector(''#'' + this.fragment).scrollIntoView({behavior: ''smooth''}); window.location.hash = ""; } catch (e) { } } ngOnDestroy() { this.fragSub.unsubscribe(); } }


Todas las demás respuestas funcionarán en la versión angular <6.1. Pero si tiene la última versión, entonces no necesitará hacer estos trucos feos ya que Angular ha solucionado el problema.

https://github.com/angular/angular/issues/6595

Todo lo que necesita hacer es establecer scrollOffset con la opción del segundo argumento del método RouterModule.forRoot .

@NgModule({ imports: [ RouterModule.forRoot(routes, { scrollPositionRestoration: ''enabled'', anchorScrolling: ''enabled'', scrollOffset: [0, 64] // [x, y] }) ], exports: [RouterModule] }) export class AppRoutingModule {}


Tuve el mismo problema. La solución: usar View port Scroller https://angular.io/api/common/ViewportScroller#scrolltoanchor

- código app-routing.module.ts:

import { PageComponent } from ''./page/page.component''; const routes: Routes = [ path: ''page'', component: PageComponent }, path: ''page/:id'', component: PageComponent } ];

- Componente HTML

<a (click) = "scrollTo(''typeExec'')"> <mat-icon>lens</mat-icon> </a>

- Código del componente:

import { Component } from ''@angular/core''; import { ViewportScroller } from ''@angular/common''; export class ParametrageComponent { constructor(private viewScroller: ViewportScroller) {} scrollTo(tag : string) { this.viewScroller.scrollToAnchor(tag); } }


Un poco tarde, pero aquí hay una respuesta que encontré que funciona:

<a [routerLink]="[''/path'']" fragment="test" (click)="onAnchorClick()">Anchor</a>

Y en el componente:

constructor( private route: ActivatedRoute, private router: Router ) {} onAnchorClick ( ) { this.route.fragment.subscribe ( f => { const element = document.querySelector ( "#" + f ) if ( element ) element.scrollIntoView ( element ) }); }

Lo anterior no se desplaza automáticamente a la vista si aterriza en una página con un ancla ya, por lo que utilicé la solución anterior en mi ngInit para que también pueda funcionar con eso:

ngOnInit() { this.router.events.subscribe(s => { if (s instanceof NavigationEnd) { const tree = this.router.parseUrl(this.router.url); if (tree.fragment) { const element = document.querySelector("#" + tree.fragment); if (element) { element.scrollIntoView(element); } } } }); }

Asegúrese de importar Router, ActivatedRoute y NavigationEnd al comienzo de su componente y todo debería estar listo.

Source


Una solución simple que funciona para páginas sin ningún parámetro de consulta, es compatible con el navegador hacia atrás / adelante, el enrutador y los enlaces profundos.

<a (click)="jumpToId(''anchor1'')">Go To Anchor 1</a> ngOnInit() { // If your page is dynamic this.yourService.getWhatever() .then( data => { this.componentData = data; setTimeout(() => this.jumpToId( window.location.hash.substr(1) ), 100); } ); // If your page is static // this.jumpToId( window.location.hash.substr(1) ) } jumpToId( fragment ) { // Use the browser to navigate window.location.hash = fragment; // But also scroll when routing / deep-linking to dynamic page // or re-clicking same anchor if (fragment) { const element = document.querySelector(''#'' + fragment); if (element) element.scrollIntoView(); } }

El tiempo de espera es simplemente permitir que la página cargue cualquier dato dinámico "protegido" por un * ngIf. Esto también se puede usar para desplazarse a la parte superior de la página al cambiar la ruta; solo proporcione una etiqueta de anclaje superior predeterminada.


Use esto para el módulo de enrutador en app-routing.module.ts :

@NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true, scrollPositionRestoration: ''enabled'', anchorScrolling: ''enabled'', scrollOffset: [0, 64] })], exports: [RouterModule] })

Esto estará en tu HTML:

<a href="#/users/123#userInfo">


Actualizar

Esto ahora es compatible

<a [routerLink]="[''somepath'']" fragment="Test">Jump to ''Test'' anchor </a>

this._router.navigate( [''/somepath'', id ], {fragment: ''test''});

Agregue el siguiente código a su componente para desplazarse

import {ActivatedRoute} from ''@angular/router''; // <-- do not forget to import private fragment: string; constructor(private route: ActivatedRoute) { } ngOnInit() { this.route.fragment.subscribe(fragment => { this.fragment = fragment; }); } ngAfterViewInit(): void { try { document.querySelector(''#'' + this.fragment).scrollIntoView(); } catch (e) { } }

Original

Este es un problema conocido y se rastrea en https://github.com/angular/angular/issues/6595