U ovom ću blog postu napraviti primjer Ionic 3 aplikacije koja će prikazivati popis blog postova sa ovog bloga koristeći WordPress REST API.
Na početnoj stranici biti će popis blog postova (naziv, vrijeme objave, kategorije, kratak sadržaj i slika) te će se moći pristupiti svakom blog postu pojedinačno.
Kreiranje aplikacije
Za početak kreiram novu Ionic aplikaciju i odmah dodajem Android platformu kako bi kasnije mogao aplikaciju pokrenuti na Android mobilnom uređaju.
1 2 3 |
$ ionic start Ionic3WordPressBlog blank $ cd Ionic3WordPressBlog $ ionic cordova platform add android |
API provider
Sada ću kreirati API Provider koji će služiti kao centralno mjesto svih WordPress URL-ova koje ću koristiti unutar Ionic aplikacije.
1 |
$ ionic g provider ApiProvider |
Na URL-u https://www.tomislavstankovic.com/blog/wp-json/wp/v2/posts dohvaćam popis blog postova. Unutar ovog API-ja također imam dva vrlo bitna podatka, a to su featured_media i categories koji će mi poslužiti za dohvaćanje slike i kategorije svakog blog posta.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import 'rxjs/add/operator/map'; @Injectable() export class ApiProvider { osnovniUrl: string = "https://www.tomislavstankovic.com/blog/wp-json/wp/v2/"; constructor(public _http: HttpClient) { console.log('Hello ApiProvider Provider'); } blogPostovi(){ return this._http.get(this.osnovniUrl + 'posts') .map(data => Object.keys(data).map(k => data[k])) } slikaBlogPosta(a:any){ return this._http.get(this.osnovniUrl + 'media' + a) .map(data => Object.keys(data).map(k => data[k])) } kategorijaBlogPosta(){ return this._http.get(this.osnovniUrl + 'categories/?per_page=100') .map(data => Object.keys(data).map(k => data[k])) } } |
Prikaz blog postova
Aplikacija će na kraju izgledati ovako:
Kao što se može vidjeti na početnom ekranu nalazi se popis zadnjih 10 blog postova. Svaki blog post ima naslov, sliku, kratak sadržaj i vrijeme proteklo od objave. Nekoliko preduvjeta je bilo potrebno zadovoljiti kako bi se sve to prikazalo na taj način.
Struktura početne stranice izgleda ovako i ovdje je posebno zanimljiva funkcija prikaziJedanBlogPost() pomoću koje prosljeđujem potrebne podatke na stranicu za prikaz pojedinačnog blog posta.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<ion-header> <ion-navbar> <ion-title> Ionic3WordPress </ion-title> </ion-navbar> </ion-header> <ion-content> <ion-card *ngFor="let post of jedanBlogPost; let i = index" tappable> <div *ngFor="let slika of jednaSlika; let i = index" (click)="prikaziJedanBlogPost({id:post.id, naslov:post.naslov, sadrzaj: post.sadrzaj, urlslike: slika.putanjaSlike, index: i})"> <div *ngIf="post.id == slika.idBlogPosta"> <img [src]="slika.putanjaSlike"> <span class="vrijeme"><ion-icon name="time"></ion-icon> {{ post.vrijeme }}</span> <span class="kategorija"><ion-icon name="ios-bookmark-outline"></ion-icon> {{post.kategorije | KategorijaPipe:kategorije}}</span> </div> </div> <ion-card-content (click)="prikaziJedanBlogPost({id:post.id, naslov:post.naslov, sadrzaj: post.sadrzaj, urlslike: slika.putanjaSlike, index: i})"> <ion-card-title [innerHTML]="post.naslov"> </ion-card-title> <div [innerHTML]="post.uvod"></div> </ion-card-content> </ion-card> </ion-content> |
Još jedna zanimljiva stvar u home.html je KategorijaPipe koja služi za dohvaćanje naziva kategorije na osnovu ID-a.
1 |
$ ionic generate pipe KategorijaPipe |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'KategorijaPipe', }) export class KategorijaPipe { transform(value, args) { let output = ''; value.forEach(function(number){ output = output + ' ' + args[number] }) return output; } } |
Naravno, potrebno je još o svemu tome obavijestiti app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { SplashScreen } from '@ionic-native/splash-screen'; import { StatusBar } from '@ionic-native/status-bar'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { ApiProvider } from '../providers/api/api'; import { HttpClientModule } from '@angular/common/http'; import { KategorijaPipe } from '../pipes/kategorija/kategorija'; @NgModule({ declarations: [ MyApp, HomePage, KategorijaPipe ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), HttpClientModule ], bootstrap: [IonicApp], entryComponents: [ MyApp, HomePage ], providers: [ StatusBar, SplashScreen, {provide: ErrorHandler, useClass: IonicErrorHandler}, ApiProvider ] }) export class AppModule {} |
Uz nešto malo CSS-a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
page-home { .vrijeme { position: relative; color: #fff; background-color: #3F9FCF; padding: 1px; } .toolbar-background { background-color: #3F9FCF; } .toolbar-title { color: #fff; } .kategorija { position: absolute; right: 10px; background-color: #3F9FCF; color: #fff; padding: 1px; } } |
Kao što se može vidjeti u home.ts za prikaz vremena u željenom obliku koristio sam Moment.js
Pojašnjenje funkcija:
- prikazBlogPostova() – dohvaća popis blog postova i kreira niz (array) jedanBlogPost
- dohvatiUrlSlike() – dohvaća URL slike pojedinačnog blog posta na osnovu parametra idslike: res[i].featured_media iz gornje funkcije
- ucitajKategorije() – dohvaća kategorije za blog post
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { ApiProvider } from './../../providers/api/api'; import moment from 'moment'; @Component({ selector: 'page-home', templateUrl: 'home.html', providers: [ApiProvider] }) export class HomePage { jedanBlogPost: Array<Object>; jednaSlika: Array<Object>; putanjaSlike: any; kategorije: any; constructor(public _navCtrl: NavController, public _api: ApiProvider) { } ionViewDidLoad(){ moment.locale('hr'); this.prikazBlogPostova(); this.ucitajKategorije(); } prikazBlogPostova(){ this.jedanBlogPost = []; this.jednaSlika = []; this._api.blogPostovi().subscribe(res => { for(var i = 0; i < res.length; i++) { //Funkcija koja dohvaća sliku - početak this.dohvatiUrlSlike(res[i].featured_media); //Funkcija koja dohvaća sliku - kraj this.jedanBlogPost.push({id: res[i].id, naslov: res[i].title.rendered, uvod: res[i].excerpt.rendered, sadrzaj: res[i].content.rendered, kategorije: res[i].categories, vrijeme: moment.utc(res[i].modified_gmt).fromNow(), idslike: res[i].featured_media}); } }); } dohvatiUrlSlike(a){ this.putanjaSlike = {}; this._api.slikaBlogPosta(a).subscribe(res => { this.jednaSlika.push({ idSlike: res[0], idBlogPosta: res[22], putanjaSlike: res[23]}); }); } ucitajKategorije(){ let categoryArray = []; this._api.kategorijaBlogPosta().subscribe(res => { res.forEach(function(item){ categoryArray[item.id] = item.name; }) this.kategorije = categoryArray; }); } prikaziJedanBlogPost(a){ this._navCtrl.push('JedanBlogPostPage', a); } } |
Klikom na naslov ili sliku blog posta otvara se jedan blog post. Stranica jednog blog posta kreirana je sljedećom naredbom
1 |
$ ionic generate page JedanBlogPost |
Dok je struktura ovakva
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<ion-header> <ion-navbar color="secondary"> <ion-title [innerHTML]="naslov"></ion-title> </ion-navbar> </ion-header> <ion-content> <img [src]="slika"> <ion-card> <ion-card-content> <div [innerHTML]="sadrzaj"></div> </ion-card-content> </ion-card> </ion-content> |
Funkcionalnost stranice za prikaz jednog blog posta ne radi ništa osim dohvaćanja proslijeđenih podataka s prethodne stranice s popisom svih blog postova pomoću objekta NavParams.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; @IonicPage() @Component({ selector: 'page-jedan-blog-post', templateUrl: 'jedan-blog-post.html' }) export class JedanBlogPostPage { naslov:any; sadrzaj:any; slika:any; constructor(public _navCtrl: NavController, public _navParams: NavParams) { } ionViewWillEnter() { this.naslov = this._navParams.data.naslov; this.sadrzaj = this._navParams.data.sadrzaj; this.slika = this._navParams.data.urlslike; } } |
Zaključak
Struktura projekta prema package.json izgleda ovako
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
{ "name": "Ionic3WordPressBlog", "version": "0.0.1", "author": "Tomislav Stanković", "homepage": "https://www.tomislavstankovic.com/", "private": true, "scripts": { "clean": "ionic-app-scripts clean", "build": "ionic-app-scripts build", "lint": "ionic-app-scripts lint", "ionic:build": "ionic-app-scripts build", "ionic:serve": "ionic-app-scripts serve" }, "dependencies": { "@angular/common": "5.0.3", "@angular/compiler": "5.0.3", "@angular/compiler-cli": "5.0.3", "@angular/core": "5.0.3", "@angular/forms": "5.0.3", "@angular/http": "5.0.3", "@angular/platform-browser": "5.0.3", "@angular/platform-browser-dynamic": "5.0.3", "@ionic-native/core": "4.4.0", "@ionic-native/splash-screen": "4.4.0", "@ionic-native/status-bar": "4.4.0", "@ionic/storage": "2.1.3", "ionic-angular": "3.9.2", "ionicons": "3.0.0", "moment": "^2.21.0", "rxjs": "5.5.2", "sw-toolbox": "3.6.0", "zone.js": "0.8.18" }, "devDependencies": { "@ionic/app-scripts": "3.1.8", "typescript": "2.4.2" }, "description": "Ionic3WordPressBlog" } |