Фінальні коригування стилю валідації

Створення форм завжди було страшним завданням, яке я відкладаю до останнього. Зазвичай я просто починаю з копіювання вже існуючого файлу форми. Сьогодні я вирішив щось з цим зробити. Ось серія статей, в яких ми розглянемо форми в Angular, у їх найпростішому вигляді, та створимо повторно використовуваний компонент для керування валідацією.

pic

Щоб додати відсутні стилі і зробити форму максимально функціональною, потрібно постійно нагадувати собі про золотий принцип:

Не припускай.

Це означає, що ми можемо додавати відносні відступи, межі, кольори за допомогою змінних CSS, але не можемо диктувати, як повинна виглядати галочка. Це стиль проекту, а не елемента. (Є такі школи дизайну, як material design, які лізуть в кожен елемент, ускладнюючи використання окремих компонентів).

Checkbox

Почнемо з checkbox. Все, що нам потрібно зробити — це поміняти місцями checkbox і label. Потім просто дозволимо зовнішньому проекту самому визначити вигляд checkbox. Є два рішення: розумне і занадто розумне. Ось як виглядає занадто розумне рішення:

.cr-field {  
 /* таргетуємо попереднього сусіда */  
 .cr-label:has(~ [type="checkbox"]) {  
 /* важливо видалити transform у всіх випадках */  
 transform: none!important;  
 inset-block-start: 0;  
 inset-inline-start: 0;  
 padding-inline-start: 1.8rem;  
 position: relative;  
 display: inline-block;  
 background: none;  
 cursor: pointer;  
 }  

 .cr-input[type="checkbox"] {  
 position: absolute;  
 inset-inline-start: 0;  
 }  
}

Простішим шляхом є введення нового властивості type для cr-field, яке явно задається. Імпліцитне присвоєння — це теж "занадто розумно."

// input.partial  
template: `  

    // ...   `   @Input() type!: string;      get typeCss(): string {    return this.type ? `${this.cssPrefix}-${this.type}` : '';   } ```  Тепер пишемо не надто розумний CSS:  ``` .cr-field.cr-checkbox {    .cr-label {    /* те саме, що і вище */    }    .cr-input {    /* те саме, що і вище */    }   } ```  Селектор став простіший, і у нас є більше можливостей для стилізації інших елементів, таких як зірочка для обов'язкових полів, текст допомоги та текст зворотного зв'язку. Бачите, іноді варто бути трохи менш розумним.  ![pic](https://drive.javascript.org.ua/dba5edc62d0_EZpqL6FdrhJBYhGf_png)  CSS для цього рішення:  ``` .cr-field.cr-checkbox {    .cr-label {    /* важливо видалити transform у всіх випадках */    transform: none!important;    inset-block-start: 0;    inset-inline-start: 0;    padding-inline-start: 1.8rem;    position: relative;    display: inline-block;    background: none;    cursor: pointer;    }    .cr-input {    position: absolute;    inset-inline-start: 0;    }    .cr-feedback {    margin-block-start: 0;    float: none;    }    .cr-required {    position: static;    }   } ```  ## Тестування країв  Одним із сценаріїв, через який ми проходили, було те, що зірочка для обов'язкового поля була поза межами екрана. Ми вже спроектували її так, щоб вона була розташована на самому правому краї.
З тим, що ми маємо на даний момент, чи можемо ми зробити це гарно виглядати без змін у бібліотечних компонентах і спільному CSS?

Ось приклад для дати закінчення терміну. Рішення, щоб розмістити зірочку всередині контексту, полягає в простому додаванні необхідних стилів до контейнера.

/* фіксуємо ширину контейнера на рівні c-5 і робимо його блоком */

/* також фіксуємо ширину внутрішніх полів на c-6 */

h
```

Результат виглядає ось так:

pic

Три речі, які я зробив:

  • Змінив ширину контейнера на бажану відносну ширину і змінив його відображення на block (компоненти Angular за замовчуванням відображаються як contents)
  • Змінив ширину внутрішнього компонента на 50% для кожного (це має більше сенсу)
  • Потім змінив повідомлення на: Додайте дату в майбутньому. Це охоплює обидва правила: термін минув і обов'язкове значення.

Отже, наш компонент залишився без змін. Це перемога.

Вам, можливо, доведеться протестувати додаткові сценарії та оновити CSS для введення, щоб зробити його якомога простішим, щоб у майбутньому не було проблем.

Тестування іншого крайнощого випадку: Красивий checkbox

Ось ще один крайній випадок. Кожен проект має свій стиль для чекбоксів. Виходячи з CSS, який ми розробили до цього часу, давайте подивимося, чи можемо ми втягнути наш одиничний чекбокс з зовнішнього світу без поламання. Використаємо приклад MDN.

