Cómo realizar operaciones CRUD en Angular

Como habrás visto en mi blog anterior, es posible realizar operaciones CRUD en JavaScript vanilla. Sin embargo, puede ser una decisión difícil elegir JavaScript vainilla, ya que se vuelve más complicado en algún momento. Además, agregar detectores de eventos a elementos DOM agregados dinámicamente es una molestia, como vimos. Se vuelve aún más complicado para proyectos a gran escala.

Una solución es utilizar marcos modernos como Angular, React, etc. Esta publicación de blog se basa en el mismo concepto que el ejemplo anterior, pero usando Angular.

Este blog asume que ya instaló Angular-cli en su máquina. Una vez que lo tenga, cree una nueva aplicación usando el siguiente comando.

ng new ngTodo

Espere unos segundos una vez que se haya creado el proyecto y luego acceda a este proyecto. Lo primero que necesitamos es crear un nuevo componente usando el siguiente comando.

ng generate component todo

Esto creará una carpeta con el nombre todo dentro de la carpeta src / app. Esta carpeta consta de los archivos todo.component.ts, todo.component.html, todo.component.css y todo.component.spec.ts.

Todo el JavaScript se escribirá en el archivo .ts. En realidad, el código de la plantilla de TypeScript (por eso la extensión del archivo es .ts) va al archivo todo.component.html, los estilos a todo.component.css y todo.component.spec.ts es para pruebas.

Para comenzar, lo primero que debe hacerse es agregar este componente dentro del archivo "app.component.html" así:

Ahora, cuando ejecute “ng serve” y cargue la aplicación en el navegador, se cargará el componente de tareas pendientes.

Ahora es el momento de dirigirse al archivo todo.component.ts.

Debería haber algún código repetitivo escrito por angular-cli. Todo nuestro código va dentro de la clase TodoComponent.

import { Component, OnInit } from '@angular/core';
@Component({
 selector: 'app-todo',
 templateUrl: './todo.component.html',
 styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
 constructor() { }
 ngOnInit() { }
}

Primero expliquemos el código repetitivo anterior. Primero importamos el decorador de componentes y la interfaz OnInit desde el núcleo angular. A continuación se muestra la definición de decorador.

Decorator marca una clase como un componente angular y nos permite establecer metadatos de configuración que determinan cómo se debe procesar, instanciar y usar el componente en tiempo de ejecución.

Mientras

La interfaz es un gancho de ciclo de vida que se llama después de que Angular haya inicializado todas las propiedades vinculadas a datos de una directiva. Defina un ngOnInit()método para manejar cualquier tarea de inicialización adicional.

Luego, estamos exportando la clase TodoComponent para que esté disponible para su importación en el resto del proyecto. Para este ejemplo, solo necesitaremos que este componente se importe en app.module.ts para iniciar el componente.

Dado que creamos este componente usando angular-cli, esa parte ya está resuelta. Si observa el archivo app.module.ts , verá que la clase TodoComponent se importa y se agrega a la matriz de declaraciones. Agreguemos algo de código ahora.

Al igual que en nuestro ejemplo anterior, agregue una propiedad mockData a la clase como se muestra a continuación.

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
 // mockData array the includes list of objects with items mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() } ];
 constructor() { }
 ngOnInit() { }
}

Como puede ver, también agregamos el tipo "cualquiera" a mockData . TypeScript aporta estrictamente la funcionalidad de tipo a JavaScript, pero en este caso eso realmente no importa. Si dejas esa parte, aún debería estar bien.

Agreguemos algunas propiedades más a esta clase que se usarán más adelante.

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
 mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() } ];
 // properties to show hide edit form, set updated value and id. show: boolean = false; value: string; id: number;
 constructor() {}
 ngOnInit() { }
}

La propiedad show se usa para mostrar editForm, la propiedad value se usa para establecer el valor del título de edición, mientras que id se usa para asignar el id del elemento editado actualmente. Veremos esto más tarde.

Antes de continuar con la discusión, agreguemos una plantilla html que vamos a usar.

 Update 
 Add

    
  • {{item.title}} Delete Edit Complete

Aquí es donde se pueden ver un montón de diferencias. Lo primero que se nota es la "ventana emergente de edición". Tiene una directiva condicional * ngIf que muestra y oculta este fragmento de código html basado en el valor de "show" que es verdadero o falso. Esa es la propiedad que proviene del TodoComponent que configuramos anteriormente.

Luego, simplemente coloque el valor (título) usando llaves {{}} dentro del campo de texto de entrada. Finalmente, agregue un evento de clic que llamará a la función de actualización y pasará el valor del campo de entrada como argumento.

Luego está la lista ul que muestra todos los elementos. Como puede ver, el elemento li tiene * ngFor, que es una directiva repetidora . Se realiza un bucle a través mockData y en su interior podemos acceder al objeto actual y ver su título.

La directiva [ngClass] agrega la clase done al elemento li según el valor de done y la propiedad del elemento. Si es cierto, agregue la clase done que coloca line-trough en el elemento li para indicar que esta tarea se logró.

También tiene sus botones que son Eliminar, Editar y Completar. Y cada uno de ellos tiene eventos de clic que llaman a su función respectiva y pasan la identificación del elemento actual. En la función de edición junto con id, el título también se pasa como argumento.

