Web

New Ionic 5 Angular 8 Display, Update, and Delete Records With RxJS

mother-board

Dive deep into Ionic and Angular

This post is about displaying API records with delete and update actions using new Ionic and Angular reactive programming. This is a continuation of my Ionic Angular series in an effort to explain how to distribute data between components using RxJS methods, such as BehaviorSubject.

All of the feed API responses/records are stored in a reactive object. This will help the application’s DOM work seamlessly with update and delete operations. Implement this to your side project and enrich your applications.

Video: .

Feed Service

You may also like: Display an Interactive HERE Map in an Ionic App.

Create a Feed service for maintaining all of the data operations like display, update, and delete.

new-ionic-angular$ ionic g s services/feed
> ng generate service services/feed
CREATE src/app/services/feed.service.spec.ts (323 bytes)
CREATE src/app/services/feed.service.ts (133 bytes)

feed.service.ts
Here the feedData method connects with out API. feedData$ is a behavior subject RxJS reactive storage object. It helps you distribute data between the components. The changeFeedData method updates the reactive object value using next().

import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { HttpService } from './http.service';
@Injectable({ providedIn: 'root' }) export class FeedService { feedData$ = new BehaviorSubject<any>([]); constructor(private httpService: HttpService) {}
changeFeedData(data: any) { this.feedData$.next(data); }
feedData(postData: any): Observable<any> { return this.httpService.post('feed', postData); } }

Feed Page – feed.page.ts
Import the Feed service and on initiate(ngOnInit), make the feed API call to get the records. Construct the postData object with login user id and token values. Store the API results in the feedData$ object using the  feedService.changeFeedData method.

import { Component, OnInit } from '@angular/core'; import { FeedService } from 'src/app/services/feed.service'; import { AuthService } from './../../services/auth.service'; import { ToastService } from './../../services/toast.service';
@Component({ selector: 'app-feed', templateUrl: './feed.page.html', styleUrls: ['./feed.page.scss'] }) export class FeedPage implements OnInit { public authUser: any;
postData = { user_id: '', token: '' }; constructor( private auth: AuthService, private feedSerive: FeedService, private toastService: ToastService ) {}
ngOnInit() { this.auth.userData$.subscribe((res: any) => { this.authUser = res;
this.getFeedData(); });
}
getFeedData() { this.postData.user_id = this.authUser.uid; this.postData.token = this.authUser.token; if (this.postData.user_id && this.postData.token) { this.feedSerive.feedData(this.postData).subscribe( (res: any) => { this.feedSerive.changeFeedData(res.feedData); }, (error: any) => { this.toastService.presentToast('Network Issue.'); } ); } } }

Display Data
Generate a component for displaying feed records.

$ ionic g c components/feedCard
> ng generate component components/feedCard
CREATE src/app/components/feed-card/feed-card.component.scss (0 bytes)
CREATE src/app/components/feed-card/feed-card.component.html (28 bytes)
CREATE src/app/components/feed-card/feed-card.component.spec.ts (741 bytes)
CREATE src/app/components/feed-card/feed-card.component.ts (279 bytes)

components.module.ts
Declare and export the module for application use.

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { IonicModule } from '@ionic/angular'; import { FeedCardComponent } from './feed-card/feed-card.component'; import { SlidesComponent } from './slides/slides.component'; import { StartButtonComponent } from './start-button/start-button.component';
@NgModule({ declarations: [SlidesComponent, StartButtonComponent, FeedCardComponent], exports: [SlidesComponent, StartButtonComponent, FeedCardComponent], imports: [CommonModule, FormsModule, IonicModule] }) export class ComponentsModule {}

feed.moudle.ts
Import the components module for accessing the components.

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { IonicModule } from '@ionic/angular'; import { ComponentsModule } from './../../components/components.module'; import { FeedPage } from './feed.page';
const routes: Routes = [ { path: '', component: FeedPage } ];
@NgModule({ imports: [ CommonModule, ComponentsModule, FormsModule, IonicModule, RouterModule.forChild(routes) ], declarations: [FeedPage] }) export class FeedPageModule {}

feed.page.html
Include the  feedCard(app-feed-card) component in feed page.

<ion-header>
<ion-toolbar> <ion-title>Feed</ion-title> </ion-toolbar> </ion-header>
<ion-content> <ion-item> <h2> Welcome to {{ authUser?.name }}</h2> </ion-item> <app-feed-card></app-feed-card></ion-content>

feed-card.component.html
Design with Ionic components.

<ion-card>
<ion-card-content> feed content </ion-card-content> </ion-card>

Display Records from Reactive Object

feed-card.component.ts
Subscribe the  feedData$ objects for feed records.

import { Component, OnInit } from '@angular/core';
import { FeedService } from './../../services/feed.service';
@Component({ selector: 'app-feed-card', templateUrl: './feed-card.component.html', styleUrls: ['./feed-card.component.scss'] }) export class FeedCardComponent implements OnInit { feedData: any;
constructor(private feedSerivce: FeedService) {}
ngOnInit() { this.feedSerivce.feedData$.subscribe((res: any) => { this.feedData = res; }); } }

