HTML <dialog> close() ничего не делает

Я прикрепляю подтверждения <dialog> ко всем формам, которым они нужны, с помощью

const forms = document.querySelectorAll("form[data-confirm]");
forms.forEach((form) => {
  const confirm = document.createElement("dialog");
  const message = document.createElement("p");
  const cancel = document.createElement("button");
  const accept = document.createElement("button");
  message.innerText = form.dataset.confirm;
  cancel.innerText = form.dataset.cancel;
  accept.innerText = form.dataset.accept;
  confirm.appendChild(message);
  confirm.appendChild(cancel);
  confirm.appendChild(accept);
  form.appendChild(confirm);
  form.onsubmit = (event) => {
    event.preventDefault();
    confirm.showModal();
  }
  cancel.onclick = () => {
    console.info(confirm.close)
    confirm.close();
  }
  accept.onclick = () => {
    form.submit();
  }
});

Кажется, это работает хорошо, за исключением метода close(), который ничего не делает и не выдает ошибок. Запись функции на консоль показывает

function close()
length: 0
name: "close"
<prototype>: function ()

в Firefox, а Edge и Chrome показывают

f close() { [собственный код] }

Изменение вызова на hide() в качестве теста предсказуемо приведет к

Uncaught TypeError: Confirm.hide не является функцией

Регистрация самого диалога показывает, что мы имеем дело с правильным объектом DOM:

...

cancel.onclick = () => {
    console.info(confirm)
    confirm.close();
}
> <dialog open = "">
...

​<prototype>: HTMLDialogElementPrototype { show: show(), showModal: showModal(), close: close(), … }

Других диалогов на странице нет. Кажется, я единственный, кто столкнулся с этой проблемой, и это заставляет меня думать, что момент фейспалма не за горами. Можете ли вы доставить его?

Вероятно, вам не следует помещать элемент <dialog> внутри <form>.

Bergi 20.02.2024 16:37

@Берги, почему бы и нет? Семантически это часть формы.

Ola Tuvesson 20.02.2024 16:54

@OlaTuvesson, потому что тогда кнопки внутри диалогового окна будут взаимодействовать с формой, как показано в ответе Пита, а вам этого не нужно. Возможно, вы захотите поставить <form method = "dialog"> вокруг кнопок внутри <dialog>.

Bergi 20.02.2024 17:12

@Bergi Может быть много причин, по которым вам захочется поставить <button> внутри формы, которая не отправляет ее.

Ola Tuvesson 20.02.2024 17:25

@OlaTuvesson конечно, но тогда лучше использовать <input type = "button"> или <button type = "button">. Однако я говорил конкретно о кнопках отмены и принятия вашего диалога.

Bergi 20.02.2024 17:33

@Bergi Ты отпустишь меня, если я изменю тип кнопки отмены на type = "button"?

Ola Tuvesson 20.02.2024 17:35

Конечно, так лучше :-) Я бы, наверное, все же рекомендовал сделать отдельный <form> для диалога и его кнопок и поместить его рядом с оригиналом <form>, поскольку, хотя они явно связаны, формы не должны быть вложенными. Но я не думаю, что ваш подход неправильный, особенно если вы хотите рассматривать кнопку принятия как <button type = "submit"> для формы, в которой находится диалог. Не уверен, что семантически чище.

Bergi 20.02.2024 17:48

@Bergi Спасибо, я так думал, что кнопки в диалоговом окне предназначены для взаимодействия с формой, а «ОК» — это, по сути, еще одна отправка. Хотя есть разные точки зрения на это! По сути, я ошибся, забыв, что поведение по умолчанию простого <button> внутри <form> заключается в отправке формы, что, по моему мнению, несколько неинтуитивно. И <button type = "button"> кажется неуклюже, чем <button type = "submit">.

Ola Tuvesson 20.02.2024 19:32
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
8
95
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вам также необходимо запретить действие кнопки отмены по умолчанию - поскольку оно находится в форме, оно, вероятно, закрывает модальное окно, но снова отправляет форму и отображает новое модальное окно (если вы измените отмену на диапазон вместо кнопки, вы увидите он работает без предотвращения по умолчанию):

const forms = document.querySelectorAll("form[data-confirm]");

forms.forEach(form => {
  const confirm = document.createElement("dialog");
  const message = document.createElement("p");
  const cancel = document.createElement("button");
  const accept = document.createElement("button");
  message.innerText = form.dataset.confirm;
  cancel.innerText = form.dataset.cancel;
  accept.innerText = form.dataset.accept;
  confirm.appendChild(message);
  confirm.appendChild(cancel);
  confirm.appendChild(accept);
  form.appendChild(confirm);
  
  form.onsubmit = event => {
    event.preventDefault();
    confirm.showModal();
  }
  
  cancel.onclick = event => {
    event.preventDefault();
    confirm.close();
  }
  
  accept.onclick = () => {
    form.submit();
  }
});
<form action = "#" method = "get" data-confirm = "confirm" data-cancel = "cancel" data-accept = "accept">
 <input type = "submit" value = "submit">
</form>

Форма не была отправлена ​​с тех пор, как я preventDefaultonsubmit, поэтому казалось, что кнопка отмены активировала только свою собственную onclick и ничего больше. Я бы заметил отправку формы, поскольку в консоли была бы соответствующая запись POST, и диалоговое окно исчезло бы. И, если быть совершенно честным, я забыл, что <button> по умолчанию действует как type = "submit", когда его помещают внутрь формы... Подсказка, много путаницы!

Ola Tuvesson 20.02.2024 16:51

Отправляя форму, я имел в виду, что она повторно активирует onsubmit, который затем отображает модальное окно (но не отправляет форму на самом деле, поскольку в onsubmit у вас была функция предотвращения по умолчанию).

Pete 20.02.2024 16:54

Спасибо. В конце концов я вместо этого установил cancel.type = "button" и удалил event.preventDefault() из обработчика событий onclick. Думаю, случай «шесть одного, полдюжины другого».

Ola Tuvesson 20.02.2024 19:37

Каждая кнопка внутри формы инициирует отправку при нажатии, поэтому вы находитесь в цикле отправки, который технически закрывает и снова открывает диалоговое окно.

Чтобы исправить это, добавьте event.preventDefault(); внутри каждой кнопки вашего диалога:

const forms = document.querySelectorAll("form[data-confirm]");

forms.forEach((form) => {
  const confirm = document.createElement("dialog");
  const message = document.createElement("p");
  const cancel = document.createElement("button");
  const accept = document.createElement("button");
  message.innerText = form.dataset.confirm;
  cancel.innerText = form.dataset.cancel;
  accept.innerText = form.dataset.accept;
  confirm.appendChild(message);
  confirm.appendChild(cancel);
  confirm.appendChild(accept);
  form.appendChild(confirm);
  form.onsubmit = (event) => {
    event.preventDefault();
    confirm.showModal(); 
  }
  cancel.onclick = () => {
    //just add this for fix your problem
    //=================================
    event.preventDefault();
    //================================
    confirm.close();
  }
  accept.onclick = () => {
    //this is not mandatory but is usefull 
    //if you want add some logic inside accept
    //=================================
    event.preventDefault();
    //================================
    form.submit();
  }
});
<form data-confirm = "confirm" data-cancel = "cancel"  data-accept = "accept">
<h2>hero</h2>
<button>test</button>
</form>

Спасибо, но это тот же ответ, что уже дал @Pete. Правильно, но лишнее.

Ola Tuvesson 20.02.2024 17:26

Другие вопросы по теме