We have covered most of the topics in building a mobile application using Ionic 3 and Angular JS 4. Today’s topic is to pull in data for news feed from a server and display it on your website. This is suggestible post since it does proper verification at the backend based on token. All it does is, it will verify system token and user token at the backend and then pulls data using feed API url. I have also added an extra code to the previous post for login authentication with PHP Restful API for showing alert messages. Please do follow the below video and code for your understanding.
Live Demo
Part 1
Ionic 3 and Angular 4: Create a Welcome Page with Login and Logout.
Video Tutorial
Ionic 3 and Angular 4: PHP Token Based Restful API User Authentication and JSON Parsing.
Database Design
To build the user feed system, you have to create two tables such as Users and Feed. You can check my previous tutorials for creating token-based API system.
Users
User table contains all the users registration details.
CREATE TABLE users(
user_id int AUTO_INCREMENT PRIMARY KEY,
username varchar(50),
password varchar(300),
name varchar(200),
email varchar(300));
user_id int AUTO_INCREMENT PRIMARY KEY,
username varchar(50),
password varchar(300),
name varchar(200),
email varchar(300));
Feed
This table contains user daily updates.
CREATE TABLE feed(
feed_id int PRIMARY KEY AUTO_INCREMENT,
feed text,
user_id_fk int,
created int
);
feed_id int PRIMARY KEY AUTO_INCREMENT,
feed text,
user_id_fk int,
created int
);
Download PHP Restul Project
$git clone https://github.com/srinivastamada/PHP-Slim-Restful.git
home.ts
Here getFeed function helps you to get the user feed data based on encrypted token. You will understand more if you watch the video.
import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';
import {AuthService} from '../../providers/auth-service';
@Component({selector: 'page-home', templateUrl: 'home.html'})
export class HomePage {
userDetails : any;
responseData : any;
dataSet : any;
userPostData = {"user_id": "","token": ""};
constructor(public navCtrl : NavController, public authService : AuthService) {
const data = JSON.parse(localStorage.getItem('userData'));
this.userDetails = data.userData;
this.userPostData.user_id = this.userDetails.user_id;
this.userPostData.token = this.userDetails.token;
this.getFeed();
}
getFeed() {
this.authService.postData(this.userPostData, 'feed')
.then((result) => {
this.responseData = result;
if (this.responseData.feedData) {
this.dataSet = this.responseData.feedData;
} else {}
}, (err) => {
});
}
convertTime(created) {
let date = new Date(created * 1000);
return date;
}
.........
// Other Functions
.........
}
import {NavController} from 'ionic-angular';
import {AuthService} from '../../providers/auth-service';
@Component({selector: 'page-home', templateUrl: 'home.html'})
export class HomePage {
userDetails : any;
responseData : any;
dataSet : any;
userPostData = {"user_id": "","token": ""};
constructor(public navCtrl : NavController, public authService : AuthService) {
const data = JSON.parse(localStorage.getItem('userData'));
this.userDetails = data.userData;
this.userPostData.user_id = this.userDetails.user_id;
this.userPostData.token = this.userDetails.token;
this.getFeed();
}
getFeed() {
this.authService.postData(this.userPostData, 'feed')
.then((result) => {
this.responseData = result;
if (this.responseData.feedData) {
this.dataSet = this.responseData.feedData;
} else {}
}, (err) => {
});
}
convertTime(created) {
let date = new Date(created * 1000);
return date;
}
.........
// Other Functions
.........
}
home.html
Binding user feed with HTML. Here using *ngFor parsing the dataSet object.
<ion-header>
<ion-navbar>
<img ion-right src="assets/imgs/bananalogo.png" class="navbarLogo" />
<ion-title>Home</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h2>Welcome to {{userDetails.name}}</h2>
<h3><i class="fa fa-heart-o" aria-hidden="true"></i></h3>
<h3>{{userDetails.email}}</h3>
<ion-card *ngFor="let item of dataSet">
<ion-card-content>
<p [innerHTML]="item.feed | linky"></p>
<span>{{ converTime(item.created) | amTimeAgo}}</span>
</ion-card-content>
</ion-card>
<button ion-button color="primary" (click)="logout()">Logout</button>
</ion-content>
<ion-navbar>
<img ion-right src="assets/imgs/bananalogo.png" class="navbarLogo" />
<ion-title>Home</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h2>Welcome to {{userDetails.name}}</h2>
<h3><i class="fa fa-heart-o" aria-hidden="true"></i></h3>
<h3>{{userDetails.email}}</h3>
<ion-card *ngFor="let item of dataSet">
<ion-card-content>
<p [innerHTML]="item.feed | linky"></p>
<span>{{ converTime(item.created) | amTimeAgo}}</span>
</ion-card-content>
</ion-card>
<button ion-button color="primary" (click)="logout()">Logout</button>
</ion-content>
Angular Plugins
Go to your project directry and intall following plugins for timeago and linky features. These plugins will improve the user data feed.
/* Time Ago */
$npm install --save angular2-moment
/* Text to Link */
$npm install --save angular-linky
$npm install --save angular2-moment
/* Text to Link */
$npm install --save angular-linky
app.module.ts
Importing new plugins in application module. Now go to src/app/app.module.ts and import MomentModule and LinkyModule for improving the user feed.
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { MyApp } from './app.component';
import { AuthService } from '../providers/auth-service';
import { Welcome } from '../pages/welcome/welcome';
import { Login } from '../pages/login/login';
import { Signup } from '../pages/signup/signup';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { LinkyModule } from 'angular-linky';
import { MomentModule } from 'angular2-moment';
@NgModule({
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
Welcome,
Login,
Signup,
TabsPage
],
imports: [
BrowserModule, HttpModule, LinkyModule, MomentModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
Welcome,
Login,
Signup,
TabsPage
],
providers: [
StatusBar,
SplashScreen, AuthService,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { MyApp } from './app.component';
import { AuthService } from '../providers/auth-service';
import { Welcome } from '../pages/welcome/welcome';
import { Login } from '../pages/login/login';
import { Signup } from '../pages/signup/signup';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { LinkyModule } from 'angular-linky';
import { MomentModule } from 'angular2-moment';
@NgModule({
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
Welcome,
Login,
Signup,
TabsPage
],
imports: [
BrowserModule, HttpModule, LinkyModule, MomentModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
Welcome,
Login,
Signup,
TabsPage
],
providers: [
StatusBar,
SplashScreen, AuthService,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
ToastController Error Notifications
Implementing error notitifications for login and signup pages.
signup.ts
Imported ToastController for user notifications .
import { Component } from '@angular/core';
import { NavController, ToastController} from 'ionic-angular';
import { TabsPage } from '../tabs/tabs';
import { LoginPage } from '../login/login';
import { AuthService } from '../../providers/auth-service';
@Component({
selector: 'page-signup',
templateUrl: 'signup.html',
})
export class SignupPage {
responseData : any;
userData = {"username": "","password": "", "name": "","email": ""};
constructor(public navCtrl: NavController, public authService:AuthService, , public toastCtrl:ToastController ) {
}
signup(){
if(this.userData.username && this.userData.password && this.userData.email && this.userData.name){
this.authService.postData(this.userData,'signup').then((result) => {
this.responseData = result;
if(this.responseData.useerData){
localStorage.setItem('userData', JSON.stringify(this.responseData));
this.navCtrl.push(TabsPage);
}
else {
this. presentToast("Give valid details");
}
}
else{
this. presentToast("Give valid details");
}
}, (err) => {
// Error log
});
}
presentToast(msg) {
let toast = this.toastCtrl.create({
message: msg,
duration: 2000
});
toast.present();
}
login(){
//Login page link
this.navCtrl.push(LoginPage);
}
}
import { NavController, ToastController} from 'ionic-angular';
import { TabsPage } from '../tabs/tabs';
import { LoginPage } from '../login/login';
import { AuthService } from '../../providers/auth-service';
@Component({
selector: 'page-signup',
templateUrl: 'signup.html',
})
export class SignupPage {
responseData : any;
userData = {"username": "","password": "", "name": "","email": ""};
constructor(public navCtrl: NavController, public authService:AuthService, , public toastCtrl:ToastController ) {
}
signup(){
if(this.userData.username && this.userData.password && this.userData.email && this.userData.name){
this.authService.postData(this.userData,'signup').then((result) => {
this.responseData = result;
if(this.responseData.useerData){
localStorage.setItem('userData', JSON.stringify(this.responseData));
this.navCtrl.push(TabsPage);
}
else {
this. presentToast("Give valid details");
}
}
else{
this. presentToast("Give valid details");
}
}, (err) => {
// Error log
});
}
presentToast(msg) {
let toast = this.toastCtrl.create({
message: msg,
duration: 2000
});
toast.present();
}
login(){
//Login page link
this.navCtrl.push(LoginPage);
}
}
Build iOS App
Following commands for executing Xcode build, watch the video tutorial you will understand more.
$ cordova platform add ios
$ ionic build ios
$ ionic build ios
Build Android App
Open Android build using Android SDK>
$ cordovaplatform add android
$ ionic build android
$ ionic build android
Previous Part Video Tutorial
Ionic 3 and Angular 4: PHP Token Based Restful API User Authentication Login and Signup.
Why not lazy load the modules??
ReplyDeleteGreat artical thanx
ReplyDeleteThanks for the tutorials, I've been following along and they have helped me.
ReplyDeleteSpotted a few typos in this article, just a quick heads up:
home.ts - text says "encryptied"
home.html - converTime()
signup.ts - useerData
signup.ts - this. presentToast() - x2
ToastController section - text says "Implemeting"
this tutorial is very good for me .
ReplyDeletethanks for help
thx for tutorial
ReplyDeleteguys pls when i try to change from localhost to live server i get a POST"my_url" not found...
ReplyDeletepls I have got a same probleme
Deletenice post
ReplyDeleteHI. Thanks for the video.
ReplyDeleteI have a question.
What will happend if for example whathever user get the localstorage from you computer or your device. Would he need just copy and paste and that's it? could he login normal whithout problem because he has the localstorage?
How could it be in angular 4 and ionic 3 this problem?
Is easy to get localstorage from mobile device?
In the browser is easy to get localstorage. One of the things I can do is only create the same variables of the user in localstorage of my browser and that's it. It's something like the credentials in the notepad of your computer.
How is this token thing work?
ReplyDeleteI've seen that you use user_id and token to fetch data from the API, what if I want to grab data from an independent table (say books) which has no user_id as foreign key? How can I verify that system token and token from data is valid or match?
DeleteHere user_id means your application session_id, based on this token key will generate. For cross verification you have to send the user_id for all of the data requests.
DeleteI got this error when I use this api Url ("let apiUrl = "http://localhost/PHP-Slim-Restful/api/";) from local server at authservice.
ReplyDeleteSyntaxError: Unexpected end of JSON input
at JSON.parse ()
at Response.Body.json (http://localhost:8100/build/main.js:61778:25)
at SafeSubscriber._next (http://localhost:8100/build/main.js:42297:29)
at SafeSubscriber.__tryOrUnsub (http://localhost:8100/build/main.js:40627:16)
at SafeSubscriber.next (http://localhost:8100/build/main.js:40576:22)
at Subscriber._next (http://localhost:8100/build/main.js:40518:26)
at Subscriber.next (http://localhost:8100/build/main.js:40482:18)
at XMLHttpRequest.onLoad (http://localhost:8100/build/main.js:62207:38)
at t.invokeTask (http://localhost:8100/build/polyfills.js:3:9655)
at Object.onInvokeTask (http://localhost:8100/build/main.js:4472:37)
(node:9392) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): [object Object]
ReplyDelete(node:9392) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Getting this error on Run and Build command
Thanks for this best tutorial.
ReplyDeleteThis is awesome to learn.
I need one help I want to upload the image to the server but in folder not in database.
Kindly Help me the PHP Restful Part to upload the image.
Thanks Alot
Thank for the tutorial, but i want to ask if there's a way where every user can see all the posted feed because currently, the user can only see what have been posted by themselves
ReplyDeletei am not getting why you use here coveretime() function .. I mean why such time is converted 2 days ago ..48 years ago.. why such time is shown ???
ReplyDeleteI have this error.
ReplyDeletePlease help
SyntaxError: Unexpected token S in JSON at position 17
at JSON.parse ()
at Response.Body.json (http://localhost:8109/build/vendor.js:67759:25)
at SafeSubscriber._next (http://localhost:8109/build/main.js:808:29)
at SafeSubscriber.__tryOrUnsub (http://localhost:8109/build/vendor.js:41126:16)
at SafeSubscriber.next (http://localhost:8109/build/vendor.js:41073:22)
at Subscriber._next (http://localhost:8109/build/vendor.js:41013:26)
at Subscriber.next (http://localhost:8109/build/vendor.js:40977:18)
at XMLHttpRequest.onLoad (http://localhost:8109/build/vendor.js:68259:38)
at t.invokeTask (http://localhost:8109/build/polyfills.js:3:15660)
at Object.onInvokeTask (http://localhost:8109/build/vendor.js:5126:33)
signup(){
ReplyDeleteif(this.userData.username && this.userData.password && this.userData.email && this.userData.name){
this.authService.postData(this.userData,'signup').then((result) => {
this.responseData = result;
if(this.responseData.useerData){
localStorage.setItem('userData', JSON.stringify(this.responseData));
this.navCtrl.push(TabsPage);
}
else {
this.presentToast("Give valid details");
}
},
else {
this.presentToast("Give valid details");
}
},
(err) => {
// Error log
});
problem with the code brp..help me through