Ionic 2 Tab view not update tabBadge when model change but only update when click on the tab - ionic2

I have this code that show the tabBadge number
<ion-tabs selectedIndex="{{activeTab}}">
<ion-tab [root]="tabThongBaoPage" tabIcon="notifications" [tabBadge]="badge.getBadge()" tabBadgeStyle="danger"></ion-tab>
</ion-tabs>
and the service controller the bag number
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import CONST from '../variable';
#Injectable()
export class BadgeSinhService {
badge: number = 0;
constructor() {
}
getBadge(): number {
return this.badge;
}
setBadge(badge): number {
this.badge = badge;
return this.badge;
}
incrementBadge() {
this.badge++
return
}
decreaseBadge() {
if (this.badge > 0) {
this.badge--
}
return;
}
}
If I click on the button with event like this
<button ion-button (click)="cong()">Cong</button>
<button ion-button (click)="tru()">Tru</button>
cong() {
this.badge.incrementBadge()
}
tru() {
this.badge.decreaseBadge()
}
The tabBadge number updated on the view, as soon as the button is click and the click event is fire
But I also have this code that wait for notification event, that will be fire when the server send a notification to the app, it will increment the tab badge number
push.on('notification', (data) => {
console.log('notifi updatei');
this.badge.incrementBadge();
})
It does increment the tab badge number but the view is not update, only when I tap on the tab then the badge number will update on the view
Why it not update the view like the click event ?

I found the answer,use ngZone to notifi angular2 to update the view
push.on('notification', (data) => {
console.log('notifi updatei');
this.badge.incrementBadge();
})
somehow the code above not create a async task in angular 2 zone, maybe because push.on not belong to angular 2
but the answer is
this.zone.run(() => {
// increment badge
})

Related

Page redirection when no network in ionic3

I have implemented one application in which the page will redirect to a page showing “no network” when the user gone offline. I have successfully implemented that. App navigates to the below screen when there is no network.In the below scenario the logic fails,’
Application fails to redirect to the " no network page " when the user opens the application for the first time or after kill during offline. In this case application launches the default root page say LoginPage.
Please find the logic below.
NetworkCheckProvider.ts
import { Injectable } from '#angular/core';
import { Network } from '#ionic-native/network';
import { Events } from "ionic-angular";
export enum ConnectionStatusEnum {
Online,
Offline
}
#Injectable()
export class NetworkCheckProvider {
private previousStatus;
constructor(private eventCtrl: Events,
private netWork:Network) {
this.previousStatus = ConnectionStatusEnum.Online;
}
public initializeNetworkEvents(): void {
this.netWork.onDisconnect().subscribe(() => {
if (this.previousStatus === ConnectionStatusEnum.Online) {
this.eventCtrl.publish('network:offline');
}
this.previousStatus = ConnectionStatusEnum.Offline;
});
this.netWork.onConnect().subscribe(() => {
if (this.previousStatus === ConnectionStatusEnum.Offline) {
this.eventCtrl.publish('network:online');
}
this.previousStatus = ConnectionStatusEnum.Online;
});
}
}
app.component.ts
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
this.networkCheck();
this.netWorkCheck.initializeNetworkEvents();
}
networkCheck() {
this.events.subscribe('network:online', () => {
this.generic.showToast("Network Available");
console.log('network connected!');
});
this.events.subscribe('network:offline', () => {
debugger;
if(this.nav.getActive().name!='NoInternetPage' || this.nav.getActive().name==null)
this.nav.push('NoInternetPage');
});
}
}
Please correct me if there is any mistake in my code. Also is there is any way to disable all click events during offline?
Thanks and Regards
Anand Raj

ionic 2 - Inappbrowser event fire after second call

I use inappbrowser plugin in ionic 2 application like this :
import {InAppBrowser} from 'ionic-native';
and use it like this :
launch(url){
this.browser = new InAppBrowser( url, "_blank", "EnableViewPortScale=yes,closebuttoncaption=Done" );
this.browser.on("exit")
.subscribe(
() => {
this.close_event=true;
},
err => {
console.log("InAppBrowser Loadstop Event Error: " + err);
});
}
and in html :
<button ion-button icon-right color="danger" (click)="launch('https://www.example.com')">launch
<ion-icon name="refresh"></ion-icon>
when click on launch button for first time and after close browser, exit event not fire but when for second time click on launch button and after close browser exit event is fire
Perhaps the first time you click on Launch button, the device platform is not ready yet?
Try to put the calls to any InAppBrowser methods inside Plaform.ready(), like so:
...
import { Platform } from 'ionic-angular';
import { InAppBrowser } from '#ionic-native/in-app-browser';
...
export class HomePage {
private iab: InAppBrowser;
private platform: Platform;
private browser;
...
var launch = function(url) {
this.platform.ready().then(
() => {
this.browser = this.iab.create( url, "_blank", "EnableViewPortScale=yes,closebuttoncaption=Done" );
this.browser.on("exit").subscribe(
(event) => {
this.close_event = true;
},
(err) => {
console.log("InAppBrowser Loadstop Event Error: " + err);
}
);
}
);
};
...
}