/* додаємо той самий CSS з правильним випадковим селектором до нашого проекту */  
.gr-something .cr-field.cr-checkbox {  

 .cr-input {  
 /* видаляємо стандартний вигляд **/  
 appearance: none;  
 width: 44px;  
 height: 24px;  
 border-radius: 12px;  
 transition: all 0.4s;  
 }  
 .cr-input::before {  
 width: 16px;  
 height: 16px;  
 border-radius: 9px;  
 background-color: var(--sh-black, #000);  
 content: '';  
 position: absolute;  
 inset-block-start: 3px;  
 inset-inline-start: 4px;  
 transition: all 0.4s;  
 }  
 .cr-input:checked {  
 background-color: var(--sh-yellow, #ffaa00);  
 transition: all 0.4s;  
 }  
 .cr-input:checked::before {  
 inset-inline-start: 22px;  
 transition: all 0.4s;  
 }  
 .cr-label {  
 /* налаштовуємо відступи у мітці */  
 padding-inline-start: 4.2rem;  
 }  
}

Вищезазначене — це приклад MDN з кількома налаштуваннями. Нам просто потрібно було звернути увагу на селектор, щоб не виникали проблеми з !important. Застосувати це так само легко, як і додати клас до селектора:




Ось як це виглядає:

pic

Ще одна перемога! Бачите, якщо б ми були занадто розумними щодо наших селекторів, це перетворилося б на спагетті.

Приховані поля

Приховані інпут-елементи спрощують валідацію, яка в іншому випадку була б складною. Якщо валідація відбувається в контексті cr-field, це прямолінійно, як у нашому попередньому прикладі з датою закінчення терміну.



 // деякий компонент з полями MM і YY  


Якщо прихований інпут не знаходиться в контексті поля, і він виконує крос-формне оновлення та валідацію, тоді cr-field має тільки зворотний зв'язок.
Рішенням є введення типу type:hidden.

Ось швидкий приклад, припустимо, якщо операційна система — це MAC, мінімальна версія має бути 5.

/* приклад компонентів форми */  

Вибір ОС    Windows    Mac    Linux    Android           
Версія ОС    

Оновлення полів оновлює приховане поле plugs з відповідним значенням або null

template: `    
    // ...          
`      
// у коді  
updatePlug() {    
  // при зміні введення форми оновлюємо приховане поле    
  const os = this.fg.get('os').value;    
  const version = this.fg.get('version').value;    
  if (os === '2' && version < 5) {    
    this.fg.get('plugs').setValue(null);    
  } else {    
    this.fg.get('plugs').setValue('plug'+ os + version);    
  }   
}  

Отже, єдине, про що я хочу потурбуватися, це приховати зірочку для обов'язкових полів і зробити відгук більш неплаваючим елементом. Інші стилі повинні бути розміщені поза компонентом.

 // давайте додамо type:hidden           

І ми враховуємо стиль cr-hidden:

/* input.css */  
.cr-field.cr-hidden {  
  .cr-label {  
    display: none;  
  }  
  .cr-input[required] ~ .cr-required {  
    display: none;  
  }  
  .cr-feedback {  
    float: none;  
    margin-block-start: 0;  
    margin-inline-start: 0;  
  }  
}  

Це буде виглядати ось так:

pic

Звісно, моя валідація дещо спрощена для демонстраційних цілей. Приховане поле може мати будь-яку валідацію (наприклад, патерн), ви можете використовувати setErrors замість setValue і налаштувати повідомлення про помилки відповідно. Це не вплине на CSS.

Автозаповнені поля

Останню проблему для виправлення становлять автозаповнені поля, такі як ім’я користувача та пароль, де ви не хочете, щоб підказка для мітки з’являлася зверху поля. Для цього ми вводимо новий тип static, щоб запобігти анімації плаваючої мітки.

pic

Хоча це не є жорстким рішенням, було б добре мати ще один стиль для неплаваючих міток в загальному.


CSS тоді визначає новий тип:

/* input.css */  
.cr-field.cr-static {  
  /* примусове плаваюче поле, навіть якщо воно порожнє */  
  .cr-label:has(~ .cr-input:placeholder-shown) {  
    transform: translateY(-100%) scale(0.8);  
  }  
}  

І це найкраще, що можна зробити. Зверніть увагу, що якщо поле буде порожнім, то ця мітка не буде плавати всередині поля. Така ціна — недорога.

pic

Ось і все.
Це завершення.

Бонус: імпорти безпосередньо

Ще одне, що ми можемо зробити, щоб зробити це зручнішим у використанні, — це помістити їх у експортований const, щоб імпортувати разом.

export const InputComponent = [  
 InputDirective,  
 CrInputPartial  
];

Тепер ми можемо імпортувати їх разом

// у нашому компоненті  
// ...  
imports: [...InputComponent],

Підсумок

Підсумовуючи, початковими цілями були наступні:

  • Використовувати нативні HTML елементи вводу.
    Ми це зробили, з додаванням лише formControlName та директиви
  • Правила валідації мають бути мінімальними.
    Ми лише змінювали повідомлення про помилки і містили базові патерни та загальні функції
  • Залишати форму Angular максимально гнучкою (не перевинаходити колесо).
    Введення є контентом, воно належить оригінальній формі
  • Використовувати атрибути замість Form builder (не нав'язливо).
    Ми реалізували директиву, яка читає різні атрибути
  • Залишати подачу форми гнучкою, щоб дозволити максимально можливу гнучкість.
    Оскільки форма не є частиною нашої директиви, нічого не нав'язується
  • Мінімальний стиль, що дозволяє повну заміну.
    Ми намагалися. Думаю, нам вдалося.

Ось і все. Let Gaza Live.

Ресурси

[

Останні коригування стилю валідації - Sekrab Garage

Опрацювання форм Angular. Щоб додати відсутні стилі, щоб зробити їх максимально функціональними, потрібно постійно нагадувати собі…

garage.sekrab.com

](https://garage.sekrab.com/posts/validation-style-final-tweaks?source=post_page-----c41a10c038b1--------------------------------)

Перекладено з: Validation style final tweaks

Leave a Reply

Your email address will not be published. Required fields are marked *