Πώς να εκτελέσετε λειτουργίες CRUD στο Angular

Όπως ίσως έχετε δει στο προηγούμενο blog μου, είναι δυνατό να κάνετε CRUD λειτουργίες σε JavaScript βανίλιας. Ωστόσο, μπορεί να είναι μια δύσκολη απόφαση να επιλέξετε JavaScript βανίλιας καθώς γίνεται πιο ακατάστατο σε κάποιο σημείο. Επιπλέον, η προσθήκη ακροατών συμβάντων σε δυναμικά προστιθέμενα στοιχεία DOM είναι πόνος, όπως είδαμε. Γίνεται ακόμη πιο περίπλοκο για έργα μεγάλης κλίμακας.

Μία λύση είναι η χρήση σύγχρονων πλαισίων όπως το Angular, το React και ούτω καθεξής. Αυτή η ανάρτηση ιστολογίου βασίζεται στην ίδια ιδέα με το προηγούμενο παράδειγμα, αλλά χρησιμοποιώντας το Angular.

Αυτό το ιστολόγιο προϋποθέτει ότι έχετε ήδη εγκαταστήσει το Angular-cli στον υπολογιστή σας. Μόλις το έχετε, δημιουργήστε μια νέα εφαρμογή χρησιμοποιώντας την παρακάτω εντολή.

ng new ngTodo

Περιμένετε λίγα δευτερόλεπτα μόλις δημιουργηθεί το έργο και, στη συνέχεια, cd σε αυτό το έργο. Το πρώτο πράγμα που χρειαζόμαστε είναι να δημιουργήσουμε ένα νέο στοιχείο χρησιμοποιώντας την παρακάτω εντολή.

ng generate component todo

Αυτό θα δημιουργήσει ένα φάκελο με το όνομα todo μέσα στο φάκελο src / app. Αυτός ο φάκελος αποτελείται από αρχεία todo.component.ts, todo.component.html, todo.component.css και todo.component.spec.ts.

Όλο το JavaScript θα γραφτεί στο αρχείο .ts. Στην πραγματικότητα ο κώδικας προτύπου TypeScript (αυτός είναι ο λόγος για τον οποίο η επέκταση αρχείου είναι .ts) πηγαίνει στο αρχείο todo.component.html, τα στυλ στο todo.component.css και το todo.component.spec.ts είναι για δοκιμές.

Για να ξεκινήσετε, το πρώτο πράγμα που πρέπει να γίνει είναι να προσθέσετε αυτό το στοιχείο μέσα στο αρχείο "app.component.html" όπως:

Τώρα, όταν εκτελείτε το "ng serve" και φορτώνετε την εφαρμογή στο πρόγραμμα περιήγησης, θα φορτωθεί το στοιχείο todo.

Τώρα ήρθε η ώρα να κατευθυνθείτε στο αρχείο todo.component.ts.

Πρέπει να υπάρχει κάποιος κωδικός λέβητας γραμμένος από το angular-cli. Όλος ο κώδικάς μας μπαίνει στην τάξη 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() { }
}

Ας εξηγήσουμε πρώτα τον παραπάνω κωδικό boilerplate. Πρώτα εισάγουμε τον Διακοσμητή Component και τη διεπαφή OnInit από τον πυρήνα Angular. Παρακάτω είναι ο ορισμός του διακοσμητή.

Το Decorator επισημαίνει μια τάξη ως γωνιακό στοιχείο και μας επιτρέπει να ορίσουμε μεταδεδομένα διαμόρφωσης που καθορίζουν τον τρόπο επεξεργασίας, δημιουργίας και χρήσης του στοιχείου κατά την εκτέλεση.

Ενώ

Το Interface είναι ένας γάντζος κύκλου ζωής που καλείται αφού η Angular έχει αρχικοποιήσει όλες τις ιδιότητες μιας οδηγίας που δεσμεύονται από δεδομένα. Ορίστε μια ngOnInit()μέθοδο για τον χειρισμό τυχόν πρόσθετων εργασιών αρχικοποίησης.

Στη συνέχεια εξάγουμε την κλάση TodoComponent για να το κάνουμε διαθέσιμο για εισαγωγή στο υπόλοιπο έργο. Για αυτό το παράδειγμα, θα χρειαστεί να εισαχθεί αυτό το στοιχείο μόνο στο app.module.ts για να ξεκινήσει το στοιχείο.

Δεδομένου ότι δημιουργήσαμε αυτό το στοιχείο χρησιμοποιώντας το γωνιακό-cli, το τμήμα αυτό έχει ήδη φροντιστεί. Εάν κοιτάξετε το αρχείο app.module.ts , θα δείτε ότι η κλάση TodoComponent εισάγεται και προστίθεται στον πίνακα δηλώσεων. Ας προσθέσουμε λίγο κώδικα τώρα.

Όπως και το προηγούμενο παράδειγμα, προσθέστε μια ιδιότητα mockData στην τάξη όπως παρακάτω.

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() { }
}

Όπως μπορείτε να δείτε, προσθέσαμε επίσης τον τύπο "οποιοδήποτε" στο mockData . Το TypeScript φέρνει αυστηρά λειτουργικότητα τύπου στο JavaScript, αλλά σε αυτήν την περίπτωση που πραγματικά δεν έχει σημασία. Εάν αφήσετε αυτό το μέρος από αυτό, θα πρέπει να είναι εντάξει.

