Ionic 2 storage returns null - ionic2

I stacked with Ionic 2 Storage after RC0.
Did all by instruction.
login.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Storage } from '#ionic/storage';
import {TabsPage} from '../tabs/tabs';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
driver: any;
phone: any;
getPhone(){
return this.storage.get("phone");
};
constructor(private navCtrl: NavController, public storage: Storage)
{
this.driver = {
phone: '',
password: ''
};
this.getPhone().then(phone => {
console.log('RAW_PHONE: ' + phone);
this.phone = phone;
if (this.phone != undefined || this.phone != null){
console.log('PHONE: ' + this.phone);
this.navCtrl.setRoot(TabsPage);
}
});
}
feed.ts
import { Component } from '#angular/core';
import { Storage } from '#ionic/storage';
#Component({
selector: 'page-feed',
templateUrl: 'feed.html'
})
export class FeedPage {
getTruck(){
return this.storage.get("truck")
};
constructor(public storage: Storage) {
this.getTruck().then(val => {
console.log('SAVED TRUCK: ' + val);
});
}
After success launch on emulator I see a log:
DEVICE READY FIRED AFTER 1467 ms
Ionic Storage driver: cordovaSQLiteDriver
RAW_PHONE: null
Ionic Push: saved push token: cWPGBZzfchU:APA91bE5Rqk-mU4my7Avb689JRaWEA-b0mbkqPPiZui8M4bQR8TDayjwhLrS04Aj4qB9Y3_-IWLy9OoLrGaci5KhRvwgWkE4FZ4eSbgB2qkkql8Nk-oItgdo1ddN9vX_asyfYnys7TiK
Token saved: cWPGBZzfchU:APA91bE5Rqk-mU4my7Avb689JRaWEA-b0mbkqPPiZui8M4bQR8TDayjwhLrS04Aj4qB9Y3_-IWLy9OoLrGaci5KhRvwgWkE4FZ4eSbgB2qkkql8Nk-oItgdo1ddN9vX_asyfYnys7TiK
LOGIN RESPONSE: ok
LOGIN - SAVE PHONE: 55555
RESPONSE AFTER LOGIN: [object Object]
TRUCK NUMBER AFTER LOGIN: 3 (it means I successfuly got number and set in storage)
SAVED TRUCK: null (it means I try to get value from storage)
On first attemption to auth I get null, but then I close app, kill it from app manager, launch again and try to auth - and get saved value. But I still need to login, because Storage lost my login value.
What is wrong?

In my case this works fine, you need to stay after storage is ready (then).
Example:
this.storage.set('forms_data', this.forms_data).then((val) => {
this.navCtrl.setRoot(HomePage);
});

Install the cordova-sqlite-storage plugin:
cordova plugin add cordova-sqlite-storage --save
install "#ionic/storage" package (Optional for Ionic 2 >= RC.0):
npm install --save #ionic/storage
Add the following line in /src/app/app.module.ts,
import { Storage } from '#ionic/storage';
export function provideStorage() {
return new Storage(['sqlite', 'websql', 'indexeddb'], { name: 'database_name' });
}
// Add "Storage" inside providers
providers: [
{ provide: Storage, useFactory: provideStorage }, Storage
]
Use set() and get() methods to store and retrieve data in your pages.
import { Storage } from '#ionic/storage';
export class MyApp {
constructor(storage: Storage) {
storage.set('key', 'value 1'); // store
storage.get('name').then((val) => { // retrive
console.log('Your value is', val);
})
}
}
For Clarifications have a look at CodeExpertz
For Video reference at YouTube

every time you see something like this:
myFunction().then(....)
or
myFunction(callbackFunction());
then myFunction is doing some asynchronous work --> so it could take some or more time to execute this function.
But JavaScript runs to completion --> it start in your first line of code and goes through your code --> means the browser does not wait until the callback of then() is called. it start the this.storage.get() function and goes on for your console.log. And at some point this.storage.get() has finished and calls the callback you defined in then()
sso you need to use like this:
console.log('Your value is', storage.get('name'));

Related

Loopback 4 - Connect to test database on Npm Test

I want to run an in-memory database for my tests, but I'm unable to make my application connect to it when I run npm test.
When I run npm test i get:
Connection fails: Error: ER_ACCESS_DENIED_ERROR: Access denied for user ''#'172.21.0.1' (using password: NO)
This is happening because I'm not setting any env variables on npm test, but I don't want to use MySQL on my tests and just an in-memory database, here what I have.
testdb.datasources.ts
import {juggler} from '#loopback/repository';
export const testdb: juggler.DataSource = new juggler.DataSource({
name: 'testdb',
connector: 'memory',
});
country.controller.acceptance.ts
import {Client, expect} from '#loopback/testlab';
import {MyApplication} from '../..';
import {setupApplication} from './test-helper';
import {givenEmptyDatabase} from '../helpers/database.helpers';
describe('Country Controller', () => {
let app: MyApplication;
let client: Client;
before('setupApllication', async () => {
({app, client} = await setupApplication());
});
before(givenEmptyDatabase);
// before(givenRunningApp);
after(async () => {
await app.stop();
});
it('Should count 0 countries', async () => {
const res = await client.get('/countries/count').expect(200);
//assertations
expect(res.body.count).to.equal(0);
});
});
test-helper.ts
import {MyApplication} from '../..';
import {
createRestAppClient,
givenHttpServerConfig,
Client,
} from '#loopback/testlab';
import {testdb} from '../fixtures/datasources/testdb.datasource';
export async function setupApplication(): Promise<AppWithClient> {
const app = new MyApplication({
rest: givenHttpServerConfig({host: 'localhost'}),
});
app.dataSource(testdb); // <--- Hoped this would do the job
await app.boot();
await app.start();
const client = createRestAppClient(app);
return {app, client};
}
export interface AppWithClient {
app: MyApplication;
client: Client;
}
The Country controller is just a standard controller create using lb4 controller.
#get('/countries/count', {
responses: {
'200': {
description: 'country model count',
content: {'application/json': {schema: countschema}},
},
},
})
async count(
#param.query.object('where', getwhereschemafor(country)) where?: where,
): promise<count> {
return await this.countryrepository.count(where);
}
Any ideas on whats going wrong?
i Found this way that works for me
Change this:
app.dataSource(testdb);
To this:
await app.bind('datasource.config.db').to({
name: 'db',
connector: 'memory'
});
You are just changing the configurations of datasource to use a local database but is still the same datasource!
make sure that the string of bind is the same used in your main datasource!

