Quarkus + Angular with Keycloak — Pt3
Published: 2023-03-23 02:40:41

On this article, we 'll finish the development of our daily-quotes application. If you haven’t seen the **second part**, click [here](https://dev.to/ricardohsmello/quarkus-angular-with-keycloak-pt2-1903). The main goal of this part is implement a communication between the frontend and the backend.

## Angular Application

Let’s change our Angular application and generate some components that will add and list quotes. Let’s divide it into two groups:

1. Create quote-list
2. Create quote-add

---

## Create quote-list
Generating Quote class:

```
$ ng generate class quote
```

**Generating Service:**

```
$ ng generate service quote-service
```

**Generating quote-list component:**

```
$ ng generate component quote-list
```

**Implementing components**
In this step we 'll change the generated components.

Open quote.ts and add the following fields:

```
export class Quote {
    message?: string;
    author?: string;
}
```

Open quote-service.service.ts and create a findAll method and define the backend restAPI http://localhost:8080/quote

```
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Quote } from 'src/app/model/quote';

@Injectable({
  providedIn: 'root'
})
export class QuoteService {

  private quoteUrl: string;

  constructor(private http: HttpClient) {
    this.quoteUrl = 'http://localhost:8080/quote';
  }

  public findAll(): Observable<Quote[]> {
    return this.http.get<Quote[]>(this.quoteUrl);
  }
}
```

Open quote-list.component.ts and inject and implement service:

```
import { Component, OnInit } from '@angular/core';
import { Quote } from '../model/quote';
import { QuoteService } from '../services/quote/quote-service.service';
 
@Component({
  selector: 'app-quote-list',
  templateUrl: './quote-list.component.html',
  styleUrls: ['./quote-list.component.scss']
})
export class QuoteListComponent implements OnInit {

  quotes?: Quote[];

  constructor(private quoteService: QuoteService) {
  }

  async ngOnInit() {
      this.quoteService.findAll().subscribe(data => {
      this.quotes = data;
    });
  }

}
```

Open quote-list.component.html must be like this:

```
<div class="container">
    <div class="row" *ngFor="let quote of quotes">
        <div class="col-sm-12">
    
           <blockquote class="blockquote">
                <p class="mb-0">
                   {{quote.message}}
                </p>
                <footer class="blockquote-footer">
                    {{quote.author}}
                </footer>
            </blockquote>
        </div>
    </div>
</div>   
```
Declaring QuoteListComponent and import HttpClientModule on app.module.ts:

```
@NgModule({
  declarations: [
    AppComponent,
    **QuoteListComponent**,
    NavbarComponent,
    AdminComponent,
  ],
  imports: [
    BrowserModule,
    CommonModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatButtonModule,
    MatMenuModule,
    MatIconModule,
    KeycloakAngularModule,
    **HttpClientModule**,
  ],
```
Adding QuoteListComponent route on app-routing.module.ts:

```
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { QuoteAddComponent } from './component/quote-add/quote-add.component.component';
import { QuoteListComponent } from './component/quote-list/quote-list.component';


const routes: Routes = [
  { path: 'home', component: AppComponent },
  { path: 'quotes', component: QuoteListComponent },
  { path: 'add', component: QuoteAddComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```

Finally, we have to enable http.cors on application.properties in Quarkus backend:

```
quarkus.http.cors=true
%dev.quarkus.http.cors.origins=/.*/
```

> Very good 😍! We have finished implementing of quote listing route. Now, we are able to get quote from backend.

## Create quote-add
Generating quote-add component:

```
$ ng generate component quote-add
```

**Implementing components**
In this step we 'll change the generated components.

Open quote-add.component.ts

```
import {Component, Inject} from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import { Quote } from 'src/app/model/quote';
import { QuoteService } from 'src/app/services/quote/quote-service.service';
 
export interface DialogData {
  message: string;
  author: string;
}

@Component({
  selector: 'app-quote-add',
  templateUrl: './quote-add.component.html',
  styleUrls: ['./quote-add.component.scss']
})

export class QuoteAddComponent {

  constructor(
    public dialogRef: MatDialogRef<QuoteAddComponent>,
    @Inject(MAT_DIALOG_DATA) public data: DialogData,
    private quoteService: QuoteService
  ) {}

  onNoClick(): void {
    this.dialogRef.close();
  }

}
```

Open quote-add.component.html

```
<div class="form">
    <h1 mat-dialog-title>Create new Quote</h1>

    <div mat-dialog-content>
        <mat-form-field class="field-author" appearance="outline">
            <mat-label>Author</mat-label>
            <input matInput [(ngModel)]="data.author">

        </mat-form-field>
        <mat-form-field class="field-message" appearance="outline">
            <mat-label>Message</mat-label>
            <textarea matInput [(ngModel)]="data.message"></textarea>
        </mat-form-field>
    </div>
</div>
<div mat-dialog-actions class="buttons">
    <button mat-button (click)="onNoClick()">Cancel</button>
    <button mat-button [mat-dialog-close]="data">Create</button>
</div>
```

Open quote-add.component.scss

```
.form {
    max-width: 500px;
    width: 100%;
    margin: 10px;
}

.field-author {
    align-items: center;
    margin: 10px;
}

.field-message {
    width: 400px;
    margin: 5px;
}

.buttons {
    align-items: center;
    background-color: deepskyblue;
    margin: 10px;
}
```

Open navbar.component.ts and change the content. It should be like this:

```
import { Component, OnInit } from '@angular/core';
import { KeycloakService } from 'keycloak-angular';
import { MatDialog } from '@angular/material/dialog';
import { QuoteAddComponent } from '../quote-add/quote-add.component';
import { QuoteService } from 'src/app/services/quote/quote-service.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss']
})


export class NavbarComponent implements OnInit {
  constructor(
    private readonly keycloak: KeycloakService,
    public dialog: MatDialog,
    public quoteService: QuoteService,
    public router: Router
    ) { }

  public hasAdminRole: boolean = false;

  message?: string; 
  author?: string;
  
  ngOnInit(): void {
    this.hasAdminRole = this.keycloak.getUserRoles().includes('admin');
   }
 
  public async logout() {
     this.keycloak.logout();
  }

  public add() {
    const dialogRef = this.dialog.open(QuoteAddComponent, {
      data: {message: this.message, author: this.author},
    })

    dialogRef.afterClosed().subscribe(async result => {      
      (await this.quoteService.save(result)).subscribe( result =>
        this.redirectTo('quotes')
        );      
    }    

);
  }
  redirectTo(uri:string){
    this.router.navigateByUrl('/', {skipLocationChange: true}).then(()=>
    this.router.navigate([uri]));
 }

}
```

Open navbar.component.html and include the add method to new quote button:      

```
<button mat-menu-item (click)="add()">New Quote</button>
```

Lets create our add http method on quote-service.service.ts:

  ```async save(quote: Quote): Promise<Observable<Quote>>{
    return this.http.post<Quote>(this.quoteUrl, quote); 
  } ```


> Very good 😍! We have finished implementing our quote add route. Now, we are able to add new quotes.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ef8qz9jbfxlqmxr1ypj.gif)

---

**Conclusion**
On this third and last part we finished our daily-quotes application by implementing communication between the frontend and backend protected by OIDC with keycloak.

Well done guys, the whole project is available at my [gitHub](https://github.com/ricardohsmello/daily-quotes).

Feel comfortable to suggest, comment and contribute with this project.

Thanks ❤️