Hi everyone I have a problem with my login form on Ionic 2.
When I do login token is saved on storage and redirect to another page, but user's data is not shown on Android or IOS because token is not available. I discover that I need to reload the page, on local environment 'location.reload()' works perfect and user's data is available but does not work when I pusblish on Google Play and App Store.
I've tried some ways to reload it but does not work on Android and IOS. What can I do?
Login function
loginForm(){
const data = {
"username" : this.login.value.username,
"email" : this.login.value.username,
"password" : this.login.value.password,
}
this.dataService.loginUser(data).subscribe(
(data) => {
let token = data.key;
this.dataService.checkAccessUserGroup(token).subscribe(
(data) => {
if(data[0] == 200){
this.storage.set('access_token', token);
//this.appCtrl.getRootNav().setRoot(HomePage);
//this.navCtrl.setRoot(HomePage);
//this.appCtrl.getRootNav().setRoot(this.navCtrl.getActive().component);
//this.navCtrl.push(HomePage);
//this.appCtrl.getRootNav().push(IndexPage);
//location.reload()
this.navCtrl.setRoot(HomePage).then(() =>{
this.navCtrl.popToRoot();
});
}
if(data[0] == 500){
this.generateAlert("Error",'No tienes permisos adecuados para acceder. Ponte en contacto con el administrador de tu Deck.');
}
},
(err) => {
if(err.status == 400){
this.generateAlert("Error",'No hemos podido verificar tus datos. Intentalo de nuevo');
}
}
);
},
(err) => {
if(err.status == 400){
this.generateAlert("Error",'Usuario o constraseña no válido. Intentalo de nuevo');
}
}
);
}
Login html
<ion-content padding id="container-home" style="background-image:url('assets/img/bg-login.png')">
<ion-row>
<ion-img class="logo-md" width="120" height="120" src="assets/img/mydecklogocolor.png"></ion-img>
</ion-row>
<ion-row id="auth-login">
<ion-col col-12 no-padding>
<ion-row class="header">
<h3>Ingresa</h3>
</ion-row>
<form id="login-container" [formGroup]="login" (ngSubmit)="loginForm()">
<ion-row>
<ion-item>
<ion-input type="text" formControlName="username"
class="input-md"placeholder="Correo electrónico / usuario"></ion-input>
</ion-item>
<ion-item>
<ion-input type="password" formControlName="password"
class="input-md" placeholder="Contraseña"></ion-input>
</ion-item>
</ion-row>
<ion-row>
<button ion-button class="auth-btn" type="submit" [disabled]="!login.valid">Ingresar</button>
</ion-row>
</form>
<ion-row>
¿Olvidaste tu contraseña?
</ion-row>
</ion-col>
</ion-row>
</ion-content>
In case of Ionic Storage, it returns a promise for both set and get functions. So they are asynchronous.
So you could try:
this.storage.set('access_token', token).then(()=>{
this.navCtrl.setRoot(HomePage);
});
You dont need to "refresh the page". You can simply set Home Page as root as soon as you are done with saving the token.
Related
Google password saving
I have a problem with the password saving system on my Ionic 5 / Vue.js 3 application (it will only be used on Android devices) :
The Google pop-up as in the image above is not shown at the right moment.
It sometimes doesn't show up at all, or it is triggered when I press the system "Home" or "Recent app" Android buttons.
Here is a snippet of my Login.vue component.
<form method="post" #submit.prevent="handleSubmit" autocomplete="on">
<ion-item lines="full">
<ion-label position="floating">Email</ion-label>
<ion-input name="email" v-model="email" type="email" pattern="email" required autocomplete="email"
inputmode="email" #blur="v$.email.$touch"></ion-input>
</ion-item>
<ion-item lines="full">
<ion-label position="floating">Password</ion-label>
<ion-input name="password" v-model="password" :type="passwordType" pattern="password" required
autocomplete="current-password" minLength="8" maxLength="16" #blur="v$.password.$touch"
#keyup.enter="handleSubmit"></ion-input>
<ion-button class="custom-hide" slot="end" #click="hideShowPassword()">
<ion-icon :icon="hidePassword ? eyeOutline : eyeOffOutline"></ion-icon>
</ion-button>
</ion-item>
<ion-button class="login-button" #click="handleSubmit"
type="submit" :disabled="!isAllowedSubmit"
color="primary" expand="block">
Login
</ion-button>
</form>
I'm using the #vuelidate/core library for form validation.
In the handleSubmit function, I look for errors, then if there is no error, I navigate to my Home page.
async handleSubmit() {
this.isAllowedSubmit = false;
this.v$.$touch();
if (this.v$.$error) {
setTimeout(() => {
this.isAllowedSubmit = true;
}, 1000);
return;
}
else {
//API call, no problem here
const tryLogin = await this.submitForm();
if (tryLogin) {
this.v$.$reset();
await this.router.replace("/logged");
await this.router.push("/modules/home");
}
return;
}
For some reason, my form redirects to the app home page instead of calling the submit function.
All my other forms work perfectly except for this one
maintenance-form-modal.component.html
<ion-header>
<ion-toolbar>
<ion-title>Maintenance Form</ion-title>
<ion-buttons slot="end">
<ion-button (click)="dismissModal()">Close</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-item lines="full">
<p>Location: {{location.name}}</p>
</ion-item>
<form [formGroup]="maintenanceForm" (ngSubmit)="submitForm()">
<ion-item lines="full">
<ion-label position="stacked">Details</ion-label>
<ion-input formControlName="details" type="text" spellcheck="true"></ion-input>
</ion-item>
<span class="error ion-padding" *ngIf="isSubmitted && maintenanceForm.controls.name.errors?.required">
Details are required.
</span>
<ion-item lines="full">
<ion-label position="stacked">Image</ion-label>
<ion-button color="primary" expand="block" size="big" (click)="takePicture()">Take Picture</ion-button>
<img [src]="photo">
</ion-item>
<span class="error ion-padding" *ngIf="isSubmitted && maintenanceForm.controls.image.errors?.required">
An image for the maintenance ticket is required.
</span>
<ion-item lines="full">
<ion-label position="stacked">Priority</ion-label>
<ion-range min="1" max="5" step="1" snaps="true" formControlName="priority">
<ion-label slot="start">1</ion-label>
<ion-label slot="end">5</ion-label>
</ion-range>
</ion-item>
<span class="error ion-padding" *ngIf="isSubmitted && maintenanceForm.controls.priority.errors?.required">
Priority is required.
</span>
<ion-item lines="full">
<ion-label position="stacked">Maintenance Type</ion-label>
<ion-select formControlName="category">
<ion-select-option>Electrical</ion-select-option>
<ion-select-option>Plumbing</ion-select-option>
<ion-select-option>Other</ion-select-option>
</ion-select>
</ion-item>
<span class="error ion-padding" *ngIf="isSubmitted && maintenanceForm.controls.category.errors?.required">
Priority is required.
</span>
<ion-row>
<ion-col>
<ion-button type="submit" color="danger" expand="block">Submit</ion-button>
</ion-col>
</ion-row>
</form>
</ion-content>
maintenance-form-modal.component.ts
import { Component, OnInit } from '#angular/core';
import {GlobalVariablesService} from '../services/global-variables.service';
import {ModalController, NavParams} from '#ionic/angular';
import { Plugins, CameraResultType, CameraSource } from '#capacitor/core';
import {DomSanitizer, SafeResourceUrl} from '#angular/platform-browser';
import {Location} from '../classes/location';
import {FormBuilder, FormControl, FormGroup, Validators} from '#angular/forms';
#Component({
selector: 'app-maintenance-form-modal',
templateUrl: './maintenance-form-modal.component.html',
styleUrls: ['./maintenance-form-modal.component.scss'],
})
export class MaintenanceFormModalComponent implements OnInit {
public static modalID: string = GlobalVariablesService.maintenanceFormModalID;
public location: Location;
public photo: SafeResourceUrl;
public isSubmitted = false;
public maintenanceForm = this.formBuilder.group({
details: new FormControl('', Validators.compose([Validators.required])),
priority: new FormControl('', Validators.compose([Validators.required])),
image: new FormControl('', Validators.compose([Validators.required])),
category: new FormControl('', Validators.compose([Validators.required]))
});
constructor(private modalController: ModalController,
private navParams: NavParams,
private sanitizer: DomSanitizer,
private formBuilder: FormBuilder) {
GlobalVariablesService.printConsoleBreaker('maintenance-form-modal.component.ts');
}
ngOnInit() {
this.location = this.navParams.get('location');
console.log('Location in modal', this.location);
console.log('Image', this.photo);
}
async takePicture() {
const image = await Plugins.Camera.getPhoto({
quality: 100,
allowEditing: false,
resultType: CameraResultType.DataUrl,
source: CameraSource.Camera
});
this.photo = this.sanitizer.bypassSecurityTrustResourceUrl(image && (image.dataUrl));
this.maintenanceForm.get('image').setValue(this.photo);
}
public submitForm() {
this.isSubmitted = true;
if (!this.maintenanceForm.valid) {
console.log('Please provide all the required values!');
return false;
} else {
console.log('Form Value', this.maintenanceForm.value);
}
}
public async dismissModal() {
await this.modalController.dismiss(null, 'cancel', MaintenanceFormModalComponent.modalID);
}
}
Google console log gives me this
========================================================== maintenance-form-modal.component.ts ==========================================================
VM786 main-es2015.js:7342 Location in modal [REDACTED]
VM786 main-es2015.js:7343 Image undefined
VM787 vendor-es2015.js:49857 Can't bind to 'ngIf' since it isn't a known property of 'span'.
VM787 vendor-es2015.js:49857 Can't bind to 'ngIf' since it isn't a known property of 'span'.
VM787 vendor-es2015.js:49857 Can't bind to 'ngIf' since it isn't a known property of 'span'.
VM787 vendor-es2015.js:49857 Can't bind to 'ngIf' since it isn't a known property of 'span'.
DevTools failed to load SourceMap: Could not load content for http://localhost/48-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/60-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/20-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
capacitor-runtime.js:2394 onscript loading complete
Navigated to http://localhost/tabs/customers?ion-input-4=&ion-sel-0=
DevTools failed to load SourceMap: Could not load content for http://localhost/runtime-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/tabs/sentry-cordova.bundle.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/polyfills-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/styles-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/main-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
DevTools failed to load SourceMap: Could not load content for http://localhost/vendor-es2015.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
vendor-es2015.js:75090 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
vendor-es2015.js:106154 Ionic Native: deviceready event fired after 361 ms
vendor-es2015.js:106459 Native: tried calling StatusBar.styleDefault, but the StatusBar plugin is not installed.
vendor-es2015.js:106465 Install the StatusBar plugin: 'ionic cordova plugin add cordova-plugin-statusbar'
vendor-es2015.js:106459 Native: tried calling SplashScreen.hide, but the SplashScreen plugin is not installed.
vendor-es2015.js:106465 Install the SplashScreen plugin: 'ionic cordova plugin add cordova-plugin-splashscreen'
capacitor-runtime.js:5173 Initialized the NfcPlugin
main-es2015.js:8337 ========================================================== tabs.page.ts ==========================================================
It turns out that several bugs were occurring because the modal was not declared in declarations and entryComponents in app.module.ts
I cannot display data in ionic. How can I display the data in ionViewWillEnter and using post method in laravel API?
I have tried to call the data using console.log to check if the data is there or not. I tried "console.log(this.id);" before this.authService in ionViewWillEnter as shown below.
kprofile.ts
ionViewWillEnter(){
this.authService.postData(this.id,'viewProfileClinic').then((result) => {
this.responsedata = result;
console.log(result);
this.usersClinic.email = this.responsedata.email;
this.usersClinic.telno = this.responsedata.telno;
this.clinic_regno = this.responsedata.clinic_regno;
this.clinic_name = this.responsedata.clinic_name;
this.site = this.responsedata.site;
this.clinic_address = this.responsedata.clinic_address;
this.zip = this.responsedata.zip;
this.city = this.responsedata.city;
this.state = this.responsedata.state;
},(err) =>{
});
}
as I console.log result is shown
no clinic data
as I run ionic serve.
below is the api
.api
//VIEW ALL CLINIC PROFILE
public function viewProfileClinic(Request $request)
{
$id =$request->id;
$clinicID = $request->clinic_id;
$count = RegisterClinic::where('clinic_id',$clinicID)->count();
if($count == 1)
{
$clinicData = RegisterClinic::where('clinic_id',$clinicID)->first();
$callEmailTelno = User::where('id',$clinicData->uid)->first();
$datamsg = response()->json([
'calldata' => 'Email:'.$callEmailTelno->email.' Telno:'.$callEmailTelno->telno
.' Clinicregno:'.$clinicData->clinic_regno.' Clinicname:'.$clinicData->clinic_name
.' Site:'.$clinicData->site.' Clinicaddress:'.$clinicData->clinic_address
.' Zip:'.$clinicData->zip.' City:'.$clinicData->city.' State:'.$clinicData->state
]);
return $datamsg->content();
}
else{
$datamsg = response()->json([
'error' => array("text"=>"No clinic data.")
]);
return $datamsg->content();
}
}
This is what I want it to be displayed in ionic in .html file.
.html
<ion-list>
<p>Clinic Profile</p>
<form #f="ngForm" (ngSubmit)="onSubmit(f)" class="list-form">
<ion-item>
<ion-label stacked>Clinic Email</ion-label>
<ion-input type="text" name="usersClinic.email" [(ngModel)]="usersClinic.email">{{usersClinic.email}}</ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Telephone no.</ion-label>
<ion-input type="text" name="usersClinic.telno" [(ngModel)]="usersClinic.telno">{{usersClinic.telno}}</ion-input>
</ion-item>
<button ion-button color="light" class="transparent-button" [disabled]="!f.valid" text-center round>
Edit
</button>
</form>
<ion-item>
<p>Clinic Registration no</p>
{{clinic_regno}}
</ion-item>
<ion-item>
<p>Clinic Name</p>
{{clinic_name}}
</ion-item>
<ion-item>
<p>Clinic Site</p>
{{site}}
</ion-item>
<ion-item>
<!-- <p>Clinic Address</p> -->
<ion-label primary>Clinic Address</ion-label>
<!-- <ion-textarea>{{clinic_address}},{{zip}},{{city}},{{state}}.</ion-textarea> -->
<ion-textarea rows="6" disabled [value]="clinic_address" ></ion-textarea>
</ion-item>
</ion-list>
the api response in postman is as below.
{"calldata":"Email:jumin#hu.cm Telno:0148232323 Clinicregno:87234824 Clinicname:Klinik Ikhlas Site:www.wuu Clinicaddress:UTC Central Market Zip:87000 City:Labuan State:Wilayah Persesekutuan Labuan"}
Below is my
authService.ts
file which I put my postData method.
postData(credentials, type) {
let headers = new Headers({
'Content-Type': 'application/json'
});
let options = new RequestOptions({ headers: headers });
return new Promise((resolve, reject) => {
this.http.post(apiUrl + type, JSON.stringify(credentials), options)
.toPromise()
.then((response) => {
console.log('API Response : ', response.json());
resolve(response.json());
})
.catch((error) => {
console.error('API Error : ', error.status);
console.error('API Error : ', JSON.stringify(error));
reject(error.json());
});
});
}
Not sure if this would work for you, but for my API response it came in as json also but instead of me extracting it as json I ran:
this.responsedata = (JSON.stringify(result));
Then,
this.responsedata = JSON.parse(this.responsedata);
Also, another possibility may be the API not formatting the data correctly. I'm sure you've echoed your data on the API, but there may be an issue with something there because you're getting the else callback. So maybe start with the if statement.
P.S.- Sometimes the headers can be a pain if not formatted correctly, if you're passing a token or any type of data in your headers sometimes Angular/Ionic is a little more sensitive than postman to the data.
I am able to fetch all the albums from Facebook User's account. I am trying to show it in Grid but I need cover photo of Album as well. I tried below code:
<ion-grid>
<div *ngFor="let album of albums; let i = index;">
<ion-row *ngIf="i % 3 === 0">
<ion-col col-4 *ngIf="i < albums.length">
<ion-card>
<img src="https://graph.facebook.com/{{albums[i].id}}/picture?type=album" />
<div class="card-title">{{ albums[i].name }}</div>
</ion-card>
</ion-col>
<ion-col col-4 *ngIf="i+1 < albums.length">
<ion-card (click)="albumClicked(album)">
<img src="https://graph.facebook.com/{{albums[i+1].id}}/picture?type=album" />
<div class="card-title">{{ albums[i+1].name }}</div>
</ion-card>
</ion-col>
<ion-col col-4 *ngIf="i+2 < albums.length">
<ion-card (click)="albumClicked(album)">
<img src="https://graph.facebook.com/{{albums[i+2].id}}/picture?type=album" />
<div class="card-title">{{ albums[i+2].name }}</div>
</ion-card>
</ion-col>
</ion-row>
</div>
</ion-grid>
This is how I get albums:
FacebookService.ts:
...
getUserAlbums(userID) {
return this.facebook.api("/v2.9/" + userID + "/albums", []);
}
...
FacebookAlbumsPage.ts:
...
getUserAlbums(facebookUserId) {
this.showLoading();
this.facebookUserDetails.getUserAlbums(facebookUserId).then((res) => {
this.albums = res.data;
this.hideLoading();
});
}
...
While getting image I get below error:
Failed to load resource: the server responded with a status of 400 ()
Does anyone know how to get facebook albums with their cover photos using Ionic2 ?
Edit:
This is the url that is passed in img src:
https://graph.facebook.com/186028675250734/picture?type=album
But when I opened the link directly into browser, it returned below error:
{
"error": {
"message": "Unsupported get request. Object with ID '186028675250734' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api",
"type": "GraphMethodException",
"code": 100,
"fbtrace_id": "BtQDS1csSgu"
}
}
I am using ionic framework with a android device (with cordova, of course). There's a modal I'm using for settings and stuff, it opens well on desktop browser with
`inic serve`
However, after build this, either with
cordova build android or ionic build android
it won't open again, not only is it in an real android device, but also in the desktop browser.
Here's the code:
for the html view:
<ion-modal-view>
<ion-header-bar>
<h1 class="title">Settings</h1>
<div class="buttons">
<button class="button button-clear" ng-click="hideModal()">Done</button>
</div>
</ion-header-bar>
<ion-content class="padding">
<form name="settingsForm" novalidate>
<ion-item class="item-input">
<label class="input-label">IP Address</label>
<input type="text" ng-model="vm.ipAddress" name="ipAddr" required />
</ion-item>
<ion-item class="item-input">
<label class="input-label">Port Number</label>
<input type="text" ng-model="vm.portNum" name="portNum" required />
</ion-item>
<a class="button button-block button-positive" ng-click="vm.startCommand()"
ng-disabled="settingsForm.ipAddr.$invalid || settingsForm.portNum.$invalid && !vm.isListening">{{vm.btnString}}</a>
</form>
<br />
<ion-list>
<ion-item class="item-divider">Messages from socket ws://{{vm.ipAddress}}:{{vm.portNum}} -></ion-item>
<ion-item class="item-text-wrap" ng-repeat="msg in vm.msgs">{{msg}}</ion-item>
</ion-list>
</ion-content>
</ion-modal-view>
for the controller:
/// <reference path="../_reference.ts" />
module app.settings {
interface IModelScope extends angular.IScope {
model: Ionic.IModal;
showModal(): void;
hideModal(): void;
}
interface ISettingsCtrl {
ipAddress: string;
portNum: number;
msgs: string[];
btnString: string;
startCommand(): void;
}
class SettingsCtrl implements ISettingsCtrl {
ipAddress: string;
portNum: number;
msgs: string[] = [];
btnString: string = 'Start';
private _gotDirective: boolean;
private _isListening: boolean = false;
static $inject = ['$scope', 'SocketSvc', '$ionicPopup', '$ionicModal', '$ionicLoading'];
constructor(private _scope: IModelScope,
private _socketSvc: app.service.ISocketSvc,
private _ionicPopup: Ionic.IPopup,
private _ionicModel: Ionic.IModal,
private _ionicLoading: Ionic.ILoading) {
_ionicModel.fromTemplateUrl('../../settings/settings.html', {
scope: _scope,
animation: 'slide-in-up'
}).then(m => {
_scope.model = m;
});
_scope.showModal = () => {
_scope.model.show();
}
_scope.hideModal = () => {
_scope.model.hide();
}
}
angular.module('app')
.controller('SettingsCtrl', SettingsCtrl);
}
yes, i'm using typescript
#GuillemVicens well, it turns out the ionic framework starter gives you a nice place to start but not cordova-friendly enough. In the ionic project, I put my settings.html under the
/www/settings/settings.html
and settings.ctrl.ts
/www/scripts/settings/settings.ctrl.ts
So I use the
_ionicModel.fromTemplateUrl('../../settings/settings.html', {
scope: _scope,
animation: 'slide-in-up'
}
to try to specify the modal's template. However in cordova, it package all the
www
into the
assets/www
witch should be fine because it still got all this hierarchy (which turns out not).
All the scripts turns to run just under the
/assets/www
directory, so if you switch your
../../settings/settings.html into ./settings/settings.html
it'll work just fine.
For who don't have much time, the scripts run in browser just under it's own directory, but in android, it run under the /www/ directory, so make sure you use the relative addressing right.