Eso es todo para la plantilla. Regresemos a TodoComponent. Aquí no necesitamos ninguna función de renderización que teníamos en JavaScript vanilla. La lista mockData y la directiva * ngFor hacen el trabajo para renderizar. Entonces la parte R de CRUD está lista. Ejecute el servidor angular usando "ng serve" y cargue la aplicación en su navegador. Debería tener resultados similares a los siguientes:

Creemos ahora la función que es la C en CRUD.

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() }];
 show: boolean = false; value: string; id: number;
 constructor() {}
 // Create function to create new item. create(item) { this.mockData.push({ id: Date.now(), title: item, done: false, date: new Date() }); }
 ngOnInit() { }
}

La función Crear se activa cuando se hace clic en el botón AÑADIR de la plantilla. Esto es muy fácil de entender y seguir. Primero, accede a la matriz mockData usando la palabra clave this y empuja un nuevo objeto con propiedades apropiadas (como id, título, hecho y fecha, etc.). Esto hará el trabajo.

Actualice su navegador y escriba "Este es un elemento nuevo" y presione el botón AÑADIR; obtendrá un resultado similar al anterior.

Ahora continuemos con la función eliminar / eliminar que es la parte D de CRUD.

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
 mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() } ];
 show: boolean = false; value: string; id: number;
 constructor() {}
 create(item) { this.mockData.push({ id: Date.now(), title: item, done: false, date: new Date() }); }
 // delete/remove function goes here. remove(id) { this.mockData = this.mockData.filter(item => { if (item.id !== id) { return item; } }); }
 ngOnInit() { }
}

De nuevo muy simple. Filtre a través de mockData y busque el elemento actual utilizando la identificación del elemento que se eliminará y la identificación del elemento actual de mockData . Y devuelve todos los elementos excepto el que coincide con este elemento.

Actualice su navegador y elimine el primer elemento de la lista. Debe eliminarse de la pantalla de la siguiente manera:

Para la actualización, nuevamente, es lo mismo que en el ejemplo básico de JavaScript: editar es parte de dos pasos. Primero muestre el formulario de edición y luego actualice el elemento. Primero, mostremos el formulario de edición que es "edit-popup":

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
 mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() } ];
 show: boolean = false; value: string; id: number;
 constructor() {}
 create(item) { this.mockData.push({ id: Date.now(), title: item, done: false, date: new Date() }); }
 remove(id) { this.mockData = this.mockData.filter(item => { if (item.id !== id) { return item; } }); }
 // this function does the same as renderEditForm in previous blog. edit(id, title) { this.show = true; this.value = title; this.id = id; }
 ngOnInit() { }
}

The above function simply sets some TodoComponent attributes — that is, set this.show to true which displays the form. Set the value of this.value to the item’s title that is to be updated, and set this.id to the item’s id. All these attributes can then be accessed in the template and we can use them accordingly.

Now press the EDIT button for the first item and you should be able to see the edit form appear at the top of the page:

Now it’s time to write the update function that actually performs update operations — this is the U part of CRUD.

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
 mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() } ];
 show: boolean = false; value: string; id: number;
 constructor() {}
 create(item) { this.mockData.push({ id: Date.now(), title: item, done: false, date: new Date() }); }
 remove(id) { this.mockData = this.mockData.filter(item => { if (item.id !== id) { return item; } }); }
 edit(id, title) { this.show = true; this.value = title; this.id = id; }
 // function that performs update update(title) { this.mockData.map(item => { if (item.id === this.id) { item['title'] = title; } });
 this.show = false; }
 ngOnInit() { }
}

This function gets the title, that is the value of the updated input text field, as an argument. Then map through mockData and place a check to find the item that needs to be updated based on its id. Once found, replace the title property with the edited one and set this.show to false to hide the edit form.

With this part, when you press the UPDATE button, after entering the updated title you should see the updated title like this:

The final part is to mark the task as done, which function is below.

import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.css']})export class TodoComponent implements OnInit {
 mockData: any = [ { id: '1', title: 'Buy Milk.', done: false, date: new Date() }, { id: '2', title: 'Meeting with Ali.', done: false, date: new Date() }, { id: '3', title: 'Tea break.', done: false, date: new Date() }, { id: '4', title: 'Go for a run.', done: false, date: new Date() } ];
 show: boolean = false; value: string; id: number;
 constructor() {}
 create(item) { this.mockData.push({ id: Date.now(), title: item, done: false, date: new Date() }); }
 remove(id) { this.mockData = this.mockData.filter(item => { if (item.id !== id) { return item; } }); }
 edit(id, title) { this.show = true; this.value = title; this.id = id; }
 update(title) { this.mockData.map(item => { if (item.id === this.id) { item['title'] = title; } });
 this.show = false; }
 setTaskComplete(id) { this.mockData.map(item => { if (item.id === id) { item['done'] = true; } }); }
 ngOnInit() { }
}

This does pretty much the same stuff: map through mockData and find the item to be set as done based on id, and set its done property to true.

Finally, add some CSS in the todo.component.css file below.

.done { text-decoration: line-through;}

The above CSS adds a line-through to any element that has the done class, in this case tasks that are completed.

After this, press a couple of Complete buttons and you should see something similar like this:

You can see the difference between this example and the previous one using vanilla JavaScript. Angular allows us to write an approach that’s easy to understand, maintain and scale. This is beneficial in large scale applications. Vanilla JavaScript does the job, but really gets complicated once the application grows.

To get all the code written in this example, go ahead and clone the below repository.

//github.com/zafar-saleem/ngTodo