¿Cómo utilizar Angular Material para formularios en tu eCommerce?
Dominar los formularios es crucial para crear una experiencia de usuario atractiva y eficiente en cualquier aplicación eCommerce. En esta guía, exploraremos cómo integrar componentes de Angular Material, una poderosa solución de diseño de Google, para mejorar la usabilidad y apariencia de tus formularios.
¿Qué es Angular Material y por qué usarlo?
Angular Material es una colección de componentes de interfaz de usuario que siguen las directrices de Material Design, proporcionando una experiencia de usuario amigable e intuitiva. Permite a los desarrolladores crear aplicaciones rápidas y receptivas gracias a su fácil integración y capacidad para personalizar componentes visuales.
¿Cuáles son los componentes más útiles para formularios?
Algunos de los componentes clave de Angular Material ideales para formularios son:
Checkbox (Casilla de verificación): Mejora la usabilidad al ofrecer una interfaz clara y visualmente consistente.
DatePicker (Selector de fechas): Añade un selector de fechas más agradable visualmente comparado con el selector nativo del navegador.
MatFormField y MatInput: Permiten agrupar y estilizar inputs, selects y textareas con ayudas visuales y animaciones.
¿Cómo implementar un MatFormField con MatInput?
Para empezar, visita la página de Angular Material y familiarízate con la documentación y ejemplos. A continuación, te mostramos cómo implementar un campo de formulario sencillo:
<mat-form-fieldappearance="fill"><mat-label>Name</mat-label><inputmatInputplaceholder="Enter your name"required><mat-error*ngIf="name.hasError('required')">This field is required</mat-error></mat-form-field>
¿Cómo se personalizan los mensajes de error?
Utiliza el componente MatError para mostrar mensajes de error estilizados automáticamente en rojo. Aquí un ejemplo:
<mat-error*ngIf="form.get('name').hasError('maxlength')"> This field exceeds the maximum length
</mat-error>
¿Cómo integrar íconos dentro del MatFormField?
Angular Material permite la integración de íconos para mejorar la interacción visual del usuario. Puedes agregar íconos a tus campos de formulario de la siguiente manera:
<mat-form-fieldappearance="fill"><mat-label>Choose a date</mat-label><inputmatInput[matDatepicker]="picker"><mat-datepicker-togglematSuffix[for]="picker"></mat-datepicker-toggle><mat-datepicker#picker></mat-datepicker></mat-form-field>
Consejos para mejorar la accesibilidad y apariencia
Asegúrate de que todos los formularios sean accesibles, proporcionando etiquetas y alternativas a los elementos visualmente enriquecidos.
Aplica un diseño responsivo para asegurar que tu formulario se ve bien en todos los dispositivos.
Usa herramientas de edición CSS para ajustar proporciones y espaciados.
Implementar Angular Material en formularios no solo mejora la experiencia de usuario sino también facilita el desarrollo al ofrecer componentes robustos y listos para usar. Siguiendo esta guía, puedes transformar tus formularios en piezas clave de tu aplicación eCommerce. Continúa explorando todas las posibilidades que Angular Material ofrece y comparte tus experiencias y soluciones en la comunidad. ¡La práctica y la colaboración son claves para el éxito!
Implementación de Formularios con Angular Material
Implementación de Formularios con Angular Material
Alternativa para el manejo de los mensajes de error. Resulta que mat-error debe ser hijo directo de mat-form-field para que se integre bien y visualmente se vea más cool. Además con esta alternativa podría utilizar varios mensajes según el error. Recordemos que en el ng-container no se renderiza si no lo que haya adentro (Ahora que lo pienso se parece al fragment de React 🤔)
<mat-form-field><mat-label>Name</mat-label><input type="text" matInput formControlName="name"/><mat-icon matSuffix>sentiment_very_satisfied</mat-icon><mat-error *ngIf="nameField.touched && nameField.invalid"><ng-container *ngIf="nameField.hasError('required')">El campo nombre es requerido</ng-container><ng-container *ngIf="nameField.hasError('maxlength')">El campo nombre no puede tener más de 10 caracteres</ng-container></mat-error></mat-form-field>
Bueno así me quedo, como que el input de tipo color no me convence, tocaría checarle más la documentación de material haber si hay como darle un mejor aspecto.
Buenas, implemente los mismo presentado en la clase 15 con respecto a datepicker, pero me aparece el siguiente error en pantalla y no me deja avanzar en el curso.
lo resolví, si están trabajando con la versión 11 de Angular y Angular material, hagan un upgrade hasta la versión 11.2.14 del core y CLI, y al 11.2.13 en angular material. Tienen un bug interno.
no uso angular material no me gusta estoy haciendo un proyecto aparte totalmente diferente al del curso, llevo las herramientas que me da el curso a otro nivel en lo posible
html
<<form [formGroup]="form"(ngSubmit)="send()"><div formGroupName="fullName"><mat-form-field><mat-label>Name</mat-label><input type="text" formControlName="name" matInput><mat-icon matSuffix color="primary"*ngIf="isNameValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isNameInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isNameInvalid()"><mat-error *ngIf="name().hasError('required') && name().touched">Este campo es requerido</mat-error><mat-error *ngIf="name().hasError('maxlength')">El máximo son de 10 caracteres</mat-error><mat-error *ngIf="name().hasError('pattern')">El nombre no debe tener caracteres</mat-error></div><mat-form-field><mat-label>Last</mat-label><input type="text" formControlName="last" matInput><mat-icon matSuffix color="primary"*ngIf="isLastValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isLastInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isLastInvalid()"><mat-error *ngIf="last().hasError('required') && last().touched">Este campo es requerido</mat-error><mat-error *ngIf="last().hasError('maxlength')">El máximo son de 10 caracteres</mat-error><mat-error *ngIf="last().hasError('pattern')">El nombre no debe tener caracteres</mat-error></div></div><mat-form-field><mat-label>Email</mat-label><input type="email" formControlName="email" matInput><mat-icon matSuffix color="primary"*ngIf="isEmailValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isEmailInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isEmailInvalid()"><mat-error *ngIf="email().hasError('required') && email().touched">Este campo es requerido</mat-error><mat-error *ngIf="email().hasError('email') && email().touched">Este no es un email válido</mat-error></div><mat-form-field><mat-label>Phone</mat-label><input type="tel" formControlName="phone" matInput><mat-icon matSuffix color="primary"*ngIf="isPhoneValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isPhoneInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isPhoneInvalid()"><mat-error *ngIf="phone().hasError('required') && phone().touched">Este campo es requerido</mat-error></div><mat-form-field><mat-label>Color</mat-label><input type="color" formControlName="color" matInput><mat-icon matSuffix color="primary"*ngIf="isColorValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isColorInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isColorInvalid()"><mat-error *ngIf="color().hasError('required') && color().touched">Este campo es requerido</mat-error></div><mat-form-field><mat-label>Date</mat-label><input matInput formControlName="date"[matDatepicker]="picker"><mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle><mat-datepicker #picker></mat-datepicker><mat-icon matSuffix color="primary"*ngIf="isDateValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isDateInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isDateInvalid()"><mat-error *ngIf="date().hasError('required') && date().touched">Este campo es requerido</mat-error></div><mat-form-field><mat-label>Age</mat-label><input type="number" formControlName="age" matInput><mat-icon matSuffix color="primary"*ngIf="isAgeValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isAgeInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isAgeInvalid()"><mat-error *ngIf="age().hasError('required') && age().touched">Este campo es requerido</mat-error><mat-error *ngIf="age().hasError('min') && age().touched">Debe ser mayor mayot de edad</mat-error><mat-error *ngIf="age().hasError('max') && age().touched">Debe estar vivo</mat-error></div><mat-form-field><mat-label>Url</mat-label><input type="url" formControlName="url" matInput><mat-icon matSuffix color="primary"*ngIf="isUrlValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isUrlInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isUrlInvalid()"><mat-error *ngIf="url().hasError('required') && url().touched">Este campo es requerido</mat-error></div><mat-form-field><mat-label>Category</mat-label><mat-select formControlName="category"><mat-option value="cat1-db 1">category-1 showed</mat-option><mat-option value="cat2-db 2">category-2 showed</mat-option><mat-option value="cat3-db 3">category-3 showed</mat-option><mat-option value="cat4-db 4">category-4 showed</mat-option></mat-select><mat-icon matSuffix color="primary"*ngIf="isCategoryValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isCategoryInvalid()">close</mat-icon></mat-form-field><div class="messages"[class.active]="isCategoryInvalid()"><mat-error *ngIf="category().hasError('required') && category().touched">Este campo es requerido</mat-error></div><mat-form-field><mat-label>Tag</mat-label><mat-select formControlName="tag" multiple><mat-option value="tag-db 1">tag-1 showed</mat-option><mat-option value="tag-db 2">tag-2 showed</mat-option><mat-option value="tag-db 3">tag-3 showed</mat-option><mat-option value="tag-db 4">tag-4 showed</mat-option></mat-select><mat-icon matSuffix color="primary"*ngIf="isTagValid()">done</mat-icon><mat-icon matSuffix color="warn"*ngIf="isTagInvalid()">close</mat-icon></mat-form-field><mat-checkbox id="agree" formControlName="agree">Agree</mat-checkbox><div class="messages"[class.active]="isAgreeInvalid()"><mat-error *ngIf="agree().hasError('required') && agree().touched">debe aceptar los términos y condiciones
</mat-error></div><mat-radio-group formControlName="gender"><mat-radio-button value="Masculino">Masculino</mat-radio-button><mat-radio-button value="Femenino">Femenino</mat-radio-button><mat-radio-button value="Otro">Otro</mat-radio-button></mat-radio-group><div class="messages"[class.active]="isGenderInvalid()"><strong *ngIf="gender().hasError('required') && gender().touched">Este campo es requerido</strong></div><mat-radio-group formControlName="zone"><mat-radio-button value="zona-1">zona-1</mat-radio-button><mat-radio-button value="zona-2">zona-2</mat-radio-button><mat-radio-button value="zona-3">zona-3</mat-radio-button><mat-radio-button value="zona-4">zona-4</mat-radio-button></mat-radio-group><div class="messa ges"[class.active]="isZoneInvalid()"><strong *ngIf="zone().hasError('required') && zone().touched">Este campo es requerido</strong></div><button mat-raised-button type="submit" color="primary">Enviar</button></form>>
Typescript
<import{Component,OnInit}from'@angular/core';import{FormBuilder,FormGroup,Validators}from'@angular/forms';@Component({selector:'app-builder-form',templateUrl:'./builder-form.component.html',styleUrls:['./builder-form.component.scss']})exportclassBuilderFormComponentimplementsOnInit{form:FormGroup;constructor(privateformBuilder:FormBuilder){this.buildForm();}ngOnInit():void{this.name().valueChanges.subscribe(value=>console.log(value));// Observable dentro de angularthis.form.valueChanges.subscribe(value=>console.log(value));}buildForm():void{this.form=this.formBuilder.group({fullName:this.formBuilder.group({name:['',[Validators.required,Validators.maxLength(10),Validators.pattern(/^[a-zA-Z ]+$/)]],last:['',[Validators.required,Validators.maxLength(10),Validators.pattern(/^[a-zA-Z ]+$/)]]}),email:['',[Validators.required,Validators.email]],phone:['',Validators.required],color:['#FFFFFF',Validators.required],date:['',Validators.required],age:['',[Validators.required,Validators.min(18),Validators.max(100)]],url:['',Validators.required],category:['',Validators.required],tag:['',Validators.required],agree:[false,[Validators.requiredTrue]],gender:['',Validators.required],zone:['',Validators.required]});}name=()=>this.form.get('fullName.name');last=()=>this.form.get('fullName.last');email=()=>this.form.get('email');phone=()=>this.form.get('phone');color=()=>this.form.get('color');date=()=>this.form.get('date');age=()=>this.form.get('age');url=()=>this.form.get('url');category=()=>this.form.get('category');tag=()=>this.form.get('tag');agree=()=>this.form.get('agree');gender=()=>this.form.get('gender');zone=()=>this.form.get('zone');isNameValid=()=>this.name().valid&&this.name().touched;isNameInvalid=()=>this.name().invalid&&this.name().touched;isLastValid=()=>this.last().valid&&this.last().touched;isLastInvalid=()=>this.last().invalid&&this.last().touched;isEmailValid=()=>this.email().valid&&this.email().touched;isEmailInvalid=()=>this.email().invalid&&this.email().touched;isPhoneValid=()=>this.phone().valid&&this.phone().touched;isPhoneInvalid=()=>this.phone().invalid&&this.phone().touched;isColorValid=()=>this.color().valid&&this.color().touched;isColorInvalid=()=>this.color().invalid&&this.color().touched;isDateValid=()=>this.date().valid&&this.date().touched;isDateInvalid=()=>this.date().invalid&&this.date().touched;isAgeValid=()=>this.age().valid&&this.age().touched;isAgeInvalid=()=>this.age().invalid&&this.age().touched;isUrlValid=()=>this.url().valid&&this.url().touched;isUrlInvalid=()=>this.url().invalid&&this.url().touched;isCategoryValid=()=>this.category().valid&&this.category().touched;isCategoryInvalid=()=>this.category().invalid&&this.category().touched;isTagValid=()=>this.tag().valid&&this.tag().touched;isTagInvalid=()=>this.tag().invalid&&this.tag().touched;isAgreeValid=()=>this.agree().valid&&this.agree().touched;isAgreeInvalid=()=>this.agree().invalid&&this.agree().touched;isGenderValid=()=>this.gender().valid&&this.gender().touched;isGenderInvalid=()=>this.gender().invalid&&this.gender().touched;isZoneValid=()=>this.zone().valid&&this.zone().touched;isZoneInvalid=()=>this.zone().invalid&&this.zone().touched;send():void{this.form.valid?this.formValid():this.form.markAllAsTouched();}formValid():void{this.buildForm();}}>
Buenas tengo una consulta tal vez no sea especifica a formulario pero bueno, para darle un contexto, el tema es que tengo dos tabla y en una contiene todas las materia (parte derecha de la imagen) al hacer click en (+) agrega al Curso de la tabla izquierda de la imagen (la relación de Curso y Materia es N:N). Este es el codigo del boton (+) que llama a un servicio
agregarMateriaAlCurso(materia:Materia){if(this.cursoSeleccionado){this.cursoService// el metodo updatecurso crea la relacion curso materia si enviamos materiaId.updateCursoMateria(this.cursoSeleccionado.cursoId, materia.materiaId).subscribe(data=>{// actualizo las materia del cursothis.obtenerMateriasCurso(this.cursoSeleccionado.cursoId);// actualizo las materias que no estan en el cursothis.obtenerMateriasNoCurso(this.cursoSeleccionado.cursoId);this.miToast.fire({icon:'success',title:`Se agrego la Materia ${materia.materiaNombre}`});});}else{this.miToast.fire({icon:'error',title:`Debe seleccionar un Curso`});}
Mi consulta es al hacer click en el boton este tarda unos segundo en llamar al servicio y hacer toda las operaciones que en mi caso funcionan bien..pero si yo hago DOS veces click (rapidamente) este agrega dos veces la misma materia..hay alguna forma de controlar eso???
Dejo tmb el codigo del html: