7

Angular(v14) | GraphQL Client - Apollo Angular(v3) | JSON Server GraphQL Fake En...

 1 year ago
source link: https://www.learmoreseekmore.com/2022/07/angular14-grphqlclient-apollo-angularv3-json-server-graphql-fake-edpoint-crud-example.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
New%20Video%20Daily.png

In this article, we will implement Angular(v14) CRUD to consume the GraphQL endpoint using the Apollo Angular(v3) library.

GraphQL API:

  • GraphQL API mostly has a single endpoint. So data fetching or updating will be carried out by that single endpoint. For posting data or querying data, we have to follow its own syntax. GraphQL carries two essential operations:
  • Query - (Fetching Data)
  • Mutation - (Saving Data)

Create An Angular(v14) Application:

Let's create an Angular(v14) application to accomplish our demo. 
Command To Create Angular Application
ng new your_app_name
Let's install the bootstrap into our application.
npm install bootstrap
Now configure the CSS and JS links of bootstrap in 'angular.json'.
1.JPG
Let's add the bootstrap 'Navbar' component at 'app.component.html'.
src/app/app.component.html:


  1. <nav class="navbar navbar-dark bg-primary">
  2. <div class="container-fluid">
  3. <div class="navbar-brand">
  4. Fruit Basket
  5. </div>
  6. </div>
  7. </nav>

Setup JSON Server For Fake GraphQL Endpoint:

