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.
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!
> 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();
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!
> 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-content>
<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>
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!
> 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>
<ion-card-content>
<button (click)="feedDeleteAction(i)" class="right">
<ion-icon name="trash"></ion-icon>
</button>
<p [innerHTML]="feed.feed"></p>
</ion-card-content>
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!
> 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-item>a
<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>
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!
> 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>
</div>
{{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>
<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>
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
$ npm run ios-open
Build Android App
Open Android build using Android SDK
$ npm run android-add
$ npm run android-open
$ npm run android-open
Project Updates
If you want to update your project changes.
$ npm run ios-copy
$ npm run android-copy
$ npm run android-copy
Thanks for you tutorial Mr Srinivas, but i want know how modify the icon and splash screen in this app. pls
ReplyDelete