muchas gracias por el video, los mensajes de errores siempre han sido una agonÃa para mÃ, y en literal 5 segundos me han quedado claro!
Conoce la importancia de los formularios para tu sitio web
Versiones de Angular Forms
¿Por qué aprender Angular Forms?
Presentación del proyecto: tour por los formularios de Platzi Store
Novedades de Angular 10: cómo migrar proyectos de Angular 8 o 9 a la versión 10
Primeros pasos con Angular Forms
Template Forms vs. Reactive Forms
Dominando el FormControl y sus estados
Cómo usar inputs de texto y la importancia del type
Manejo y binding de selects y selects múltiples
Manejo y binding de inputs radio y checkbox
Aplica validaciones a un FormControl
Integración y validaciones con CSS para mostrar errores
Descubre todas las validaciones de Angular Forms
Usando FormGroup para agrupar multiples campos
Reactive Forms con FormBuilder
Los 11 validadores de Angular (y expresiones regulares)
Manejando múltiples FormsGroups
Usando componentes de Angular Material
Errores comunes de usabilidad en formularios
Validaciones personalizadas: mejorando nuestro formulario de registro
Implemeta validaciones avanzadas en PlatziStore
Cómo hacer validaciones grupales en Angular Forms
Validaciones condicionadas y reactividad a variaciones en la UI
Proyecto: formulario para crear categorÃas de productos
Proyecto: conectando nuestro formulario y la API
Proyecto: subir imágenes a Firebase Storage
Validaciones asincrónicas
PatchValue: crear vs. editar
Proyecto: creando el método de editar categorÃas
Construye formularios dinámicos conectando una API
Smart vs. dumb components: un patrón para dividir responsabilidades
Implementando smart y dumb components en PlatziStore
Proyecto: mejorando nuestro formulario de productos
Select dinámico: carga opciones desde una API
Select dinámico: trabajando con objetos
¿Cómo crear campos on demand? Forms dinámicos con FormArray
Estrategias avanzadas y optimización de formularios
Crea tu propia librerÃa de componentes con CVA o Control Value Accesor
Crea un buscador de gifs usando la API de Giphy
Optimiza un input de búsquedas con RxJS y debounce
Examina la accesibilidad de tus formularios
Siguientes pasos en tu carrera de desarrollo web profesional con Angular
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Convierte tus certificados en tÃtulos universitarios en USA
Antes: $249
Paga en 4 cuotas sin intereses
Termina en:
Aportes 10
Preguntas 0
muchas gracias por el video, los mensajes de errores siempre han sido una agonÃa para mÃ, y en literal 5 segundos me han quedado claro!
Febrero 10 de 2023 el api no funciona
18 de Septiembre del 2022 las endpoints no funcionan
febrero 24, 2022 las endpoints no funcionan.
Enero 27 - 2023 la API sigue sin funcionar…
El api ahora te pide que la imagen sea un array asi que lo solucione asi: primero en el formGroup ponerlo como nulo, images: [null, [Validators.required]], en el input html poner el atributo multiple y luego en el metodo uploadFile modificar el codigo del task por esto task
.snapshotChanges()
.pipe(
finalize(() => {
this.image$ = fileRef.getDownloadURL();
this.image$.subscribe((url) => {
const currentValue = this.form.get(‘images’).value || [];
const newValue = […currentValue, url];
this.form.patchValue({ images: newValue });
});
})
)
.subscribe();
Si estas viendo el video en 2023 recuerda usar la nueva version de la API:
https://api.escuelajs.co/api/v1
. Para esta clase es necesario en el HTML de products modificar los siguientes datos:
.
anterior -> nuevo
{{product._id}} -> {{product.id}},
{{product.name}} -> {{product.title}},
[routerLink]="['edit', product._id] -> [routerLink]="['edit', product.id]
Logre seguir la clase pero haciendo unas modificaciones por lo que cambio la API, comparto resultado y el codigo
codigo .html
<form [formGroup]="form" (ngSubmit)="saveProduct($event)">
<mat-card>
<mat-card-header>
<mat-card-title>Producto</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="row">
<div class="col-xs">
<mat-form-field>
<input placeholder="Title" formControlName="title" matInput type="text">
<div class="messages" *ngIf="titleField.touched && titleField.invalid">
<mat-error *ngIf="titleField.hasError('required')">Este campo es rerquerido</mat-error>
<mat-error *ngIf="titleField.hasError('minlength')">Debe tener mas de 4 caracteres</mat-error>
</div>
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-xs">
<mat-form-field>
<input placeholder="Price" formControlName="price" matInput type="number">
</mat-form-field>
<div class="messages" *ngIf="priceField.errors && priceField.dirty">
<mat-error *ngIf="priceField.hasError('price_invalid')">No te debes pasar de 10000</mat-error>
<mat-error *ngIf="priceField.hasError('required')">El campo es requerido</mat-error>
</div>
</div>
</div>
<div class="row">
<div class="col-xs">
<mat-form-field>
<textarea placeholder="Text" formControlName="description" matInput></textarea>
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-xs">
<div *ngFor="let imageField of imagesField.value">
<img *ngIf="imageField" [src]="imageField" style="width: 200px;">
</div>
<input type="file" (change)="uploadFile($event)" multiple="multiple">
</div>
</div>
<div class="row">
<div class="col-xs">
<mat-form-field>
<input placeholder="Category" formControlName="categoryId" type="number" matInput/>
</mat-form-field>
</div>
</div>
</mat-card-content>
<mat-card-actions>
<button [disabled]="form.invalid" mat-raised-button type="submit">Guardar</button>
</mat-card-actions>
</mat-card>
</form>
Codigo .ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AngularFireStorage } from '@angular/fire/storage';
import { finalize } from 'rxjs/operators';
import { MyValidators } from './../../../../utils/validators';
import { ProductsService } from './../../../../core/services/products/products.service';
import { FileModel } from './../../../../core/models/file.model'
import { Observable } from 'rxjs';
@Component({
selector: 'app-product-create',
templateUrl: './product-create.component.html',
styleUrls: ['./product-create.component.scss']
})
export class ProductCreateComponent implements OnInit {
form: FormGroup;
image$: Observable<any>;
constructor(
private formBuilder: FormBuilder,
private productsService: ProductsService,
private router: Router,
private storage: AngularFireStorage
) {
this.buildForm();
}
ngOnInit() {
}
saveProduct(event: Event) {
event.preventDefault();
if (this.form.valid) {
const product = this.form.value;
this.productsService.createProduct(product)
.subscribe((newProduct) => {
this.router.navigate(['./admin/products']);
});
}
}
uploadFile(event) {
const files = [...event.target.files] as FileModel[];
files.forEach(item => {
const name = `${item.name}`;
const fileRef = this.storage.ref(name);
const task = this.storage.upload(name, item);
task.snapshotChanges()
.pipe(
finalize(() => {
this.image$ = fileRef.getDownloadURL();
this.image$.subscribe(url => {
const fileList = this.imagesField.value as string[]
this.imagesField.setValue([...fileList, url ])
});
})
)
.subscribe();
})
if (files) {
this.imagesField.setValue([] as string[])
}
}
private buildForm() {
this.form = this.formBuilder.group({
title: ['', [Validators.required, Validators.minLength(4)]],
price: ['', [Validators.required, MyValidators.isPriceValid]],
images: [Array<string>(), Validators.required],
categoryId: ['', Validators.required],
description: ['', [Validators.required, Validators.minLength(10)]],
});
}
get titleField() {
return this.form.get('title')
}
get priceField() {
return this.form.get('price');
}
get imagesField() {
return this.form.get('images');
}
get descriptionField() {
return this.form.get('description');
}
}
Utilizando la nueva API (https://api.escuelajs.co/api/v1) me muesta los siguiente mensajes
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?