feed-card.component.html
Bind with HTML and iterate the feed data.

<ion-card *ngFor="let feed of feedData; let i = index">
<ion-card-content [innerHTML]="feed.feed"> </ion-card-content> </ion-card>

Delete Records

Alert Service
Generate the alert service for confirming the record delete action.

new-ionic-angular$ ionic g s services/alert
> ng generate service services/alert
CREATE src/app/services/alert.service.spec.ts (328 bytes)
CREATE src/app/services/alert.service.ts (134 bytes)

alert.service.ts
Import the Ionic component and modify the presentAlertConfirm method with dynamic inputs. This way you can reuse for other actions.

import { Injectable } from '@angular/core';
import { AlertController } from '@ionic/angular';
@Injectable({ providedIn: 'root' }) export class AlertService { constructor(public alertController: AlertController) {}
async presentAlertConfirm(header: string, message: string) { let choice; const alert = await this.alertController.create({ header: header, message: message, buttons: [ { text: 'Cancel', role: 'cancel' }, { text: 'Okay', role: 'okay' } ] });
await alert.present(); await alert.onDidDismiss().then(data => { choice = data; }); return choice; } }

feed.service.ts
Now, include the feedDelete API post request method. Here, the deleteFeedData method removes the object from the reactive object, feedData$.

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { HttpService } from './http.service';
@Injectable({ providedIn: 'root' }) export class FeedService { feedData$ = new BehaviorSubject<any>([]); constructor(private httpService: HttpService) {}
changeFeedData(data: any) { this.feedData$.next(data); }
getCurrentFeedData() { return this.feedData$.getValue(); }
deleteFeedData(msgIndex: number) { let data = []; let currentFeedData = this.getCurrentFeedData(); currentFeedData.splice(msgIndex, 1); let newFeedUpdateData = data.concat(currentFeedData); this.changeFeedData(newFeedUpdateData); }
feedData(postData: any): Observable<any> { return this.httpService.post('feed', postData); }
feedDelete(postData: any): Observable<any> { return this.httpService.post('feedDelete', postData); } }

feed-card.components.ts
Create a feedDeleteAction and connect with the feedDelete API and the alert confirm action. Then, delete the record from the behavior subject.

import { Component, Input, OnInit } from '@angular/core';
import { AlertService } from './../../services/alert.service'; import { FeedService } from './../../services/feed.service';
@Component({ selector: 'app-feed-card', templateUrl: './feed-card.component.html', styleUrls: ['./feed-card.component.scss'] }) export class FeedCardComponent implements OnInit { @Input() loginUser: any; feedData: any; postData = { user_id: '', token: '' };
constructor( private feedSerivce: FeedService, private alertSerivce: AlertService ) {}
ngOnInit() { this.feedSerivce.feedData$.subscribe((res: any) => { this.feedData = res; }); }
feedDeleteAction(msgIndex: number) {
this.postData.user_id = this.loginUser.user_id; this.postData.token = this.loginUser.token; this.alertSerivce .presentAlertConfirm('Delete feed', 'Do you want to delete this feed?') .then((res: any) => { if (res.role === 'okay') { this.feedSerivce.feedDelete(this.postData).subscribe((res: any) => { if (res.success) { this.feedSerivce.deleteFeedData(msgIndex); } }); } }); } }

feed-card.components.html
Bind the action with the delete button.

<ion-card *ngFor="let feed of feedData; let i = index">
<ion-card-content> <button (click)="feedDeleteAction(i)" class="right"> <ion-icon name="trash"></ion-icon> </button> <p [innerHTML]="feed.feed"></p> </ion-card-content></ion-card>

Update Feed
feed.server.ts
Add methods for the feedUpdate to connect the RESTful API. Push the feed data using  updateFeedData().

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { HttpService } from './http.service';
@Injectable({ providedIn: 'root' }) export class FeedService { feedData$ = new BehaviorSubject<any>([]); constructor(private httpService: HttpService) {}
changeFeedData(data: any) { this.feedData$.next(data); }
getCurrentFeedData() { return this.feedData$.getValue(); }
updateFeedData(newFeed: any) { let data = []; data.push(newFeed); let currentFeedData = this.getCurrentFeedData(); let newFeedUpdateData = data.concat(currentFeedData); this.changeFeedData(newFeedUpdateData); } deleteFeedData(msgIndex: number) { let data = []; let currentFeedData = this.getCurrentFeedData(); currentFeedData.splice(msgIndex, 1); let newFeedUpdateData = data.concat(currentFeedData); this.changeFeedData(newFeedUpdateData); }
feedData(postData: any): Observable<any> { return this.httpService.post('feed', postData); }
feedDelete(postData: any): Observable<any> { return this.httpService.post('feedDelete', postData); }
feedUpdate(postData: any): Observable<any> { return this.httpService.post('feedUpdate', postData); } }

