Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#FocusTrap for nested DynamicDialogs still not working #9329

Closed
kaleemGhouri opened this issue Sep 29, 2020 · 29 comments · Fixed by #12039
Closed

#FocusTrap for nested DynamicDialogs still not working #9329

kaleemGhouri opened this issue Sep 29, 2020 · 29 comments · Fixed by #12039
Labels
LTS-FIXED-13.4.4 LTS-FIXED-14.2.6 Type: Bug Issue contains a bug related to a specific component. Something about the component is not working
Milestone

Comments

@kaleemGhouri
Copy link

Tab keys not working when i open dynamic dialog from another dynamic dialog, it stuck on close button so if i focus on control by using mouse keys and then i press tab key it focus again close button. I am using 9.1.5-lts version
1

@kaleemGhouri kaleemGhouri changed the title #FocusTrap for DynamicDialog still not working #FocusTrap for nested DynamicDialogs still not working Sep 30, 2020
@aashu0148
Copy link

hey! what is the issue can u please explain

@kaleemGhouri
Copy link
Author

Hey!! problem is that when we open a dynamic dialog from a dynamic dialog then focus controls using tab key stuck on the 1st dialog. expected behavior should have been like focus on last open dynamic dialog

@kaleemGhouri
Copy link
Author

Btw thanks for your reply

@Brian-Wuest
Copy link

This issue is also affecting the project I am working on.

Trying to use the keyboard to tab through field when working on a Dynamic Dialog on-top of another Dynamic Dialog does not work.

Trying to use the "FocusTrap" module on my second Dynamic Dialog does not address the issue.

@yigitfindikli yigitfindikli added the Status: Pending Review Issue or pull request is being reviewed by Core Team label Nov 25, 2020
@ivanovych666
Copy link

I have the same problem. Here is my workaround:

export class FirstModalComponent {
    constructor(
        private dialogService: DialogService,
        public dynamicDialogRef: DynamicDialogRef,
    ) {
    }

    public openSecondModal(): void {
        // open the second modal
        const secondModalRef = this.dialogService.open(SecodModalComponent);
        
        // get DynamicDialogComponent instance for the current/first modal
        const dynamicDialogComponent = this.dialogService.dialogComponentRefMap.get(this.dynamicDialogRef).instance;

        // unbind tab/esc buttons listeners
        dynamicDialogComponent.unbindGlobalListeners();

        // when the second modal is closed/destroyed then
        secondModalRef.onDestroy.pipe(first()).subscribe(() => {
            // reinitialize the first modal
            dynamicDialogComponent.moveOnTop(); // we need this for properly Esc button handler
            dynamicDialogComponent.bindGlobalListeners(); // bind tab/esc buttons listeners
            dynamicDialogComponent.focus(); // apply [autofocus] if any
        });
    }
}

@techmaster242
Copy link

techmaster242 commented Feb 2, 2021