Ας προσθέσουμε μερικές ακόμη ιδιότητες σε αυτήν την τάξη που θα χρησιμοποιηθούν αργότερα.

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() { }
}

Η ιδιότητα εμφάνισης χρησιμοποιείται για την εμφάνιση του editForm, η τιμή της ιδιότητας χρησιμοποιείται για τον καθορισμό της τιμής του τίτλου επεξεργασίας, ενώ το αναγνωριστικό χρησιμοποιείται για την εκχώρηση του αναγνωριστικού του τρέχοντος επεξεργασμένου στοιχείου. Θα το δούμε αργότερα.

Πριν προχωρήσουμε σε περαιτέρω συζήτηση, ας προσθέσουμε ένα πρότυπο html που πρόκειται να χρησιμοποιήσουμε.

 Update 
 Add

    
  • {{item.title}} Delete Edit Complete

Εδώ μπορεί να δει κανείς πολλές διαφορές. Το πρώτο πράγμα που είναι αισθητό είναι το "edit-popup". Έχει μια οδηγία * ngIf υπό όρους που εμφανίζει και κρύβει αυτό το κομμάτι κώδικα html με βάση την τιμή του "show" που είναι είτε αληθές είτε λάθος. Αυτή είναι η ιδιότητα που προέρχεται από το TodoComponent που ρυθμίσαμε νωρίτερα.

Στη συνέχεια, απλώς τοποθετήστε την τιμή (τίτλος) χρησιμοποιώντας {{}} τιράντες μέσα στο πεδίο κειμένου εισαγωγής. Τέλος, προσθέστε ένα συμβάν κλικ που θα καλέσει τη συνάρτηση ενημέρωσης και θα μεταβιβάσει την τιμή του πεδίου εισαγωγής ως όρισμα.

Στη συνέχεια, υπάρχει η λίστα ul που δείχνει όλα τα στοιχεία. Όπως μπορείτε να δείτε, το στοιχείο li έχει * ngFor το οποίο είναι μια οδηγία επαναλήπτη . Βγαίνει μέσω mockData και μέσα σε αυτό έχουμε πρόσβαση στο τρέχον αντικείμενο και εμφανίζουμε τον τίτλο του.

Η οδηγία [ngClass] προσθέτει την ολοκληρωμένη κλάση στο στοιχείο li με βάση την αξία του ολοκληρωμένου και της ιδιότητας του αντικειμένου. Εάν είναι αλήθεια, προσθέστε την ολοκληρωμένη κλάση που βάζει τη γραμμή στο στοιχείο li για να δείξει ότι αυτή η εργασία επιτεύχθηκε.

Διαθέτει επίσης τα κουμπιά του τα οποία είναι τα κουμπιά Διαγραφή, Επεξεργασία και Πλήρης. Και κάθε ένα από αυτά έχει συμβάντα κλικ που καλούν την αντίστοιχη συνάρτηση και μεταβιβάζουν το αναγνωριστικό του τρέχοντος στοιχείου. Στη συνάρτηση επεξεργασίας παράλληλα με το αναγνωριστικό, ο τίτλος περνά επίσης ως όρισμα.

So that’s it for the template. Let’s head back to the TodoComponent. Here we do not need any render function which we had in vanilla JavaScript.The mockData list and *ngFordirective do the job for rendering. So the R part of CRUD is done. Run the angular server using “ng serve” and load the application in your browser. You should have similar results like below:

Let’s now create the function which is the C in 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() { }
}

The Create function is triggered when the ADD button is clicked from the template. This is very easy to understand and follow. First, it accesses the mockData array using the this keyword and pushes a new object with appropriate properties (like id, title, done and date etc). This will do the job.

Refresh your browser and type “This is a new item” and press the ADD button — you’ll get a similar result to the above.

Now let’s continue to the remove/delete function which is the D 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() }); }
 // delete/remove function goes here. remove(id) { this.mockData = this.mockData.filter(item => { if (item.id !== id) { return item; } }); }
 ngOnInit() { }
}

Again very simple. Filter through mockData and find the current element using the item’s id that is to be deleted and the id of the current element from mockData. And return all the items except the one that matches this element.

Refresh your browser and delete the first item from the list. It should be deleted from the screen as below:

For update, again, it’s the same as the vanilla JavaScript example: edit is part of two steps. First show the edit form, and second update the item. First let’s show the edit form which is “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;}

Το παραπάνω CSS προσθέτει ένα line-through σε οποιοδήποτε στοιχείο έχει την ολοκληρωμένη κλάση, σε αυτήν την περίπτωση εργασίες που έχουν ολοκληρωθεί.

Μετά από αυτό, πατήστε μερικά πλήκτρα και θα δείτε κάτι παρόμοιο όπως αυτό:

Μπορείτε να δείτε τη διαφορά μεταξύ αυτού του παραδείγματος και του προηγούμενου χρησιμοποιώντας JavaScript βανίλιας. Το Angular μας επιτρέπει να γράψουμε μια προσέγγιση που να είναι κατανοητή, να διατηρείται και να κλιμακώνεται. Αυτό είναι ευεργετικό σε εφαρμογές μεγάλης κλίμακας. Η Vanilla JavaScript κάνει τη δουλειά, αλλά πραγματικά γίνεται πολύπλοκη μόλις μεγαλώσει η εφαρμογή.

Για να γράψετε όλο τον κώδικα σε αυτό το παράδειγμα, προχωρήστε και κλωνοποιήστε το παρακάτω αποθετήριο.

//github.com/zafar-saleem/ngTodo