how to notify user about the state of network connectivity in ionic2

according to my application , I have to notify user whenever he gets disconnected from a network .so in a provider i used two function , one returns true on online state and the other returns true on offline state. In app.component.ts am checking whether app is in online state or not by calling "isOnline()" of the provider.here the provider code..
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { Network } from '#ionic-native/network';
import { Platform } from 'ionic-angular';
import {Observable} from 'rxjs/Rx';
/*
Generated class for the Connectivity provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
declare var Connection;
#Injectable()
export class Connectivity {
onDevice: boolean;
myObservable :any;
constructor(public http: Http,public platform: Platform,public network:Network) {
console.log('Hello Connectivity Provider');
this.onDevice = this.platform.is('cordova');
/*
this.myObservable = Observable.create(observer => {
let result = this.isOffline();
observer.next(result);
});
*/
}
isOnline(): boolean {
if(this.onDevice && this.network.type){
return this.network.type !== Connection.NONE;
} else {
return navigator.onLine;
}
}
isOffline(): boolean {
if(this.onDevice && this.network.type){
return this.network.type === Connection.NONE;
} else {
return !navigator.onLine;
}
}
}
inside the constructor of app.component.ts am calling isOnline()
constructor(platform: Platform,public connectivityService: Connectivity) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
Splashscreen.hide();
/*this.connectivityService.myObservable.subscribe((data) => {
console.log(data);
});*/
if(this.connectivityService.isOnline()){
console.log("online");
}
else {
console.log("offline");
}
});
this is working fine but, when i get disconnected from network ,i have to refresh the browser again then only am able to see the "offline" on console.how to notify user as soon as network is lost
onchange() method isn't working correctly..
https://github.com/driftyco/ionic-native/issues/1043
I used the solution from the github forum:
Observable.merge(this.network.onConnect(), this.network.onDisconnect())
.subscribe(e => console.log(e), err => console.error(err));
Have a look at the Ionic Native Network documentation.
Particularly the onChange() method:
onchange()
Returns an observable to watch connection changes
Returns: Observable<any>
I am getting this error this.network.onchange(...).subscribe is not a function and I am using ionic native 3.6.0. Looking at the Network native plugin this is how the code looks like.
/**
* Returns an observable to watch connection changes
* #return {Observable<any>}
*/
Network.prototype.onchange = function () {
return Observable.merge(this.onConnect(), this.onDisconnect());
};
Doing the same in your code can fix the issue
import { Observable } from 'rxjs/Observable';
Observable.merge(this.network.onConnect(), this.network.onDisconnect()).subscribe(() => {
this.getNetworkInfo();
});

In Ionic 2, iBeacon integration throws "No provider for IBeacon" error

