最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dialog element 'open' event - Stack Overflow

programmeradmin4浏览0评论

For the dialog element <dialog>, is there some sort of "open" event that is fired when it is shown, either normally or as a modal?

The spec isn't totally clear on this, and MDN just lists a bunch of inherited events.

The close event does fire, but I can't seem to get any sort of open event.

Example HTML:

<dialog>
  <h1>Oh hey, a dialog...</h1>
</dialog>

And in JavaScript:

document.querySelector('dialog').addEventListener('open', (e) => {
  console.log(e);
});
document.querySelector('dialog').showModal();

For the dialog element <dialog>, is there some sort of "open" event that is fired when it is shown, either normally or as a modal?

The spec isn't totally clear on this, and MDN just lists a bunch of inherited events.

The close event does fire, but I can't seem to get any sort of open event.

Example HTML:

<dialog>
  <h1>Oh hey, a dialog...</h1>
</dialog>

And in JavaScript:

document.querySelector('dialog').addEventListener('open', (e) => {
  console.log(e);
});
document.querySelector('dialog').showModal();
Share Improve this question asked Mar 6, 2018 at 2:37 BradBrad 163k55 gold badges377 silver badges552 bronze badges 3
  • Just a guess try show event? – Vinay Commented Mar 6, 2018 at 2:59
  • @Viney Unfortunately, that event doesn't fire either. – Brad Commented Mar 6, 2018 at 17:10
  • There seems to be some progress recently to rectify the situation github./whatwg/html/issues/9733 – Martin Commented Jul 3, 2024 at 14:49
Add a ment  | 

4 Answers 4

Reset to default 7

2025 Update: beforetoggle and toggle events

This is now available via the beforetoggle and toggle events in Chromium v123: https://github./whatwg/html/pull/10091

Previous Answer:

No, there is no open event.

The dialog has an open property which can determine if it's opened or not, but unfortunately there's no event when this transitions.

An easy solution to your problem would be this :

<dialog id="dial">
  <h3> dialog element </h3>
  <button id="close">x</button>
</dialog>
<button id="buttonDialog" > Open   </button>
<button id="buttonDialog2"> Open 2 </button>
const
  dialog  = document.getElementById('dial')
, close   = document.getElementById('close')
, button  = document.getElementById('buttonDialog')
, button2 = document.getElementById('buttonDialog2')
  ;
button.addEventListener('click', event => {
  dialog.showModal()
  })
close.addEventListener('click', event => {
  dialog.close()
  })
let observer = new MutationObserver(function()  {
  if (event[0].attributeName == 'open') console.log('updated')
  });
observer.observe(dialog, { attributes: true })
  ;
button2.addEventListener('click', event => {
  dialog.setAttribute('open', true)
  })

As mentioned in the ments/anwers here, it is possible to generate this event using a MutationObserver().

As the answers here seem cruelly inplete (even wrong), I did my own experiments to pose an easily exploitable answer.

Nota : _ <dialog> JS objects always have an open property, and it is a boolean value (true or false), even if this attribute is not present on the HTML declaration.

1st solution :

(() =>  // IIFE => add  event 'dialog-open' to all Dialog elements
  {
  const
    OpenEvent = new CustomEvent('dialog-open') 
  , ObserverM = new MutationObserver( recs =>
    {
    recs.forEach( ({attributeName: attr, target: dial }) =>
      {
      if (attr === 'open' && dial.open )
        dial.dispatchEvent( OpenEvent );    
      })
    });
  document.querySelectorAll('dialog').forEach( dial =>
    {
    ObserverM.observe( dial, { attributes: true } );
    })
  })() // IIFE end...

const
  btShowDial = document.querySelector('#bt-show_mDialog')
, dialogBox  = document.querySelector('#dialog-box')
, dialBForm  = document.querySelector('#dialog-box form')
  ;
btShowDial.onclick =_=>
  {
  dialogBox.showModal()
  }
dialogBox.addEventListener('dialog-open', () =>
  {
  dialBForm.inNum.valueAsNumber =  0 | Math.random() *10**4
  dialogBox.returnValue = 'exit with Escape key'
  })
dialogBox.onclose=_=>
  {
  console.log(`${dialBForm.inNum.value } is ${dialogBox.returnValue}` )
  }
<button id="bt-show_mDialog">show modal dialog..</button>

<dialog id="dialog-box">
  <form method="dialog">
    <h3>Dialog -1-</h3>
    <label> mumeric : <input type="number" name="inNum"></label>
    <br>
    <button value="good"> good </button>
    <button value="bad" > bad </button>
  </form>
</dialog>

Personally, I prefer to use their event methods directly on DOM Objects.
They have the advantage of being unique, and of making the code more readable.
so might as well add this one, rather than creating a specific custom event!

2nd solution :

(() =>  // IIFE => add  event 'dialog-open' to all Dialog elements
  {
  const Dialogs = document.querySelectorAll('dialog');

  Dialogs.forEach( dial => dial.onOpen = function(){} )  // add onOpen empty method.

  const ObserverM = new MutationObserver( recs =>
    {
    recs.forEach( ({attributeName: attr, target: dial }) =>
      {
      if (attr === 'open' && dial.open ) dial.onOpen();  // call onOpen Method...  
      })
    });
  Dialogs.forEach( dial => ObserverM.observe( dial, { attributes: true }))
  })() // IIFE end...

const
  btShowDial = document.querySelector('#bt-show_mDialog')
, dialogBox  = document.querySelector('#dialog-box')
, dialBForm  = document.querySelector('#dialog-box form')
  ;
btShowDial.onclick =_=>
  {
  dialogBox.showModal()
  }
dialogBox.onOpen =_=>
  {
  dialBForm.inNum.valueAsNumber =  0 | Math.random() *10**4
  dialogBox.returnValue         = 'exit with Escape key'
  }
dialogBox.onclose=_=>
  {
  console.log(`${dialBForm.inNum.value } is ${dialogBox.returnValue}` )
  }
dialog::backdrop {
  background: #00ddff5d;
  }
<button id="bt-show_mDialog">show modal dialog..</button>

<dialog id="dialog-box">
  <form method="dialog">
    <h3>Dialog -1-</h3>
    <label> mumeric : <input type="number" name="inNum"></label>
    <br>
    <button value="good"> good </button>
    <button value="bad" > bad </button>
  </form>
</dialog>

Found this thread and wanted to post my solution: custom event.

After setting a document.querySelector('dialog').showModal(); call you can add a document.querySelector('dialog').dispatchEvent(new Event('open'));. Then the expected document.querySelector('dialog').addEventListener('open', e => {...}); works!

发布评论

评论列表(0)

  1. 暂无评论