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
You don't have access to this class
Keep learning! Join and start boosting your career
Uploading images to a server using a form may seem like a complex task, but with the right tools, everything becomes simpler. In this section, we will explore how to integrate FiberStorage into an Angular project to upload images efficiently, and how to use reactive forms to manage this functionality.
FiberStorage is a service that allows you to store files in the cloud, providing URLs that can be used later in web applications. This service is especially useful for managing images:
To allow image uploads, we need to modify the HTML form and file management logic in Angular:
<input type="file" (change)="uploadFile($event)">
uploadFile(event: Event) { const file = (event.target as HTMLInputElement).files[0]; const fileName = 'category.png'; // Consider a random name to avoid conflicts}
To handle cloud storage, it is necessary to import and configure Angular FiberStorage inside our project:
import { AngularFireStorage } from '@angular/fire/storage';
constructor(private storage: AngularFireStorage) {}
const fileRef = this.storage.ref(fileName);const uploadTask = this.storage.upload(fileName, file);
uploadTask.snapshotChanges().pipe( finalize(() => { fileRef.getDownloadURL().subscribe(url => { console.log('File available at: ', url);', url); }); }) ).subscribe();
To improve the user experience, it is advisable to provide a preview of the image:
<img*ngIf="imagePreview" [src]="imagePreview">
uploadFile(event: Event) { const file = (event.target as HTMLInputElement).files[0]; const reader = new FileReader(); reader.onload = () => { this.imagePreview = reader.result as string; }; reader.readAsDataURL(file);}
Stylize the category listing: make sure images are displayed correctly when editing and deleting categories.
Generate randomized file names: Avoid conflicts by generating a unique, randomized name for each uploaded image.
Improve file upload input styling: Implement a visually appealing design for the file selector with CSS or by using style libraries.
Explore these enhancements to fully master the FiberStorage integration and optimize your forms in Angular. Constant practice will allow you to effectively manage file uploads, vital for modern applications. Keep learning and overcoming challenges!
Contributions 8
Questions 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>
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();
}
Want to see more contributions, questions and answers from the community?