Let's use JSON Server to set up a fake GraphQL endpoint into our local machine.
Now install the JSON GraphQL server globally.
npm install -g json-graphql-server
Create a db.js file within our angular application root folder. Define the API response type with sample data in  'db.js' as below.
src/db.js:


  1. module.exports = {
  2. fruits:[
  3. id:1,
  4. name: "mango",
  5. quantity:2,
  6. price:500

Now let's add a command in 'package.json' to run the GraphQL server.

2.JPG
Now start the GraphQL server, and run the below command in the terminal.
npm run graphql-run

Then if we access the "http://localhost:3000" it opens up the GraphQL UI tool interact with the graphQL server.

3.JPG

Install Apollo Angular(GraphQL Client) Package:

Install the Apollo Angular package.
ng add apollo-angular
After the package is installed, it generates a file like the 'graphql.module.ts', in this file, we have to configure our GraphQL Url
src/app/graphql.module.ts:
4.JPG

Create A Feature Module(Fruit Module) And A Child Component(Home Component):

Let's create a Feature Module/Child Module like the 'Fruit' Module.
ng generate module fruits --routing
5.JPG
Now configure module-level routing at the 'AppRoutingModule'.
src/app/app-routing.module.ts:


  1. // existing code hidden for display purpose
  2. const routes: Routes = [{
  3. path:'',
  4. loadChildren:() => import('./fruits/fruits.module').then(_ => _.FruitsModule)
  • Here configured 'FruitModule' as a lazy loading module.

Now let's create 'Home' component at 'Fruits' Module.

ng generate component fruits/home --skip-tests
6.JPG

Add the 'Home' component route in 'FruitsRoutingModue'.

src/app/fruits/fruits-routing.module.ts:


  1. // existing code hidden for display purpose
  2. import { HomeComponent } from './home/home.component';
  3. const routes: Routes = [{
  4. path:'',
  5. component: HomeComponent

Implement Read Operation:

Let's implement the 'Read' operation, fetching data from the GraphQL endpoint and then display on UI.
Let's create a response model for our GraphQL endpoint.
ng generate interface fruits/fruits

src/app/fruits/fruits.ts:



  1. export interface Fruits {
  2. id: number;
  3. price: number;
  4. name: string;
  5. quantity: number;

Now try to frame the GraphQL 'Query' operation to fetch the data.

7.JPG
  • Here 'query' keyword classify our request as fetch operation.
  • Here 'allFruits' keyword is resolver method name at server which serves all the response. So we no need to bother about this name because it will be auto populated in the above tool or we can cross check schema that appears in the above tool.
  • Here we are requesting the server to return 'id', 'price', 'name', and 'quantity' properties only as the part of the response.
  • In the response we can observe root object 'data', then we will have property which name matches with our request resolver method(eg: allFruits).

Let's create file to store the 'Query' like 'fruits-query.ts'

ng generate class fruits/gql/fruits-query --skip-tests

src/app/fruits/gql/fruits-query.ts:



  1. import { gql } from "apollo-angular";
  2. export const GET_Fruits = gql`
  3. query{
  4. allFruits{
  5. price,
  6. name,
  7. quantity
  • Here we have enclose our 'Query' inside of the 'gql' that loads from the 'apollo-angular'.

Let's add the following logic in 'home.component.ts'.

src/app/fruits/home/home.component.ts:


  1. import { Component, OnInit } from '@angular/core';
  2. import { Apollo } from 'apollo-angular';
  3. import { map, Observable, of } from 'rxjs';
  4. import { Fruits } from '../fruits';
  5. import { GET_Fruits } from '../gql/fruits-query';
  6. @Component({
  7. selector: 'app-home',
  8. templateUrl: './home.component.html',
  9. styleUrls: ['./home.component.css'],
  10. export class HomeComponent implements OnInit {
  11. constructor(private apollo: Apollo) {}
  12. allFruits$: Observable<Fruits[]> = of([]);
  13. ngOnInit(): void {
  14. this.allFruits$ = this.apollo
  15. .watchQuery<{ allFruits: Fruits[] }>({ query: GET_Fruits })
  16. .valueChanges.pipe(map((result) => result.data.allFruits));
  • (Line: 13) Injected the 'Apollo' instance that loads from the 'apollo-angular'.
  • (Line: 15) Declare and initialized the 'allFruits$' variable of type 'Observable<Fruits[]>'.
  • (Line: 18-20) Here 'watchQuery<{ allFruits: Fruits[] }>()' used for GraphQL 'Query' operation. It takes our 'GET_Fruits' as input parameter. Finally assigning the API response to the 'allFruits$' variable.
src/app/fruits/home/home.component.html:


  1. <div class="container">
  2. <table class="table">
  3. <thead>
  4. <tr>
  5. <th scope="col">Id</th>
  6. <th scope="col">Name</th>
  7. <th scope="col">Quantity</th>
  8. <th scope="col">Price</th>
  9. </tr>
  10. </thead>
  11. <tbody>
  12. <tr *ngFor="let item of allFruits$ | async">
  13. <th scope="row">{{ item.id }}</th>
  14. <td>{{ item.name }}</td>
  15. <td>{{ item.quantity }}</td>
  16. <td>{{ item.price }}</td>
  17. </tr>
  18. </tbody>
  19. </table>
  20. </div>
19.JPG

Create 'Add' Component:

Let's create a new component like 'Add' under the 'Fruits' module.
ng generate component fruits/add --skip-tests
Let's configure the 'Add' component route in 'FruitRouteModule'.
src/app/fruits/fruits-routing.module.ts:


  1. import { AddComponent } from './add/add.component';
  2. // existing code for display purpose
  3. const routes: Routes = [
  4. path: 'add',
  5. component: AddComponent

Implement Create Operation:

Let's implement 'Create' operation like posting data to the GraphQL endpoint.
Let's try to frame the GraphQL 'Mutation' operation to save the data.
8.JPG
  • Here 'mutation' keyword represent posting the data.Here 'String!'(Non-nullable string), 'Int!'(Non-nullable initiger types) are GraphQL type. Here '$name', '$quantity', '$price' variable names at the bottom where we pass our data to them.
  • Here 'createFruit' is an resolver method, I framed this 'Mutation' based on the schema provided by the tool above.
Let's create a file for GraphQL 'mutations' like 'fruits-mutation.ts'
ng generate class fruits/gql/fruits-mutation --skip-tests

src/app/fruits/gql/fruits-mutation.ts:



  1. import { gql } from "apollo-angular";
  2. export const CREATE_Fruit = gql`
  3. mutation($name:String!, $quantity:Int!, $price: Int!){
  4. createFruit(name:$name, quantity: $quantity, price: $price){
  5. name,
  6. quantity,
  7. price
  • Here our mutation wrapped around the 'gql' that loads from the 'apollo-angular'.

Let's add the following logic into 'add.component.html'.

src/app/fruits/add/add.component.html:


  1. import { Component, OnInit } from '@angular/core';
  2. import { Router } from '@angular/router';
  3. import { Apollo } from 'apollo-angular';
  4. import { Fruits } from '../fruits';
  5. import { CREATE_Fruit } from '../gql/fruits-mutation';
  6. import { GET_Fruits } from '../gql/fruits-query';
  7. @Component({
  8. selector: 'app-add',
  9. templateUrl: './add.component.html',
  10. styleUrls: ['./add.component.css'],
  11. export class AddComponent implements OnInit {
  12. constructor(private apollo: Apollo, private router: Router) {}
  13. fruitForm: Fruits = {
  14. id: 0,
  15. name: '',
  16. price: 0,
  17. quantity: 0,
  18. ngOnInit(): void {}
  19. create() {
  20. this.apollo
  21. .mutate<{ createFruit: Fruits }>({
  22. mutation: CREATE_Fruit,
  23. variables: {
  24. name: this.fruitForm.name,
  25. price: this.fruitForm.price,
  26. quantity: this.fruitForm.quantity,
  27. update: (store, { data }) => {
  28. if (data?.createFruit) {
  29. var allData = store.readQuery<{ allFruits: Fruits[] }>({
  30. query: GET_Fruits,
  31. if (allData && allData?.allFruits?.length > 0) {
  32. var newData: Fruits[] = [...allData.allFruits];
  33. newData?.unshift(data.createFruit);
  34. store.writeQuery<{ allFruits: Fruits[] }>({
  35. query: GET_Fruits,
  36. data: { allFruits: newData },
  37. .subscribe(({ data }) => {
  38. this.router.navigate(['/']);
  • (Line: 14) Injected 'Apollo' instance that loads from the 'apollo-angular'. Injected 'Router' instance that loads from the '@angular/router'.
  • (Line: 16-21) Declare and initialize the 'fruitForm' variable for form binding.
  • (Line: 26-54) GraphQL mutation invocation.
  • (Line: 27) The 'Apollo.mutate()' method invokes the GraphQL endpoint for saving new record.
  • (Line: 28) Our 'mutation:Create_Fruit' mutation operation.
  • (Line: 29-33) To pass payload to GraphQL endpoint we have to use the 'variables'. Here we mapped our 'fruitFrom' data to the 'variables'.
  • (Line: 34:50) The 'update' property registered with arrow function for updating the angular-apollo cache. By default angular-apollo save the data in 'in-memroy' cache, so newly created record need to updated to cache so that record will be displayed on the table content of 'Home' component.The arrow function contains 2 input parameter like 'store' and '{data}'(mutation response object).
  • (Line: 36-38) The 'store.readQuery' to fetch the data from the in-memory cache store. Here we use 'GET_Fruits' as 'query'.
  • (Line: 41-42)  Pusssing all data from cache into variable 'newData'. Atlast pushing our newly created record into the 'newData'.
  • (Line: 44-47) The 'store.writeQuery' save our 'newData' into the in-memory  cache store.

src/app/fruits/add/add.component.html:



  1. <div class="container">
  2. <legend>Create Item</legend>
  3. <form>
  4. <div class="mb-3">
  5. <label for="txtName" class="form-label">Name</label>
  6. <input
  7. type="text"
  8. name="name"
  9. [(ngModel)]="fruitForm.name"
  10. class="form-control"
  11. id="txtName"
  12. />
  13. </div>
  14. <div class="mb-3">
  15. <label for="txtPrice" class="form-label">Price</label>
  16. <input
  17. type="number"
  18. name="price"
  19. [(ngModel)]="fruitForm.price"
  20. class="form-control"
  21. id="txtPrice"
  22. />
  23. </div>
  24. <div class="mb-3">
  25. <label for="txtQuantity" class="form-label">Quantity</label>
  26. <input
  27. type="number"
  28. name="quantity"
  29. [(ngModel)]="fruitForm.quantity"
  30. class="form-control"
  31. id="txtQuantity"
  32. />
  33. </div>
  34. <button type="button" (click)="create()" class="btn btn-primary">
  35. Create
  36. </button>
  37. </form>
  38. </div>
  • Here added simple form for creating the new item.

Now in 'FruitsModule' import the 'FormsModule'.

src/app/fruits/fruits.module.ts:


  1. import { FormsModule } from '@angular/forms';
  2. // existing code hidden for display purpose
  3. @NgModule({
  4. imports: [FormsModule],
  5. export class FruitsModule {}

(step1)

9.JPG

(step2)

10.JPG

Implement Read Operation With Filters:

Let's implement the 'Read' operation with filters to fetch the data from the GraphQL endpoint.
Now try to frame the GraphQL query operation with filter parameters.
11.JPG
  • Here you can see 'FruitFilter' is a custom type that was at GraphQL serve. It contains different filtering parameters like 'id', 'name', 'name_eq', 'quantity_le', etc can be identify at schema in above tool
  • Here '$fruitFilter' is our variable name.
Let's add our 'query' operation with filters in our 'fruits-query.ts'.
src/app/fruits/gql/fruits-query.ts:


  1. export const GET_Search = gql`
  2. query($fruitFilter:FruitFilter){
  3. allFruits(filter:$fruitFilter){
  4. price
  5. quantity

Let's add a search by name functionality in the 'Home' component. Add the following HTML in 'home.component.html'.

src/app/fruits/home/home.component.html:


  1. <div class="container">
  2. <div class="row mt-2">
  3. <div class="col col-md-4">
  4. <a class="btn btn-primary" routerLink="/add">Create</a>
  5. </div>
  6. <div class="col col-md-6 offset-md-2">
  7. <div class="input-group mb-3">
  8. <input type="text" class="form-control"[(ngModel)]="searchName" placeholder="Search By Name" aria-label="Recipient's username" aria-describedby="button-addon2">
  9. <button class="btn btn-outline-primary" (click)="search()"type="button" id="btnsearch">Search</button>
  10. </div>
  11. </div>
  12. </div>
  13. <table class="table">
  14. <!-- exising code hideen for display purpose -->
  15. </table>
  16. </div>
  • (Line: 8) The 'Input' filed for search. Enabled model binding with 'searchName' property.
  • (Line: 9) Add the 'search' button whose click event registered with the 'search()' method.

Let's implement the 'search()' method in the 'app.component.ts' file.

src/app/fruits/home/home.component.ts:


  1. // existing code hidden for display purpose
  2. export class HomeComponent implements OnInit {
  3. searchName:string = '';
  4. search() {
  5. this.allFruits$ = this.apollo.watchQuery<{ allFruits: Fruits[] }>({
  6. query: GET_Search,
  7. variables: { fruitFilter: {name:this.searchName} },
  8. .valueChanges.pipe(map((result) => result.data.allFruits));
  • (Line: 3) Declared and initialized the 'searchName' property which is used for model binding with the search box text field.
  • (Line: 8) The 'searchName' is passed as a value to the 'variables'.
12.JPG

Create 'Edit' Component:

Let's create a new angular component like 'Edit' under the 'Fruits' Module.
ng generate component fruits/edit --skip-tests
Now configure the 'Edit' component route in 'Fruits' module.
src/app/fruits/fruits-routing.module.ts:


  1. import { EditComponent } from './edit/edit.component';
  2. // existing code hidden for display purpose
  3. const routes: Routes = [
  4. path: 'edit/:id',
  5. component: EditComponent,
  • Here edit component route contains a dynamic value that is our 'id' of the item we want to edit.

Implement Update Operation:

Let's implement the 'Update' operation like posting the item to be updated to the GraphQL endpoint.
Now frame the 'mutation' operation for the update.
13.JPG
  • Here 'updateFruit' is the server resolver name we can identify it from the schema in the above tool.
  • Here 'ID!'(Non-nullable JSON ID type), 'String!'(non-nullable string type), 'Int!'(non-nullable intiger type) are GraphQL types
  • Here '$id', '$name', '$quantity', '$price' are GraphQL variables for posting the data.
Let's add the 'mutation' operation for the update operation in the 'fruits-mutation.ts'.
src/app/fruits/gql/fruits-mutation.ts:


  1. export const Update_Fruit = gql`
  2. mutation($id:ID!,$name:String!, $quantity:Int!, $price: Int!){
  3. updateFruit(id:$id,name:$name, quantity: $quantity, price: $price){
  4. name,
  5. quantity,
  6. price

Let's update the logic in 'edit.component.ts' as follows.

src/app/fruits/edit/edit.component.ts:


  1. import { Component, OnInit } from '@angular/core';
  2. import { ActivatedRoute, Router } from '@angular/router';
  3. import { Apollo } from 'apollo-angular';
  4. import { Fruits } from '../fruits';
  5. import { Update_Fruit } from '../gql/fruits-mutation';
  6. import { GET_Fruits, GET_Search } from '../gql/fruits-query';
  7. @Component({
  8. selector: 'app-edit',
  9. templateUrl: './edit.component.html',
  10. styleUrls: ['./edit.component.css'],
  11. export class EditComponent implements OnInit {
  12. constructor(
  13. private route: ActivatedRoute,
  14. private apollo: Apollo,
  15. private router: Router
  16. fruitForm: Fruits = {
  17. id: 0,
  18. name: '',
  19. price: 0,
  20. quantity: 0,
  21. ngOnInit(): void {
  22. this.route.paramMap.subscribe((params) =< {
  23. var id = Number(params.get('id'));
  24. this.getById(id);
  25. getById(id: number) {
  26. this.apollo
  27. .watchQuery>{ allFruits: Fruits[] }<({
  28. query: GET_Search,
  29. variables: { fruitFilter: { id } },
  30. .valueChanges.subscribe(({ data }) =< {
  31. var fruritById = data.allFruits[0];
  32. this.fruitForm = {
  33. id: fruritById.id,
  34. name: fruritById.name,
  35. price: fruritById.price,
  36. quantity: fruritById.quantity,
  37. update() {
  38. this.apollo
  39. .mutate>{ updateFruit: Fruits }<({
  40. mutation: Update_Fruit,
  41. variables: {
  42. name: this.fruitForm.name,
  43. price: this.fruitForm.price,
  44. quantity: this.fruitForm.quantity,
  45. id: this.fruitForm.id,
  46. update: (store, { data }) =< {
  47. if (data?.updateFruit) {
  48. var allData = store.readQuery>{ allFruits: Fruits[] }<({
  49. query: GET_Fruits,
  50. if (allData && allData?.allFruits?.length < 0) {
  51. var newData: Fruits[] = [...allData.allFruits];
  52. newData = newData.filter((_) =< _.id !== data.updateFruit.id);
  53. newData.unshift(data.updateFruit);
  54. store.writeQuery>{ allFruits: Fruits[] }<({
  55. query: GET_Fruits,
  56. data: { allFruits: newData },
  57. .subscribe(({ data }) =< {
  58. this.router.navigate(['/']);
  • (Line: 15) Injected the 'ActivatedRoute' that loads from the '@angular/router'.
  • (Line: 16) Injected the 'Apollo' that loads from the 'apollo-angular'
  • (Line: 17) Injected the 'Router' that loads from the '@angular/router'.
  • (Line: 20-25) The 'fruitForm' declare and initialized which we will use for form model binding.
  • (Line: 28-31) Reading the item 'id' from the URL.
  • (Line: 34-49) The 'getById()' method invokes GraphQL endpoint to fetch the item by 'id'. On successful response, we assign the data to our edit form.
  • (Line: 37-38) Here we use the 'Get_Serch' query operator and in the variable, we pass the 'id' value.
  • (Line: 51-83) The 'update()' method to invoke GraphQL endpoint to updating the records.
  • (Line: 54) The 'Update_Fruit' is our mutation operation
  • (Line: 55-60) Assigning our form data to the GraphQL variables.
  • (Line: 61-78) Just like we updated the apollo-graphql in-memory cache in create operation here also we are updating the record in the in-memory cache.

src/app/fruits/edit/edit.component.html:



  1. <div class="container">
  2. <legend>Edit Item</legend>
  3. <form>
  4. <div class="mb-3">
  5. <label for="txtName" class="form-label">Name</label>
  6. <input
  7. type="text"
  8. name="name"
  9. [(ngModel)]="fruitForm.name"
  10. class="form-control"
  11. id="txtName"
  12. />
  13. </div>
  14. <div class="mb-3">
  15. <label for="txtPrice" class="form-label">Price</label>
  16. <input
  17. type="number"
  18. name="price"
  19. [(ngModel)]="fruitForm.price"
  20. class="form-control"
  21. id="txtPrice"
  22. />
  23. </div>
  24. <div class="mb-3">
  25. <label for="txtQuantity" class="form-label">Quantity</label>
  26. <input
  27. type="number"
  28. name="quantity"
  29. [(ngModel)]="fruitForm.quantity"
  30. class="form-control"
  31. id="txtQuantity"
  32. />
  33. </div>
  34. <button type="button" (click)="update()" class="btn btn-primary">
  35. update
  36. </button>
  37. </form>
  38. </div>
  • Here form binding is carried with the 'fruitForm' variable and the 'Update' button click event registered with the 'update()' method.

Let's add the 'Edit' button in 'home.component.html'

src/app/fruits/home/home.component.html:


  1. <td>
  2. <a class="btn btn-primary" [routerLink]="['edit', item.id]"
  3. >Edit</a>
  4. </td>

(step 1)

14.JPG

(step 2)

15.JPG

(step 3)

16.JPG

Implement Delete Operation:

Let's implement the 'Delete' operation by invoking the GraphQL endpoint for removing the item.
Now frame the mutation operation for removing the item.
17.JPG
  • Here 'removeFruit' is a GraphQL server resolver method we can identify at the above tool
  • Here we use '$id' variable to pass the item 'id' to delete the item at the server
Now let's add our delete mutation command in 'fruits-mutation'.
src/app/fruits/gql/fruits-mutation:
export const Delete_Fruit = gql`
mutation($id:ID!){
  removeFruit(id:$id){
    id
  }
}
`

Let's update the logic in the 'home.component.ts' as follows.

src/app/fruits/home/home.component.ts:


  1. import { Component, OnInit } from '@angular/core';
  2. import { Apollo } from 'apollo-angular';
  3. import { map, Observable, of } from 'rxjs';
  4. import { Fruits } from '../fruits';
  5. import { Delete_Fruit } from '../gql/fruits-mutation';
  6. import { GET_Fruits, GET_Search } from '../gql/fruits-query';
  7. declare var window: any;
  8. @Component({
  9. selector: 'app-home',
  10. templateUrl: './home.component.html',
  11. styleUrls: ['./home.component.css'],
  12. export class HomeComponent implements OnInit {
  13. constructor(private apollo: Apollo) {}
  14. allFruits$: Observable<Fruits[]> = of([]);
  15. searchName: string = '';
  16. deleteModal: any;
  17. idTodelete: number = 0;
  18. ngOnInit(): void {
  19. this.deleteModal = new window.bootstrap.Modal(
  20. document.getElementById('deleteModal')
  21. this.allFruits$ = this.apollo
  22. .watchQuery<{ allFruits: Fruits[] }>({ query: GET_Fruits })
  23. .valueChanges.pipe(map((result) => result.data.allFruits));
  24. search() {
  25. this.allFruits$ = this.apollo
  26. .watchQuery<{ allFruits: Fruits[] }>({
  27. query: GET_Search,
  28. variables: { fruitFilter: { name: this.searchName } },
  29. .valueChanges.pipe(map((result) => result.data.allFruits));
  30. openDeleteModal(id: number) {
  31. this.idTodelete = id;
  32. this.deleteModal.show();
  33. delete() {
  34. this.apollo
  35. .mutate<{ removeFruit: Fruits }>({
  36. mutation: Delete_Fruit,
  37. variables: {
  38. id: this.idTodelete,
  39. update: (store, { data }) => {
  40. if (data?.removeFruit) {
  41. var allData = store.readQuery<{ allFruits: Fruits[] }>({
  42. query: GET_Fruits,
  43. if (allData && allData?.allFruits?.length > 0) {
  44. var newData: Fruits[] = [...allData.allFruits];
  45. newData = newData.filter((_) => _.id == data.removeFruit.id);
  46. store.writeQuery<{ allFruits: Fruits[] }>({
  47. query: GET_Fruits,
  48. data: { allFruits: newData },
  49. .subscribe(({ data }) => {
  50. this.deleteModal.hide();
  • (Line: 21) Here declare 'deleteModal' variable.
  • (Line: 22) Here declare 'idToDelete' variable.
  • (Line: 25-27) Here assign the bootstrap instance to the 'deleteModal' variable.
  • (Line: 43-46) Here 'openDeleteModal' method shows the delete confirmation modal.
  • (Line: 49-76) Here 'delete()' invokes the GraphQL endpoint for deleting the item.
  • (Line: 51) Here 'Delete_Fruit' our mutation operator.
  • (Line: 53) Passing our 'idToDelete' value to the GraphQL variable
  • (Line: 55-71) Using the 'update' method remove the item from the local in-memory cache.
  • (Line: 74) Close the bootstrap modal popup

src/app/fruits/home/home.component.html:



  1. <div class="container">
  2. <div class="row mt-2">
  3. <div class="col col-md-4">
  4. <a class="btn btn-primary" routerLink="/add">Create</a>
  5. </div>
  6. <div class="col col-md-6 offset-md-2">
  7. <div class="input-group mb-3">
  8. <input
  9. type="text"
  10. class="form-control"
  11. [(ngModel)]="searchName"
  12. placeholder="Search By Name"
  13. aria-label="Recipient's username"
  14. aria-describedby="button-addon2"
  15. />
  16. <button
  17. class="btn btn-outline-primary"
  18. (click)="search()"
  19. type="button"
  20. id="btnsearch"
  21. Search
  22. </button>
  23. </div>
  24. </div>
  25. </div>
  26. <table class="table">
  27. <thead>
  28. <tr>
  29. <th scope="col">Id</th>
  30. <th scope="col">Name</th>
  31. <th scope="col">Quantity</th>
  32. <th scope="col">Price</th>
  33. </tr>
  34. </thead>
  35. <tbody>
  36. <tr *ngFor="let item of allFruits$ | async">
  37. <th scope="row">{{ item.id }}</th>
  38. <td>{{ item.name }}</td>
  39. <td>{{ item.quantity }}</td>
  40. <td>{{ item.price }}</td>
  41. <td>
  42. <a class="btn btn-primary" [routerLink]="['edit', item.id]">Edit</a> |
  43. <button
  44. type="button"
  45. (click)="openDeleteModal(item.id)"
  46. class="btn btn-danger"
  47. Delete
  48. </button>
  49. </td>
  50. </tr>
  51. </tbody>
  52. </table>
  53. </div>
  54. <!-- Modal -->
  55. <div
  56. class="modal fade"
  57. id="deleteModal"
  58. tabindex="-1"
  59. aria-labelledby="exampleModalLabel"
  60. aria-hidden="true"
  61. <div class="modal-dialog">
  62. <div class="modal-content">
  63. <div class="modal-header">
  64. <h5 class="modal-title" id="exampleModalLabel">Warning!</h5>
  65. <button
  66. type="button"
  67. class="btn-close"
  68. data-bs-dismiss="modal"
  69. aria-label="Close"
  70. ></button>
  71. </div>
  72. <div class="modal-body">Are you sure to delete the item?</div>
  73. <div class="modal-footer">
  74. <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
  75. Close
  76. </button>
  77. <button type="button" class="btn btn-danger" (click)="delete()">
  78. Confirm Delete
  79. </button>
  80. </div>
  81. </div>
  82. </div>
  83. </div>
  • (Line: 44-50) Added the 'Delete' button registered the click event with 'openDeleteModal()'.
  • (Line: 58-87) Bootstrap Modal HTML.
  • (Line: 81-83) Added the 'Confirm Delete' button registered the click event with 'delet()'.
18.JPG

Support Me!
Buy Me A Coffee PayPal Me

Wrapping Up:

Hopefully, I think this article delivered some useful information on the Angular 14 CRUD sample by consuming the GraphQL endpoint using the Angular Apollo library. using I love to have your feedback, suggestions, and better techniques in the comment section below.

Refer:

Follow Me:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK