New Ionic 5 Angular 8 Display, Update and Delete Records with RxJS
Wall Script
MailxEngine
Friday, November 01, 2019

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

This post is about displaying the API records with delete and update actions using new Ionic and Angular reactive programming. This is a continuation of Ionic Angular series and it explains to you how to distribute the data between the components using RxJS method like BehaviorSubject. All of the feed API responses/records storing in a reactive object, This help the application DOM works seamlessly with update and delete operations. Implement this to your side project and enrich your applications.

New Ionic 5 Angular 8 Update and Delete Records with RxJS


Live Demo


Video Tutorial



Feed Service
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)
[OK] Generated service!

feed.service.ts
Here feedData method connects with API. feedData$ is a behavior subject RxJS reactive storage object, this helps you distribute the data between the components. 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 page initiate(ngOnInit) make the feed API call to get the records. Construct the postData object with login user id and token values. Storing the API results in feedData$ reactive object using 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)
[OK] Generated component!

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.
aimport { 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)
[OK] Generated service!

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 deleteFeedData method remove 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 feedDelete API with 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 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 feedUpdate to connect 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)
[OK] Generated component!


feed-update.component.ts
Import the feed service and follow the same like feedDelete action. Construct the postData value with text
aimport { 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 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>a

Timeago

Install the Time Ago pipe.
$npm install time-ago-pipe --save

Create web component for timego.
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)
[OK] Generated component!

components.module.ts
Import all of the newly generated components feedUpdate, timeAgo 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.
aimport { 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.
<div>
  {{newTime | timeAgo}}
</div>

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
Following commands for executing Xcode build, watch the video tutorial you will understand more.
$ npm run ios-add
$ npm run ios-open

Build Android App
Open Android build using Android SDK
$ npm run android-add
$ npm run android-open


Project Updates
If you want to update your project changes.
$ npm run ios-copy
$ npm run android-copy

web notification

0 comments:

Make in India