Ionic 2 - List update doesn't reflect in UI unless page is refreshed

My template:
<ion-item-sliding *ngFor="let draft of drafts">
<ion-item>
<h2>Report draft header</h2>
</ion-item>
<ion-item-options side="left">
<button ion-button color="secondary" (click)="draftUpload(draft.report.pk)">
<ion-icon name="md-cloud-upload"></ion-icon>
Upload
</button>
</ion-item-options>
</ion-item-sliding>
In the controller, I do this:
draftUpload(pk) {
this.dataService.uploadReport(pk);
this.drafts = this.dataService.getDraftReports();
}
Here is the getDraftReports() functions:
getDraftReports() {
var draftReports = [];
let reportObj : any;
this.storage.forEach((value, key, index) => {
reportObj = JSON.parse(value);
if(reportObj.report.uploaded=="no"){
draftReports.push(reportObj);
}
});
return draftReports;
}
This doesn't work, although the DB changes are made. If I refresh the page, or navigate away and back, the list updates.
What am I doing wrong?
It seems a change detection issue. Change detection is fired on every browser event, timeout or http request.
The case is that your function: getDraftReports() is asyncronous and is its callback is not detected for Angular and consequently it doesn't fires the change detection event in order to update the view.
In order to solve this you will have to wrap this function into the angular zone. See this code:
import zone:
import { NgZone } from '#angular/core';
Inject the service ngZone:
constructor(private zone: NgZone) {
....
}
And finally add this to your function:
draftUpload(pk) {
this.dataService.uploadReport(pk);
this.zone.run(
() => {
this.drafts = this.dataService.getDraftReports();
}
)
}
Hope this helps.
this.storage.foreach returns a promise and hence is asynchronous.
Your draftReports array is returned before it is set.You need to return the promise :
getDraftReports(draftsHandler:any) {
//var draftReports = [];
//Use a filter method and return the promise.
return this.storage.forEach((value, key, index) => {
let reportObj : any;
reportObj = JSON.parse(value);
if(reportObj.report.uploaded=="no"){
//draftReports.push(reportObj);
draftsHandler(reportObj);
}
});
}
In your draftUpload set drafts within then.
draftUpload(pk) {
this.dataService.uploadReport(pk);
this.dataService.getDraftReports((data)=>this.draftsHandler(data)).then(()=>{
//next steps
}
}
draftsHandler(data:any){
this.drafts.push(data)
}

How to implement login flow in ionic 2?

So I'm trying to get started with ionic 2 from ionic 1 and need some guidance on how to set up authentication in my project. Specifically I'm using firebase and angularfire2.
As a general approach should I either:
a. Check for session/localStorage on app.ts and set the rootPage to login if unauthenticated? Using this method if I log the user out and set the nav rootpage back to the login, the tabs are displayed at the bottom.
b. Create the login page as a modal which removes the problem of the tabs appearing at the bottom, but I'm not sure if I should be firing the modal from app.ts since I'm not sure if the application itself has a root view I should be referencing.
Also, should I set up the auth login and logout as a service and refactor it out rather than having it in the login page and the logout button in the profile controllers?
Here's my logic thus far using method A:
app.ts
export class MyApp {
rootPage: any;
local: Storage = new Storage(LocalStorage);
constructor(platform: Platform) {
this.local.get('user').then(user => {
if (user) {
this.rootPage = TabsPage;
} else {
this.rootPage = LoginPage;
}
});
platform.ready().then(() => {
StatusBar.styleDefault();
});
}
}
And in myProfile.ts
logout() {
this.local.remove('user');
this.user = null;
let modal = Modal.create(LoginPage);
this.nav.present(modal); //should I set the rootPage instead? if so how do I remove the tabBar or set the rootpage of the containing app root page
}
a. Check for session/localStorage on app.ts and set the rootPage to
login if unauthenticated? Using this method if I log the user out and
set the nav rootpage back to the login, the tabs are displayed at the
bottom.
You can use Angularfire2 Ionic Provider , Go to this link for more details Angularfire2 Auth with Ionic
import { Observable } from 'rxjs/Observable';
import { Injectable } from '#angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
// Do not import from 'firebase' as you'll lose the tree shaking benefits
import * as firebase from 'firebase/app';
#Injectable()
export class AuthService {
private currentUser: firebase.User;
constructor(public afAuth: AngularFireAuth) {
afAuth.authState.subscribe((user: firebase.User) => this.currentUser = user);
}
getauthenticated(): boolean {
return this.currentUser !== null;
}
signInWithFacebook(): firebase.Promise<any> {
return this.afAuth.auth.signInWithPopup(new firebase.auth.FacebookAuthProvider());
}
signOut(): void {
this.afAuth.auth.signOut();
}
displayName(): string {
if (this.currentUser !== null) {
return this.currentUser.facebook.displayName;
} else {
return '';
}
}
}
Then from App.ts Import the Provider you just created and then check for Auth status
constructor(public authService: AuthService) {
let authState = this.authservice.getauthenticated();
if (authState) {
this.rootPage = TabsPage;
} else {
this.rootPage = LoginPage;
}
}
And Finally for the Logout use Navigating from an Overlay Component
import { App } from 'ionic-angular';
constructor(
public appCtrl: App
) {}
setRoot(Page:any) {
this.appCtrl.getRootNav().setRoot(Page);
This will not display the Tabs in bottom.
Here's an example of an ionic login flow with a jwt stored in the local storage:
https://github.com/RedFroggy/ionic2-nfc-app/tree/master/app/pages/login

How to instantly change between the actions of a same link without refreshing the page? Creating a FB like feature

I am building a 'Watch this deal' functionality, which is similar to FB 'like' feature. (Ember version 1.13)
Here is the scenario:
There is an icon beside every deal which will enable the current user to 'watch' or 'not watch' the deal. The actions are completed and working and changes on the UI is also working fine. The problem is, when I click on that icon, I become a watcher of the deal but the icon doesn't change. I have to refresh the page to see that change.
controller:
actions:{
// add and remove watchers
addToWatcher: function(deal) {
var _this = this;
var currentUser = this.get('currentUser');
deal.get('watchers').addObject(currentUser);
deal.save().then(function () {
Ember.get(_this, 'flashMessages').success("You are now watching");
}, function() {
// Ember.get(_this, 'flashMessages').danger('apiFailure');
});
},
removeWatcher: function(deal) {
var _this = this;
var currentUser = this.get('currentUser');
deal.get('watchers').removeObject(currentUser);
deal.save().then(function () {
Ember.get(_this, 'flashMessages').success("You are now watching");
}, function() {
// Ember.get(_this, 'flashMessages').danger('apiFailure');
});
}
}
templates:
{{#if (check-watcher deal currentUser.id)}}
<i class="fa fa-2x sc-icon-watch watched" {{action 'removeWatcher' deal}} style="padding: 5px 10px;"></i><br>
{{else}}
<i class="fa fa-2x sc-icon-watch" {{action 'addToWatcher' deal}} style="padding: 5px 10px;"></i><br>
{{/if}}
Here check-watcher is a helper I wrote to check if the deal is being watched by the current user. If it is, the icon will be Red and clicking on it again will trigger 'removeWatcher' action. If not, icon will be black and clicking on it will make user watch the deal.
check-watcher helper:
import Ember from 'ember';
export function checkWatcher(object, currentUser) {
var currentUser = object[1];
var watchers = object[0].get('watchers').getEach('id');
if (watchers.contains(currentUser)) {
return true;
} else{
return false;
}
}
export default Ember.Helper.helper(checkWatcher);
If I were to just change the class, that would have been easy, but I have to change the action too in the views, that's where it's a little tricky.
So, how to make the change in UI happen between adding and removing watchers without refreshing the page?
In short, you need to define a compute method for the helper:
import Ember from 'ember';
export function checkWatcher(object, currentUser) {
var currentUser = object[1];
var watchers = object[0].get('watchers').getEach('id');
if (watchers.contains(currentUser)) {
return true;
} else{
return false;
}
}
export default Ember.Helper.extend({ compute: checkWatcher });
In that case, the helper will recompute its output every time the input changes.
And there is not need to change an action in a template. You could always call 'toggleWatcher' action from template, and then decide what to do in the controller:
toggleWatcher(deal) {
var currentUser = this.get('currentUser');
if (deal.get('watchers').contains(currentUser)) {
this.send('removeWatcher', deal);
} else {
this.send('addToWatcher', deal);
}
}