Я прикрепляю подтверждения <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(), … }
Других диалогов на странице нет. Кажется, я единственный, кто столкнулся с этой проблемой, и это заставляет меня думать, что момент фейспалма не за горами. Можете ли вы доставить его?
@Берги, почему бы и нет? Семантически это часть формы.
@OlaTuvesson, потому что тогда кнопки внутри диалогового окна будут взаимодействовать с формой, как показано в ответе Пита, а вам этого не нужно. Возможно, вы захотите поставить <form method = "dialog"> вокруг кнопок внутри <dialog>.
@Bergi Может быть много причин, по которым вам захочется поставить <button> внутри формы, которая не отправляет ее.
@OlaTuvesson конечно, но тогда лучше использовать <input type = "button"> или <button type = "button">. Однако я говорил конкретно о кнопках отмены и принятия вашего диалога.
@Bergi Ты отпустишь меня, если я изменю тип кнопки отмены на type = "button"?
Конечно, так лучше :-) Я бы, наверное, все же рекомендовал сделать отдельный <form> для диалога и его кнопок и поместить его рядом с оригиналом <form>, поскольку, хотя они явно связаны, формы не должны быть вложенными. Но я не думаю, что ваш подход неправильный, особенно если вы хотите рассматривать кнопку принятия как <button type = "submit"> для формы, в которой находится диалог. Не уверен, что семантически чище.
@Bergi Спасибо, я так думал, что кнопки в диалоговом окне предназначены для взаимодействия с формой, а «ОК» — это, по сути, еще одна отправка. Хотя есть разные точки зрения на это! По сути, я ошибся, забыв, что поведение по умолчанию простого <button> внутри <form> заключается в отправке формы, что, по моему мнению, несколько неинтуитивно. И <button type = "button"> кажется неуклюже, чем <button type = "submit">.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам также необходимо запретить действие кнопки отмены по умолчанию - поскольку оно находится в форме, оно, вероятно, закрывает модальное окно, но снова отправляет форму и отображает новое модальное окно (если вы измените отмену на диапазон вместо кнопки, вы увидите он работает без предотвращения по умолчанию):
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", когда его помещают внутрь формы... Подсказка, много путаницы!
Отправляя форму, я имел в виду, что она повторно активирует onsubmit, который затем отображает модальное окно (но не отправляет форму на самом деле, поскольку в onsubmit у вас была функция предотвращения по умолчанию).
Спасибо. В конце концов я вместо этого установил cancel.type = "button" и удалил event.preventDefault() из обработчика событий onclick. Думаю, случай «шесть одного, полдюжины другого».
Каждая кнопка внутри формы инициирует отправку при нажатии, поэтому вы находитесь в цикле отправки, который технически закрывает и снова открывает диалоговое окно.
Чтобы исправить это, добавьте 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. Правильно, но лишнее.
Вероятно, вам не следует помещать элемент
<dialog>внутри<form>.