Feed Update Component
Generate a component for feed update operations.

new-ionic-angular$ ionic g c components/feed-update ng generate component components/feed-update
CREATE src/app/components/feed-update/feed-update.component.scss (0 bytes)
CREATE src/app/components/feed-update/feed-update.component.html (30 bytes)
CREATE src/app/components/feed-update/feed-update.component.spec.ts (755 bytes)
CREATE src/app/components/feed-update/feed-update.component.ts (287 bytes)

feed-update.component.ts
Import the feed service and follow the same process similar to the feedDelete action. Construct the postData value with text.

import { Component, Input, OnInit } from '@angular/core';
import { FeedService } from './../../services/feed.service';
@Component({ selector: 'app-feed-update', templateUrl: './feed-update.component.html', styleUrls: ['./feed-update.component.scss'] }) export class FeedUpdateComponent implements OnInit { @Input() loginUser: any; public postData = { feed: '', feed_id: '', lastCreated: '', token: '', user_id: '' }; constructor(private feedService: FeedService) {}
ngOnInit() {}
feedUpdateAction() { if (this.postData.feed.length > 0) { this.postData.lastCreated = ''; this.postData.user_id = this.loginUser.user_id; this.postData.token = this.loginUser.token; this.feedService.feedUpdate(this.postData).subscribe((res: any) => { this.postData.feed = ''; this.feedService.updateFeedData(res.feedData); }); } } }

feed-update.component.html
Bind the postData value with ion-textarea. Connect the feedUpdateAction with the update button.

<ion-item>
<ion-textarea placeholder="Enter more information here..." [(ngModel)]="postData.feed"></ion-textarea> </ion-item> <ion-item> <ion-button color='mango' item-end (click)="feedUpdateAction()">Update</ion-button></ion-item>

Timeago

Install the Time Ago pipe.

$npm install time-ago-pipe --save

Then, create a web component for timeago.

new-ionic-angular$ ionic g c components/timeago
ng generate component components/timeago
CREATE src/app/components/timeago/timeago.component.scss (0 bytes)
CREATE src/app/components/timeago/timeago.component.html (26 bytes)
CREATE src/app/components/timeago/timeago.component.spec.ts (733 bytes)
CREATE src/app/components/timeago/timeago.component.ts (272 bytes)

components.module.ts
Import all of the newly generated components — feedUpdatetimeAgo, and TimeAgoPipe.

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { IonicModule } from '@ionic/angular'; import { TimeAgoPipe } from 'time-ago-pipe'; import { FeedCardComponent } from './feed-card/feed-card.component'; import { FeedUpdateComponent } from './feed-update/feed-update.component'; import { SlidesComponent } from './slides/slides.component'; import { StartButtonComponent } from './start-button/start-button.component'; import { TimeagoComponent } from './timeago/timeago.component'; @NgModule({ declarations: [ SlidesComponent, StartButtonComponent, FeedCardComponent, FeedUpdateComponent, TimeagoComponent, TimeAgoPipe ], exports: [ SlidesComponent, StartButtonComponent, FeedCardComponent, FeedUpdateComponent, TimeagoComponent ], imports: [CommonModule, FormsModule, IonicModule] }) export class ComponentsModule {}

timeago.component.ts
Using @input, retrieve the created value from the feed loop. Convert the Unix timestamp to date format.

import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-timeago', templateUrl: './timeago.component.html', styleUrls: ['./timeago.component.scss'], }) export class TimeagoComponent implements OnInit { @Input() created: any; newTime: any; constructor() { }
ngOnInit() { this.newTime = this.converTime(this.created);; }
converTime(time: any) { let a = new Date(time * 1000); return a; }
}

timeago.component.html
Apply the timeAgo pipe.

{{newTime | timeAgo}}

feed-card.component.html
Now connect the app-timeago component with HTML.

<ion-card *ngFor="let feed of feedData; let i = index">
<ion-card-content> <button (click)="feedDeleteAction(i, feed.feed_id)" class="right"> <ion-icon name="trash"></ion-icon> </button> <p [innerHTML]="feed.feed"></p> <app-timeago [created]="feed.created"></app-timeago> </ion-card-content></ion-card>

Building a Mobile Application
You have to create a production build for generating mobile applications.

Production Build

$ ionic build --prod

Build iOS App
Follow the commands for executing the Xcode build. (Watch the video tutorial for a better understanding if this is confusion.)

$ npm run ios-add
$ npm run ios-open

Build Android App
Open Android build using the Android SDK.,

$ npm run android-add
$ npm run android-open

Project Updates
If you want to update your project changes run the following command:

$ npm run ios-copy
$ npm run android-copy

Further Reading

Comment here

This site uses Akismet to reduce spam. Learn how your comment data is processed.