Introducción a Angular y Fundamentos

1

Aprende Angular 17

2

Creando tu primer proyecto en Angular

3

Implementando estilos

4

Mostrando elementos

5

Property Binding en Angular

6

Event Binding: click y doble click

7

Event binding: keydown

8

Modelo de reactividad con Signals

9

Creando un Signal en Angular

Estructuras de control en Angular

10

Directivas de control

11

Uso de ngFor

12

ngFor para objetos

13

Update Tasks

14

Uso de ngIf

15

Uso de ngSwitch y ngSwitchDefault

16

Controlando un input

17

Manejo de formularios en Angular

Alistando tu aplicación para producción

18

Estilos al modo Angular

19

Clases en Angular

20

Editing mode

21

Estados compuestos con computed

22

Usando effect para localStorage

23

Uso de ngbuild

24

Despliegue con Firebase Hosting

25

Nueva sintaxis en Angular

26

Directivas @For, @switch

27

Migrando a la nueva sintaxis de Angular v17

Componentes Reutilizables y Comunicación

28

Construyendo un e-commerce en Angular

29

Componentes en Angular

30

Mostrando los componentes

31

Angular DevTools

32

Uso de Inputs en Angular

33

Uso de Outputs en Angular

34

Componentes para Producto

Ciclo de vida de los componentes

35

Ciclo de vida de componentes

36

Ciclo de vida de componentes: ngOnChanges

37

Ciclo de vida de componentes: ngOnInit

38

Detectando cambios en los inputs

39

Evitando memory leaks con ngDestroy

40

Audio player con ngAfterViewInit

41

Creando la página "about us" o "conócenos"

Mejorando la interfaz del producto

42

Creando componente de productos

43

Creando el Header

44

Creando el carrito de compras

45

Comunicación padre e hijo

46

Calculando el total con ngOnChanges

47

El problema del prop drilling

48

Reactividad con signals en servicios

49

Entendiendo la inyección de dependencias

Integración y Datos

50

Obteniendo datos una REST API

51

Importaciones cortas en Typescript

52

Pipes en Angular

53

Construyendo tu propio pipe

54

Utilizando librerías de JavaScript en Angular

55

Conociendo las directivas

56

Deployando un proyecto en Vercel

Enrutamiento y Navegación

57

Ruta 404

58

Uso del RouterLink

59

Vistas anidadas

60

Uso del RouterLinkActive

61

Detalle de cada producto

62

Obteniendo datos del producto

63

Galería de imagenes

64

Detalle de la galería

Perfeccionando tu e-commerce

65

Mostrando categorias desde la API

66

Url Params

67

LazyLoading y Code Splitting

68

Aplicando LazyLoading

69

Prefetching

70

Usando la nueva sintaxis de Angular 17

71

Lanzando tu aplicación a producción

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Manejo de formularios en Angular

17/71
Recursos

Aportes 37

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Busque y busque y me encontré con pattern y bueno aplique una expresión regular ayudandome de chatgpt

validators: [
  Validators.required,
  Validators.pattern('^\\S.*$'),
  Validators.minLength(3),
],

Luego usando trim(), para eliminar los espacios al inicio y al final, por si las dudas jejeje

this.tasks.update((previous) => [
  ...previous,
  { title: value.trim(), completed: false },
]);

Si es inválido o si son espacios en blanco, lo ignoro. Le quito espacios en blanco al guardar el value también.