I'm trying to integrate ibeacon feature in Ionic 2 app.
I'm using https://ionicframework.com/docs/native/ibeacon/ plugin.
Followed the steps as mentioned in the document.
Created a provider class.
Added the plugin integration.
Invoke the provider class in Home page.
But when running the app on android device, getting error,
"Failed to navigate: No provider for IBeacon!"
Please suggest any fix.
Thanks.
Beacon Provider class:
import { Injectable } from '#angular/core';
import { Platform, Events } from 'ionic-angular';
import { IBeacon } from '#ionic-native/ibeacon';
/*
Generated class for the BeaconProvider provider.
//
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class BeaconProvider {
delegate: any;
region: any;
constructor(public platform: Platform, public events: Events, private ibeacon : IBeacon) {
}
initialise(): any {
let promise = new Promise((resolve, reject) => {
// we need to be running on a device
if (this.platform.is('cordova')) {
// Request permission to use location on iOS
this.ibeacon.requestAlwaysAuthorization();
// create a new delegate and register it with the native layer
this.delegate = this.ibeacon.Delegate();
// Subscribe to some of the delegate’s event handlers
this.delegate.didRangeBeaconsInRegion()
.subscribe(
data => {
this.events.publish('didRangeBeaconsInRegion', data);
},
error => console.error()
);
// setup a beacon region – CHANGE THIS TO YOUR OWN UUID
this.region = this.ibeacon.BeaconRegion('deskBeacon', 'E2C56DB5-DFFB-48D2-B060-D0F5A71096E0');
// start ranging
this.ibeacon.startRangingBeaconsInRegion(this.region)
.then(
() => {
resolve(true);
},
error => {
console.error('Failed to begin monitoring: ', error);
resolve(false);
}
);
} else {
console.error('This application needs to be running on a device');
resolve(false);
}
});
return promise;
}
}
And in Home page,
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { AuthService } from '../../providers/auth-service';
import { LoginPage } from '../login/login';
import { BeaconProvider } from '../../providers/beacon-provider';
import { BeaconModel } from '../../models/beacon-module';
import { Platform, Events } from 'ionic-angular';
import { NgZone } from '#angular/core';
#Component({
selector: 'page-home',
templateUrl: 'home.html',
providers : [BeaconProvider]
})
add
import { IBeacon } from '#ionic-native/ibeacon'; to your app.module.ts
and add IBeacon to your providers in app.module.ts.
That fixed the issue for me.
Have you tried adding the service in the constructor of home.ts ?
constructor(private myService: IBeacon ){
}
(This is for Ionic 3 but the process is similar for Ionic 2)
I suggest you put IBeacon definition in app.module.ts under the provider list like this
#NgModule({
declarations: [
MyApp,
],
imports: [
BrowserModule,
HttpModule,
HttpClientModule,
AngularFireDatabaseModule,
AngularFireModule.initializeApp(config),
AngularFireAuthModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
}
}),
IonicModule.forRoot(MyApp),
IonicStorageModule.forRoot()
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
],
providers: [
Api,
Items,
User,
Camera,
CardIO,
NFC,
Ndef,
IBeacon,
Stripe,
SplashScreen,
StatusBar,
{ provide: Settings, useFactory: provideSettings, deps: [Storage] },
// Keep this to enable Ionic's runtime error handling during development
{ provide: ErrorHandler, useClass: IonicErrorHandler },
FirebaseProvider,
BarcodeScanner,
AuthProvider,
BeaconProvider,
]
})
export class AppModule { }

Ionic 2: How to call Provider function in Controller class

I have created new Cordova Plugin only on my machine. Then I added it to my project. It is working fine when I call that plugin. Now, I tried to make a structured caller for my plugin. I created a Provider for it, but the problem is I don't know how to call my plugin function from my Controller class. Below is my sample code.
Provider: my-service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
declare let myPlugin: any;
#Injectable()
export class MyService {
constructor(public http: Http) {
console.log('Hello MyService Provider');
}
public myFunction() {
myPlugin.myPluginFunction(
(data) => {
return data;
},
(err) => {
return err;
});
}
}
Pages: my-page.ts
import { Component } from '#angular/core';
import { NavController, ViewController } from 'ionic-angular';
import { MyService } from '../../providers/my-service';
#Component({
selector: 'page-my-page-ionic',
templateUrl: 'hello-ionic.html'
})
export class MyPage {
constructor(private viewCtrl: ViewController, private myService: MyService) {}
ionViewWillEnter() {
//I tried to call like this
this.myService.myFunction().subscribe(
data => {
alert("success");
},
error => {
alert("error");
});
}
}
It returns me this error - Property 'subscribe' does not exist on type 'void'. I don't know how to call that function, since my provider returns me success or error.
I think since your myFunction() does not return any observable you cannot subscribe to it. It just returns data directly.
You can use it like this in this case:
var data = this.myService.myFunction();
console.log("Data from plugin is :", data);
If you want to use it as an Observable, return a new observable like this:
public myFunction() {
return Observable.create(observer => {
myPlugin.myPluginFunction(
(data) => {
observer.next(data);
},
(err) => {
observer.next(data);
});
},
(err) => {
observer.error(err);
});
}

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