I have the same problem. Here is my workaround:
// when the second modal is closed/destroyed then
secondModalRef.onDestroy.pipe(first()).subscribe(() => {

What is the first() thing you're calling in the pipe? I'm trying your workaround but this isn't working for me.

Wait, apparently it's part of rxjs. But this part:

this.dialogService.dialogComponentRefMap.get(this.dynamicDialogRef)

is coming back as undefined for me.

@ivanovych666
Copy link

ivanovych666 commented Feb 7, 2021

@techmaster242

What is the first() thing you're calling in the pipe? I'm trying your workaround but this isn't working for me.

Wait, apparently it's part of rxjs. But this part:

.pipe(first()) - this is for a subscription canceling (unsubscribing), you can do this in different ways, it is not necessary for this example. And yes, it is from rxjs.

this.dialogService.dialogComponentRefMap.get(this.dynamicDialogRef)

As I mentioned in the comment, it is to "get DynamicDialogComponent instance for the current/first modal", without this line, we can't do all the things below. Because this.dynamicDialogRef doesn't have the necessary methods, it is like a wrapper for a DynamicDialogComponent instance.

@miguelarcjr
Copy link

Same problem

@AndreAquilau
Copy link

I also have the same problem

@miguelarcjr
Copy link

To work you need to add the DialogService into app.module providers

@hannesthor
Copy link

I am also experiencing the tab problem - in a dynamic dialog, opened from a dynamic dialog, all tabbing wants to go to the close button (X). If I turn that off, all tabbing goes to the first input control.

@tisys-parceiros
Copy link

was this problem resolved?

@kaleemGhouri
Copy link
Author

not found any solution that's why I avoid nested dialog solution in my application

@djay1977
Copy link

@cagataycivici
This problem is really important, we have a lot of feedback from our clients on our projects on this subject.
Sometimes we don't have the choice to open 2 DynamicDialog.
Would it be possible to fix this problem for a 13.x version?

Thanks in advance

@thedavidhoffman
Copy link

Any updates on this issue?

@Oznaprazzi
Copy link

I'm having the same problem with pressing enter or space keys

@wilsondab
Copy link

I found a posible solution, apply when open a DynamicDialog inside another DynamicDialog

export class DynamicDialog2 implements OnInit {
ngOnInit{
...
this.dialogService.dialogComponentRefMap.forEach(dialog => {
if(dialog.instance.childComponentType.name.includes("--name of the entity --")){
dialog.instance.focus();
}
else{
dialog.instance.unbindGlobalListeners(); // close for the previous instance
}
});
}
}

@Wadoks
Copy link

Wadoks commented May 6, 2022

I found a posible solution, apply when open a DynamicDialog inside another DynamicDialog

export class DynamicDialog2 implements OnInit { ngOnInit{ ... this.dialogService.dialogComponentRefMap.forEach(dialog => { if(dialog.instance.childComponentType.name.includes("--name of the entity --")){ dialog.instance.focus(); } else{ dialog.instance.unbindGlobalListeners(); // close for the previous instance } }); } }

Unfortunatly, this workaround does not work for me.

Any updates on this issue ?

@ymfreddy
Copy link

please help us!
any solution?

@mselerin
Copy link
Contributor

mselerin commented Oct 12, 2022

The workaround did not work for me neither.

But I've found a solution. Here is the relevant part :

@Component({
  templateUrl: './first-dialog.component.html',
  providers: [DialogService]
})
export class FirstDialogComponent {
  constructor(
    private refDialogComponent: DynamicDialogComponent,
    private dialogService: DialogService
  ) { }


  public openSecondDialog(): void {
    this.refDialogComponent.unbindDocumentKeydownListener();
    
    const subref = this.dialogService.open(SecondDialogComponent);
    subref.onDestroy.pipe(
      take(1),
      tap(() => this.refDialogComponent.bindDocumentKeydownListener())
    ).subscribe();
  }
}

The trick is to get a reference to the nearest DynamicDialogComponent (in the constructor), which is in fact the first dialog.
Then, before opening the second dialog, unbind the key listeners from the first dialog and re-bind them when the second dialog is destroyed.

@mertsincan
Copy link
Member

Hi,

So sorry for the delayed response! Improvements have been made to many components recently, both in terms of performance and enhancement. Therefore, this improvement may have been developed in another issue ticket without realizing it. You can check this in the documentation. If there is no improvement on this, can you reopen the issue so we can include it in our roadmap?
Please don't forget to add your feedback as a comment after reopening the issue. These will be taken into account by us and will contribute to the development of this feature. Thanks a lot for your understanding!

Best Regards,

@djay1977
Copy link

Hi,

The problem is still not solved with the latest version of PrimeNG 14.2.1
The solution is in this ticket : #12039
Could you merge for the next release?
Thanks

@mertsincan mertsincan reopened this Nov 11, 2022
@github-actions github-actions bot added the Status: Needs Triage Issue will be reviewed by Core Team and a relevant label will be added as soon as possible label Nov 11, 2022
@jakubnavratil
Copy link

Just discovered this issue in my app, looking for a fix. Thanks @mselerin for pushing the fix and workaround!
Hope they will merge this soon.

@djay1977
Copy link

Hi @mertsincan, @cagataycivici
Would it be possible to merge this issue which works perfectly. We've been waiting for this fix for several years.
Thanks in advance

@jakubnavratil
Copy link

I created this service, all you need is to just open every dialog with this.
So change DialogService to TabbedDialogService

import { Injectable, Type } from '@angular/core';
import {
  DialogService,
  DynamicDialogComponent,
  DynamicDialogConfig,
  DynamicDialogRef,
} from 'primeng/dynamicdialog';
import { first } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class TabbedDialogService {
  constructor(private dialogService: DialogService) {}

  currentDialogRef: DynamicDialogRef | null = null;

  open(
    componentType: Type<any>,
    config: DynamicDialogConfig
  ): DynamicDialogRef {
    let currentDialogComponent: DynamicDialogComponent | undefined;
    if (this.currentDialogRef) {
      currentDialogComponent = this.dialogService.dialogComponentRefMap.get(
        this.currentDialogRef
      )?.instance;
      currentDialogComponent?.unbindGlobalListeners();
    }

    const lastDialogRef = this.currentDialogRef;
    const dialogRef = this.dialogService.open(componentType, config);
    this.currentDialogRef = dialogRef;

    dialogRef.onDestroy.pipe(first()).subscribe(() => {
      // reinitialize the first modal
      if (currentDialogComponent) {
        currentDialogComponent.moveOnTop(); // we need this for properly Esc button handler
        currentDialogComponent.bindGlobalListeners(); // bind tab/esc buttons listeners
        currentDialogComponent.focus(); // apply [autofocus] if any
      }

      this.currentDialogRef = lastDialogRef;
    });

    return dialogRef;
  }
}

@VekrO
Copy link

VekrO commented Mar 28, 2023

@djay1977 I have the same problem, but DynamicDialogComponent is a component, that is, I can't inject a component into a class, is there any solution for this?

@djay1977
Copy link

the solution is here : #12039

@cetincakiroglu cetincakiroglu added this to the 15.4.2 milestone Apr 25, 2023
@cetincakiroglu cetincakiroglu added Type: Bug Issue contains a bug related to a specific component. Something about the component is not working LTS-PORTABLE and removed Status: Pending Review Issue or pull request is being reviewed by Core Team Status: Needs Triage Issue will be reviewed by Core Team and a relevant label will be added as soon as possible labels Apr 25, 2023
@yarikwest
Copy link

yarikwest commented Oct 13, 2023

for me it still doesn't work :( (version 16.5.0)

@cromanauter
Copy link

cromanauter commented Apr 19, 2024

En la versión 17.3.3 yo hice lo siguiente :

1 .Desde MenuComponent abro el primer dialog que tiene el componente FloatRequestsComponent :

` public openRequestsFloatingModal() : void {

  const dialogRef = this.dialog.open(FloatRequestsComponent, {
    styleClass: 'app-full-bleed-dialog',
    style: {
             minWidth: '60vw',
             minHeight: '44vh',
             maxWidth: '80vw',
             maxHeight: '60vh',
             hasBackdrop: false,
             autoFocus: false},
    modal: true,
    draggable: true,
    resizable: true,
    header: 'Solicitudes'
  });
}`
  1. Abro el segundo modal NewRequestsComponent
 public openNewRequestModal() : void {
      this.compOpened[index].value = true;
      const dialogRef = this.dialog.open(NewRequestComponent, {
        styleClass: 'app-full-bleed-dialog',
        style: {
               'min-height': '60vh',
               'max-height': '80vh',
               'min-width': '45vw',
               'max-width': '50vw'} ,
        modal: false,
        header: 'Nueva solicitud',
        draggable: true,
        resizable: true,
        data: {
          new: true
        }
      }); }
  1. En el segundo dialogo abierto deberías colocar este código en el ngOnInit (Ojo donde dice newRequestComponent debe tener el nombre del componente del 2 dialog):
 this.dialogService.dialogComponentRefMap.forEach(dialog => {
      if (dialog.instance.childComponentType.name.includes("NewRequestComponent")) {
        dialog.instance.focus();
      }
      else {
        dialog.instance.unbindGlobalListeners(); // cerrar para la instancia anterior
      }
    });
Saludos , espero que les sirva.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LTS-FIXED-13.4.4 LTS-FIXED-14.2.6 Type: Bug Issue contains a bug related to a specific component. Something about the component is not working
Projects
None yet
Development

Successfully merging a pull request may close this issue.