|
1342 | 1342 | // ** организация "динамического" добавления строки контакта/row-contact (по нажатию "Добавить контакт" кнопки, в модальных/универсальных окнах) |
1343 | 1343 | function createModalContactsElement(context = {}) { |
1344 | 1344 | const { modalWrap, modalBodyAddContactsRowWrap, modalBodyAddBtn } = context; // получение необходимых элементов (через деструктуризациию входящего/передаваемого объекта) |
| 1345 | + const modalBodyForm = modalWrap.querySelector('form'); |
| 1346 | + const saveButton = modalWrap.querySelector('#modal-body-save-btn'); |
1345 | 1347 |
|
1346 | 1348 | if (modalContactsArr.length >= 10) return; // проверка количества контактов (не более 10) |
1347 | 1349 |
|
|
1525 | 1527 | } |
1526 | 1528 | } |
1527 | 1529 |
|
| 1530 | + // обновление состояния кнопки "Сохранить" (согласно действий с контактными инпутами) |
| 1531 | + updateSaveButtonState(modalBodyForm, saveButton); |
| 1532 | + |
1528 | 1533 | // обновление/изменение отступов для li/вариантов выпадающего списка (для первого и последнего элементов) |
1529 | 1534 | updateDropItemPaddings(modalContactList); |
1530 | 1535 |
|
|
1635 | 1640 | modalContactXBtn.addEventListener('click', (event) => { |
1636 | 1641 | event.stopPropagation(); // исключение непредвиденных событий/поведения |
1637 | 1642 | deleteModalContactsElement(event, { |
| 1643 | + modalBodyForm, |
1638 | 1644 | modalBodyAddBtn, |
1639 | 1645 | modalBodyAddContactsRowWrap, |
1640 | 1646 | }); // удаление строки контактов (посредствам "X", передача context(a)) |
|
1645 | 1651 | if (event.key === 'Enter') { |
1646 | 1652 | event.stopPropagation(); // исключение непредвиденных событий/поведения |
1647 | 1653 | deleteModalContactsElement(event, { |
| 1654 | + modalBodyForm, |
1648 | 1655 | modalBodyAddBtn, |
1649 | 1656 | modalBodyAddContactsRowWrap, |
1650 | 1657 | }); // удаление строки контактов (посредствам "X", передача context(a)) |
|
1811 | 1818 | // ** удаление строки row-контакта в модальном окне (через "X" кнопку, с/без уточняющего сообщения) |
1812 | 1819 | function deleteModalContactsElement(event, context = {}) { |
1813 | 1820 | const clickedContactsXBtn = event.currentTarget; // получение ИМЕННО кнопки, а не/может внутренней иконки (согласно "размазанного" события) |
1814 | | - const { modalBodyAddBtn, modalBodyAddContactsRowWrap } = context; // получение необходимых элементов (через деструктуризациию входящего/передаваемого объекта) |
| 1821 | + const { modalBodyForm, modalBodyAddBtn, modalBodyAddContactsRowWrap } = |
| 1822 | + context; // получение необходимых элементов (через деструктуризациию входящего/передаваемого объекта) |
| 1823 | + const saveButton = modalBodyForm.querySelector('#modal-body-save-btn'); // фиксация кнопки "Сохранить" |
1815 | 1824 |
|
1816 | 1825 | if (clickedContactsXBtn) { |
1817 | 1826 | tippy.hideAll(); // предварительное скрытие всех/вдруг "активных" tooltips (перед удалением искомой строки) |
|
1862 | 1871 | modalBodyAddContactsRowWrap.classList.add('d-none'); |
1863 | 1872 | modalBodyAddBtn.classList.remove('modal-contact-btn-margin'); |
1864 | 1873 | } |
| 1874 | + |
| 1875 | + // обновление состояния кнопки "Сохранить" (после удалений строк контактов) |
| 1876 | + updateSaveButtonState(modalBodyForm, saveButton); |
1865 | 1877 | } else { |
1866 | 1878 | currentInput.focus(); // возврат фокуса искомому инпуту (после отмены удаления в confirm) |
1867 | 1879 | } |
|
1994 | 2006 | return; |
1995 | 2007 | } |
1996 | 2008 |
|
| 2009 | + const saveButton = modalBodyForm.querySelector('#modal-body-save-btn'); // фиксация кнопки "Сохранить" |
| 2010 | + |
1997 | 2011 | // [СЕРВЕР] / обработка события "submit" |
1998 | 2012 | modalBodyForm.addEventListener( |
1999 | 2013 | 'submit', |
|
2016 | 2030 | return feedback && feedback.textContent.trim() !== ''; |
2017 | 2031 | }); |
2018 | 2032 |
|
| 2033 | + // обновление состояния кнопки "Сохранить" (доступна, не доступна) |
| 2034 | + updateSaveButtonState(modalBodyForm, saveButton); |
| 2035 | + |
2019 | 2036 | if ( |
2020 | 2037 | !modalBodyForm.checkValidity() || |
2021 | 2038 | validErrors.length > 0 || |
2022 | 2039 | hasInvalidFeedback |
2023 | 2040 | ) { |
2024 | 2041 | event.stopPropagation(); |
2025 | | - } else { |
2026 | | - modalBodyForm.classList.add('was-validated'); // если всё "ок", т.е. нет ошибок, невалидных сообщений.. добавление всей форме валидационного класса (для/по Bootstrap) |
| 2042 | + return; // если есть ошибки, прекращение отработки |
| 2043 | + } |
2027 | 2044 |
|
2028 | | - setTimeout(() => { |
2029 | | - alert('Клиент успешно добавлен!'); // вывод сообщения об успешном добавлении клиента |
| 2045 | + modalBodyForm.classList.add('was-validated'); // если всё "ок", т.е. нет ошибок, невалидных сообщений.. добавление всей форме валидационного класса (для/по Bootstrap) |
2030 | 2046 |
|
2031 | | - // очистка всех полей формы (удаление классов/сообщений ошибок) |
2032 | | - allModalInputs.forEach((input) => { |
2033 | | - input.value = ''; |
2034 | | - input.classList.remove('is-invalid'); |
2035 | | - }); |
2036 | | - modalBodyForm.classList.remove('was-validated'); // удаление класса "was-validated" |
| 2047 | + setTimeout(() => { |
| 2048 | + alert('Клиент успешно добавлен!'); // вывод сообщения об успешном добавлении клиента |
2037 | 2049 |
|
2038 | | - // закрытие модального окна (через/посредствам Bootstrap API) |
2039 | | - const bootstrapModal = bootstrap.Modal.getInstance( |
2040 | | - modalBodyForm.closest('.modal') |
2041 | | - ); |
2042 | | - if (bootstrapModal) { |
2043 | | - bootstrapModal.hide(); |
2044 | | - } |
| 2050 | + // очистка всех полей формы (удаление классов/сообщений ошибок) |
| 2051 | + allModalInputs.forEach((input) => { |
| 2052 | + input.value = ''; |
| 2053 | + input.classList.remove('is-invalid'); |
| 2054 | + }); |
| 2055 | + modalBodyForm.classList.remove('was-validated'); // удаление класса "was-validated" |
2045 | 2056 |
|
2046 | | - // и напоследок.. выделение/показ только что добавленного клиента/строки |
2047 | | - setTimeout(() => { |
2048 | | - // movingToLastNewTableRow(); |
2049 | | - }, 300); // временная задержка, больше.. чтобы модальное окно успело закрыться |
2050 | | - }, 200); |
2051 | | - } |
| 2057 | + // закрытие модального окна (через/посредствам Bootstrap API) |
| 2058 | + const bootstrapModal = bootstrap.Modal.getInstance( |
| 2059 | + modalBodyForm.closest('.modal') |
| 2060 | + ); |
| 2061 | + if (bootstrapModal) { |
| 2062 | + bootstrapModal.hide(); |
| 2063 | + } |
| 2064 | + |
| 2065 | + // и напоследок.. выделение/показ только что добавленного клиента/строки |
| 2066 | + setTimeout(() => { |
| 2067 | + // movingToLastNewTableRow(); |
| 2068 | + }, 300); // временная задержка, больше.. чтобы модальное окно успело закрыться |
| 2069 | + }, 200); |
2052 | 2070 | }, |
2053 | 2071 | false |
2054 | 2072 | ); |
| 2073 | + |
| 2074 | + // обновление состояния кнопки "Сохранить" (согласно ввода данных) |
| 2075 | + modalBodyForm.addEventListener('input', () => |
| 2076 | + updateSaveButtonState(modalBodyForm, saveButton) |
| 2077 | + ); |
| 2078 | + } |
| 2079 | + |
| 2080 | + // ** организация блокировки доступности для модальной кнопки "Сохранить" (при "submit") |
| 2081 | + function updateSaveButtonState(modalBodyForm, saveButton) { |
| 2082 | + const allModalInputs = Array.from( |
| 2083 | + modalBodyForm.querySelectorAll('.modal-input') |
| 2084 | + ); |
| 2085 | + |
| 2086 | + // проверка на наличие невалидных инпутов (за исключением поля "Отчество", его "конкретного" сообщения) |
| 2087 | + const hasInvalidInputs = allModalInputs.some((input) => { |
| 2088 | + if (input.classList.contains('modal-patronymic-input')) { |
| 2089 | + const feedback = input |
| 2090 | + .closest('.modal__body-input-wrap') |
| 2091 | + .querySelector('.invalid-feedback'); |
| 2092 | + if ( |
| 2093 | + feedback && |
| 2094 | + feedback.textContent.trim() !== |
| 2095 | + 'Заполните поле "Отчество" или оставьте его пустым!' |
| 2096 | + ) { |
| 2097 | + return true; // другие сообщения.. кнопка "Сохранить" будет не доступной |
| 2098 | + } |
| 2099 | + return false; // нужное сообщение.. будет доступна |
| 2100 | + } |
| 2101 | + return input.classList.contains('is-invalid'); |
| 2102 | + }); |
| 2103 | + |
| 2104 | + // проверка обязательных полей ФИО (за исключением поля "Отчество") |
| 2105 | + const requiredInputsEmpty = allModalInputs.some( |
| 2106 | + (input) => |
| 2107 | + input.required && |
| 2108 | + !input.classList.contains('modal-patronymic-input') && |
| 2109 | + input.value.trim() === '' |
| 2110 | + ); |
| 2111 | + |
| 2112 | + // проверка состояния модальной-формы (наличие "was-submitted", да/нет) |
| 2113 | + const wasSubmitted = modalBodyForm.classList.contains('was-submitted'); |
| 2114 | + |
| 2115 | + // блокировка кнопки, если был "submit" (если/есть, появились невалидные инпуты) |
| 2116 | + saveButton.disabled = |
| 2117 | + wasSubmitted && (hasInvalidInputs || requiredInputsEmpty); |
| 2118 | + |
| 2119 | + // обновление/изменение состояния кнопки и прозрачности |
| 2120 | + saveButton.style.opacity = saveButton.disabled ? '0.5' : '1'; |
| 2121 | + saveButton.style.cursor = saveButton.disabled ? 'help' : 'pointer'; |
2055 | 2122 | } |
2056 | 2123 | })(); |
0 commit comments