Yo lo hice de esta manera: ![](https://static.platzi.com/media/user_upload/image-531aad8e-14b8-4fb6-9a34-8e4c5f089e54.jpg)
```js if(this.newTaskCtrl.valid && this.newTaskCtrl.value.trim().length > 5){ const value = this.newTaskCtrl.value.trim(); this.addTask(value); this.newTaskCtrl.setValue(''); } ```Esta es la forma en la que realice la validación para evitar que se envíen valores compuestos solo de espacios. También añadí una validación para que el tamaño del texto de la tarea sea mayor que 5 caracteres.
```js taskinput = new FormControl('',{ nonNullable:true, validators:[ Validators.required, Validators.pattern('^\\S.*$'), Validators.minLength(3), Validators.maxLength(50) ] }); ```
lo hice con un .trim()! Me parecio lo más práctico: addTodo() { const newValue = this.newTodoCtrl.value.trim(); if (newValue) { const newTodo = { name: newValue, completed: false, id: this.generateId(), }; this.todos.update((todos) => \[...todos, newTodo]); this.newTodoCtrl.setValue(''); } else { alert('Please enter a task'); this.newTodoCtrl.setValue(''); } } ```js addTodo() { const newValue = this.newTodoCtrl.value.trim(); if (newValue) { const newTodo = { name: newValue, completed: false, id: this.generateId(), }; this.todos.update((todos) => [...todos, newTodo]); this.newTodoCtrl.setValue(''); } else { alert('Please enter a task'); this.newTodoCtrl.setValue(''); } } ```
![](https://static.platzi.com/media/user_upload/image-980fdba2-f2c6-4a6c-980c-58122039d9bb.jpg)
## Mi solución: Al if dentro del inputHandler, agregarle que si el valor es válido con un .trim() al final ```js if(this.newTaskControl.valid && this.newTaskControl.value.trim()) { this.addTask(this.newTaskControl.value); this.newTaskControl.setValue(''); } ```
Hice esto:  changeHandler() {    if(*this*.newTaskCtrl.valid && *this*.newTaskCtrl.value.trim() !== ''){      const value = *this*.newTaskCtrl.value      *this*.addTask(value);      *this*.newTaskCtrl.setValue('');    } else if (*this*.newTaskCtrl.value.trim() === '') {      *this*.newTaskCtrl.setValue('');    }  } ```js changeHandler() { if(this.newTaskCtrl.valid && this.newTaskCtrl.value.trim() !== ''){ const value = this.newTaskCtrl.value this.addTask(value); this.newTaskCtrl.setValue(''); } else if (this.newTaskCtrl.value.trim() === '') { this.newTaskCtrl.setValue(''); } } ```
Esta fue mi solución: Solo agregué el trim y la condicional para agregar: `if(this.newTaskCtrl.valid ){      const value = this.newTaskCtrl.value.trim();      value !== '' && this.addTask(value);      this.newTaskCtrl.setValue('');    }`
Lo que yo hice fue crear una función que bloquea el input para agregar espacios:  // Validación personalizada para evitar espacios en blanco  noWhitespaceValidator(): ValidatorFn {    return (control: AbstractControl): ValidationErrors | null => {      const isWhitespace = (control.value || '').trim().length === 0;      const isValid = !isWhitespace;      return isValid ? null : { whitespace: true };    };  } ```js // Validación personalizada para evitar espacios en blanco noWhitespaceValidator(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const isWhitespace = (control.value || '').trim().length === 0; const isValid = !isWhitespace; return isValid ? null : { whitespace: true }; }; } ```y solamente fue agregar en el newTaskCtrl, el validator: this.noWhitespaceValidator()
```js validators:[ Validators.required, Validators.pattern('^[^\\s].*'), Validators.minLength(4) ] ```
Solución: ```js newTaskCntrl = new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.pattern(/^(?!\s*$).+/)], }); ``` newTaskCntrl = new FormControl('', { nonNullable: true, validators: \[Validators.required, Validators.pattern(/^(?!\s\*$).+/)], });
Para poner en blanco el input se puede utilizar esto: ```js this.newTaskCntrl.reset(); ```En vez de esto: ```js this.newTaskCntrl.setValue(''); ```
Compañeros quiero compartir mi solución, solo agregue una validación un patron de caracteres que recibirá el input ```js newTaskCtrl = new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.pattern('^[a-zA-Z0-9]+$')], }); ```
Mi propuesta de como resolver el reto ```ts public changeHandler(): void { if (this.newTaskCtrl.valid) { const value = this.newTaskCtrl.value.trim(); if (value.length === 0) return; this.addTask(value); this.newTaskCtrl.setValue(''); } else { alert('El campo es obligatorio'); } } ```

Yo lo hice de esta manera

changeHandler(){
    const isWhitespace = this.newTaskCtrl.value.trim().length === 0     
  
    if(this.newTaskCtrl.valid && !isWhitespace){
      const newTask = this.newTaskCtrl.value;
      this.addTask(newTask);
      this.newTaskCtrl.setValue("");
    } 
  } 
asi estaba mal mi handler? handlerInput() { const handlerValue = this.newTask.value.trim() if(handlerValue.length > 1){ this.createTodo(handlerValue) } }

Me gusta más la practica de solo capturar cuando el input no sea valido y realizar las operaciones necesarias fuera del if

  // methods
  addTodo() {
    if (!this.titleControl.valid) {
      return;
    }

    const title = this.titleControl.value;

    const newTodo: Task = {
      id: Date.now(),
      title,
      completed: false,
    };

    this.todos.update((todo) => [...todo, newTodo]);
  }
Asi mismo, el uso de minLenght y maxLenght deberia ser de uso obligatorio, por que en el mundo real siempre debes determinar la cantidad de caracteres que un usuario debe ingresar a la base de datos. Aqui esta mi solución:

Para este logica tome los siguientes escenarios.

Algunas tareas podría venir con espacios y serán válidas como por ejemplo.

  • Course angular 17
  • Course Unit test.

Pero si la casilla solo tiene espacios no se agregara ningún nuevo ítem.

Custom Validación de espacios.


import { AbstractControl, ValidationErrors } from '@angular/forms';  
    
export class TaskWhiteSpace {  
    static noSpaceAllowed(control: AbstractControl) : ValidationErrors | null {  
        if (!control.value || control.value == undefined) return null;

        let chars = Array.from(control.value);
        let counterSpaces = 0;

        chars.forEach(c => {if (c == ' ') counterSpaces++ });

        if (chars.length > counterSpaces) return null;
        return {noSpaceAllowed: true}  
    }  
}

y ya en el componente importo el custom de validación personalizada.

Para esta actividad tome base la siguiente fuente.
ejemplo

Una opción para lo que se pide es crear tu propia función de validación para luego pasarla junto con los validadores, esta función en este caso la cree en la misma clase pero lo suyo es tenerla en otro sitio donde tengas todas las funciones de validación custom para tu app ```js validatorNoWhitespace = (control: AbstractControl): ValidationErrors | null => { if (control.value.trim().length === 0) { return { noWhitespace: true }; } return null; } newTaskCtrl = new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.minLength(3), this.validatorNoWhitespace] }); ```
`changeHandler(){    if(this.newTaskCtrl.valid && this.newTaskCtrl.value.trim()){      ` `const value = this.newTaskCtrl.value;      this.addTask(value);      this.newTaskCtrl.setValue('');    ` `}}`
```ts @Component({ selector: 'app-home', standalone: true, imports: [CommonModule, ReactiveFormsModule], templateUrl: './home.component.html', styleUrl: './home.component.css' }) export class HomeComponent { // Props tasks = signal<Task[]>([]); newTaskControl = new FormControl('', { nonNullable: true, validators: [ Validators.required, // Custom validation (control) => { if (!control.value.trim()) { return { whitespace: true } } return null; }, ], }); // Methods changeHandler() { if (this.newTaskControl.valid) { this.addTask(this.newTaskControl.value.trim()); this.newTaskControl.setValue(''); } }; // ...rest of the code } ``` ---
```js addTask(title: string) { const newTask = { id: crypto.randomUUID(), title, completed: false } this.tasks.update(prevTasks => [newTask, ...prevTasks]) } handleTask() { const titleTask = this.newTaskCtrl.value.trim() titleTask && this.addTask(titleTask) this.newTaskCtrl.setValue('') } ```
Mi solución: ![](https://static.platzi.com/media/user_upload/carbon-be3cb1dd-a5cb-48d1-a1d5-11698c867121.jpg)
![](https://static.platzi.com/media/user_upload/image-4d812eb3-2c2c-4fb1-9d98-55a5d4057616.jpg)
A mi se me ocurrio esta solucion sencilla sin FormControl. Tiene algo de malo modificar de esta forma directa el DOM? `changeHandler(event: Event) {` ` if (!(event.target instanceof HTMLInputElement)) return;` ` if (event.target.value === "") return;` ` const newTaskText = event.target.value;` ` this.addTask(newTaskText);` ` event.target.value = "";` `}`
![](https://static.platzi.com/media/user_upload/image-c1772f78-4829-4b5d-a2d4-a9c34ed389d9.jpg)
addTodoReactivo(){    console.log('a');    if(this.newTask.valid && !this.validarInput(this.newTask.value)){      const value= this.newTask.value;      this.addTodo(value);      this.newTask.setValue('');    }  }   validarInput(entrada:string){    const regexEspaciosEnBlanco = /\s/;    return regexEspaciosEnBlanco.test(entrada);  }
```ts changeHandler() { const isWhiteSpace = this.newTaskInput.value.trim().length === 0; if (this.newTaskInput.invalid || isWhiteSpace) return; const value = this.newTaskInput.value; this.addTask(value); this.newTaskInput.reset(); } ```
`value.trim() ==="" && alert('Espacio vacio')`
la verdad lo de los espacio, lo realice así: `  changleHandler() {    const value = this.newTaskCtrl.value;` `    if (this.newTaskCtrl.valid) {      this.addTask(value);      this.newTaskCtrl.setValue('');      if (value.trim() === "") {        alert('Espacio vacio')      }    }  }`

✅

Usé una expresión regular para el reto y creé mejor solo una función para agregar tareas 👇

agregarTarea(){
    const regex = /^\s+$/;

    if(this.newTaskCtrl.valid && !regex.test(this.newTaskCtrl.value)){
      const value = this.newTaskCtrl.value;
      const tarea = {
        id: Date.now(),
        title: value,
        completed: false,
      }
      this.tasks.update((tasks => [...tasks, tarea]));
    }
    
    this.newTaskCtrl.setValue('');
  }
Agregué un setvalue con el valor con Trim antes de verificar la validez `  ` `changeHandler() {    this.newTaskCtrl.setValue(this.newTaskCtrl.value.trim());    ` `if (this.newTaskCtrl.valid) {      ` `const`` newTasks = this.newTaskCtrl.value;      this.addTask(newTasks);      ` `this.newTaskCtrl.setValue('');    }  ` `}`
Mi solución: ```js keyDownTask(){ if(this.newTaskCtrl.valid){ const value = this.newTaskCtrl.value; if(value.trim().length !== 0){ this.addTask(value); } this.newTaskCtrl.setValue(''); } } ```keyDownTask(){    if(this.newTaskCtrl.valid){      const value = this.newTaskCtrl.value;      if(value.trim().length !== 0){        this.addTask(value);      }      this.newTaskCtrl.setValue('');    }  }