Статьи

Новые Ionic 5 Angular 8 Отображение, обновление и удаление записей с RxJS

Погрузитесь глубоко в Ionic и Angular

Этот пост посвящен отображению записей API с действиями удаления и обновления с использованием новых Ionic и Angular реактивного программирования. Это продолжение моей серии Ionic Angular с целью объяснить, как распределять данные между компонентами с использованием методов RxJS, таких как  BehaviorSubject.

Все ответы / записи API фидов хранятся в реактивном объекте. Это поможет DOM приложения беспрепятственно работать с операциями обновления и удаления. Реализуйте это в своем стороннем проекте и обогатите свои приложения

Видео: .

Корма Сервис

Вам также может понравиться: Отображение интерактивной карты ЗДЕСЬ в приложении Ionic .

Создайте сервис Feed для обслуживания всех операций с данными, таких как отображение, обновление и удаление.

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
Здесь  feedData метод соединяется с нашим API. feedData$ является субъектом поведения объекта реактивного хранения RxJS . Это помогает вам распределять данные между компонентами. changeFeedData Метод обновляет реактивное значение объекта с использованием  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.ts
Импорт службы подачи и  initiate(ngOnInit),  сделать вызов подачи API , чтобы получить записи. Создайте  postData объект с идентификатором пользователя и значениями токена. Сохраните результаты API в  feedData$ объекте, используя   feedService.changeFeedData метод.

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.'); } ); } } }

Просмотр данных
Создание компонента для отображения записей каналов.

$ 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
Объявите и экспортируйте модуль для использования приложения.

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 { 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
Включить   feedCard(app-feed-card) компонент в страницу канала.

<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
Дизайн с ионными компонентами.

<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.

<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
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