Tercer reto: Mejorar aspecto del input. Bonus: Barra de carga que se va llenando gracias al Observable task.percentageChanges()
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
No se trata de lo que quieres comprar, sino de quién quieres ser. Aprovecha el precio especial.
Antes: $249
Paga en 4 cuotas sin intereses
Termina en:
Aportes 9
Preguntas 4
Tercer reto: Mejorar aspecto del input. Bonus: Barra de carga que se va llenando gracias al Observable task.percentageChanges()
**Reto 1 **
<a mat-raised-button color="accent" routerLink="create">Crear categoría</a>
<div class="product-grid">
<div *ngFor="let category of categories">
<mat-card>
<mat-card-header>
<mat-card-title>{{ category.name | uppercase }}</mat-card-title>
</mat-card-header>
<div class="crop-image">
<img [src]="category.image" alt="">
</div>
<mat-card-content>
<p>
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Nunc convallis eget ante ut imperdiet.
Nunc ipsum lorem, accumsan eu lobortis
ac, luctus at leo. Nullam tortor sapien,
mollis quis suscipit nec, tincidunt sed
quam. Orci varius natoque penatibus et
magnis dis parturient montes, nascetur
ridiculus mus. Mauris id pretium augue.
Integer lacinia mi lorem, a blandit enim
hendrerit vitae. Cras vestibulum diam urna,
fermentum ante elementum sed.
</p>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button>Editar</button>
<button mat-raised-button color="warn">Eliminar</button>
</mat-card-actions>
</mat-card>
</div>
</div>
Reto 2
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormControl, Validators, FormBuilder, FormGroup} from '@angular/forms';
import { finalize } from 'rxjs/operators';
import { CategoriesService } from './../../../../core/services/categories.service';
import { Category } from 'src/app/core/models/category.model';
import { AngularFireStorage } from '@angular/fire/storage';
import { v4 as uuidv4 } from 'uuid';
@Component({
selector: 'app-category-form',
templateUrl: './category-form.component.html',
styleUrls: ['./category-form.component.scss']
})
export class CategoryFormComponent implements OnInit {
form: FormGroup;
constructor(
private formBuilder: FormBuilder,
private categoriesService: CategoriesService,
private router: Router,
private storage: AngularFireStorage
) {
this.buildForm();
}
ngOnInit(): void {
}
private buildForm() {
this.form = this.formBuilder.group({
name: ['', Validators.required],
image: ['', Validators.required]
});
}
get nameField() {
return this.form.get('name');
}
get imageField() {
return this.form.get('image');
}
save() {
if (this.form.valid) {
this.createCategory();
} else {
this.form.markAllAsTouched();
}
}
private createCategory() {
const data = this.form.value;
this.categoriesService.createCategory(data)
.subscribe(rta => {
console.log(rta);
this.router.navigate(['./admin/categories']);
});
}
uploadFile(event) {
event.preventDefault();
const image = event.target.files[0];
const name = `${uuidv4()}.png`;
const ref = this.storage.ref(name);
const task = this.storage.upload(name, image);
task.snapshotChanges()
.pipe(
finalize(() => {
const urlImage$ = ref.getDownloadURL();
urlImage$.subscribe(url => {
console.log(url);
this.imageField.setValue(url);
});
})
)
.subscribe();
}
}
Reto 3
<form [formGroup]="form" (ngSubmit)="save()">
<mat-card>
<mat-card-header>
<mat-card-content>
<div class="row">
<div class="col-xs">
<mat-form-field>
<mat-label>Nombre</mat-label>
<input placeholder="Nombre" formControlName="name" matInput type="text">
<div class="messages" *ngIf="nameField.touched && nameField.invalid">
<mat-error *ngIf="nameField.hasError('required')">
Este campo es requerido
</mat-error>
</div>
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-xs">
<img *ngIf="imageField.value" [src]="imageField.value" alt=""/>
<button (click)="fileInput.click()" mat-mini-fab color="primary">
<mat-icon>perm_media</mat-icon>
</button>
<input #fileInput (change)="uploadFile($event)" placeholder="Image" type="file" style="display: none;">
<div class="messages" *ngIf="imageField.touched && imageField.invalid">
<mat-error *ngIf="imageField.hasError('required')">
Este campo es requerido
</mat-error>
</div>
</div>
</div>
</mat-card-content>
<mat-card-actions>
<button mat-raised-button type="submit">Guardar categoría</button>
</mat-card-actions>
</mat-card-header>
</mat-card>
</form>
En la actualidad tuve que modificar la forma en que se suben los archivos, porque de la manera que la explican ya no me funciono:
Aqui está el código.
import { Storage, ref, uploadBytes, listAll, getDownloadURL, StorageReference } from '@angular/fire/storage';
constructor(
private storage: Storage
) { }
uploadFile(event: any) {
const image = event.target.files[0];
const name = image.name;
const imgRef = ref(this.storage,`imagenes/${name}`);
const task = uploadBytes(imgRef,image);
task
.then(response => {
console.log(response);
this.getImage(name)
})
.catch(error => console.log(error))
}
getImage(nameImage:string) {
const imgRef = ref(this.storage, 'imagenes')
listAll(imgRef)
.then( async rta => {
const itemActual: StorageReference|undefined = rta.items.find(item => item.name === nameImage);
if(itemActual){
const url = await getDownloadURL(itemActual)
this.imageField?.setValue(url);
console.log(url);
}
})
}
Para instalar y configurar Firebase Storage
https://platzi.com/clases/1670-angular/23286-instalar-angular-firebase-y-configurar-firebase-au/
Lo que aprendimos en la clase:
Tercer reto cumplido, me guié del trabajo que hizo el compañero Juan Carlos Pinzón, me gustó mucho el haber utilizado el mat-progress-bar:
Primer reto:
Segundo reto:
Tercer reto:
Primer reto
Segundo reto
const image = event.target.files[0];
const name = `${image.name}`;
const ref = this.storage.ref(name);
const task = this.storage.upload(name, image);
Tercer reto
HTMl
<button (click)="uploadImage($event)" mat-fab color="primary"><mat-icon>insert_photo</mat-icon></button>
<input hidden (change)="uploadFile($event)" placeholder="Image" #fileInput type="file" id="file">
TS
uploadImage(event): void {
event.preventDefault();
const fileInput = document.getElementById('file');
fileInput.click();
}
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?