The item is not destroyed when navigating the router after manipulating the DOM

I have a directive that should move the element to which it is applied to the body of the document:

@Directive({
  selector: '[myDirective]'
})
export class MyDirective implements AfterViewInit {
  constructor(private elem: ElementRef,
    private renderer: Renderer2) {
  }

  ngAfterViewInit() {
    // Move element to body
    this.renderer.appendChild(document.body, this.elem.nativeElement);
  }
}

Now I use this directive in element c ngIf, which I switch based on some condition:

<div myDirective *ngIf="visible">Test</div>
<button (click)="visible = !visible">Toggle</button>

When it starts, the div will display after the button as expected because it was added to the body. At the moment, the toggle button is still working, and I can show / hide the div.

The problem occurs when I entered the routes:

<a routerLink="/route/1">Link</a>
<div myDirective *ngIf="visible">Test</div>
<button (click)="visible = !visible">Toggle</button>

Now, if I show the div and switch to another route, the div must be destroyed, but it is still visible! If I do not move the div into the body, then it behaves as expected.

ngOnDestroy, , : .

, , , div :

this.routerSubscription = router.events.first().subscribe(() => {
  this.renderer.appendChild(this.parentNode, this.elem.nativeElement);
});

, , , .

, , ?

DEMO: https://stackblitz.com/edit/angular-qximjw?file=app%2Fapp.component.ts

:

  • , URL- ,
  • ,
  • div NOT.
+6
2

ngOnDestroy:

ngOnDestroy() {
  if (this.routerSubscription) {
    this.routerSubscription.unsubscribe();
  }
  document.body.removeChild(this.elem.nativeElement);
}

, , angular ( , ngOnDestroy ). , .

.

+2

, , . RouterLink, , HomeComponent , .

const routes: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
    path: 'route/:id',
    component: HomeComponent
  }
];

, ​​ DOM, HomeComponent , , , <div> (). , HomeComponent JavaScript.

@Component({
  selector: 'home-component',
  template: `
  <a routerLink="/route/1">Link</a>
  <div myDirective *ngIf="visible" @transition>Test</div>
  <button (click)="visible = !visible">Toggle</button>
  `,
  animations: [
    trigger('transition', [
      transition(':enter', [
        style({ opacity: 0 }),
        animate('.35s ease', style({ opacity: '*' }))
      ]),
      transition(':leave', [
        style({ opacity: '*' }),
        animate('.35s ease', style({ opacity: 0 }))
      ])
    ])
  ]
})
export class HomeComponent {
  visible = false;
  constructor() {
    console.log('New instance')
  }
}

, , , Toggle - .

@Component({
    selector: 'app-toggle-button',
    template: `
    <div myDirective *ngIf="visible" @transition>Test</div>
    <button (click)="visible = !visible">Toggle</button>
    `,
    animations: [
      trigger('transition', [
        transition(':enter', [
          style({ opacity: 0 }),
          animate('.35s ease', style({ opacity: '*' }))
        ]),
        transition(':leave', [
          style({ opacity: '*' }),
          animate('.35s ease', style({ opacity: 0 }))
        ])
      ])
    ]
  })
  export class ToggleComponent {
    visible = false;
  }

app.component.html:

<app-toggle-button></app-toggle-button>
<router-outlet></router-outlet>

A SINGLE ToggleComponent, .

, , .

+2

All Articles