How to change the ionic4 ion-back-button default function? - back-button

import { IonBackButtonDelegate } from '#ionic/angular'
class TestButton {
#ViewChild('backbutton') backButtonDelegate: IonBackButtonDelegate
this.backButtonDelegate.onClick = (en: Event) => {
console.log("test")
}
}
I want to change default function of the 'ion-back-buttom', but it seem didn't work, could someone do some help? Thank you very much.

You are selecting it wrong. This should work -
import { IonBackButtonDelegate } from '#ionic/angular'
class TestButton {
#ViewChild(IonBackButtonDelegate, { static: false }) backButtonDelegate: IonBackButtonDelegate;
this.backButtonDelegate.onClick = (en: Event) => {
console.log("test")
}
}

You can do it this way. However the event will not trigger for android physical back button clicks.
In template :
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button (click)="back()">
<ion-icon name="arrow-back"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Title</ion-title>
</ion-toolbar>
</ion-header>
In component :
back() {
// Do what you want here
}

Related

ionic not load image from url wp-json and ionic4

when I connect ionic app with wordpress blog with wp-json all content loaded without image , I use ion-img
thanks
screenshot1
screenshot2
screenshot3
screenshot4
screenshot5
this is my code :
note : I use all in one security plugin on my wordpress blog
//post.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from "#angular/common/http";
import {Http, Headers, RequestOptions} from '#angular/http';
import { map } from "rxjs/operators";
import get from "lodash/get";
#Injectable({
providedIn: 'root'
})
export class PostsService {
constructor(private http: HttpClient) {}
private baseURL = "domain.com";
fetchPosts() {
return this.http
.get(`${this.baseURL}/wp-json/wp/v2/posts?_embed`)
.pipe(
map((posts: Array<any>) => posts.map(this.setEmbeddedFeaturedImage))
);
}
fetchPost(post_id: string) {
return this.http
.get(`${this.baseURL}/wp-json/wp/v2/posts/${post_id}?_embed`)
.pipe(map((post: any) => this.setEmbeddedFeaturedImage(post)));
}
/**
* Makes the featured image parameter easily accessible in a template
*/
private setEmbeddedFeaturedImage(p) {
return Object.assign({}, p, {
featured_image: get(p, "_embedded['wp:featuredmedia'][0].source_url")
});
}
fetchPostCategories() {
return this.http.get(`${this.baseURL}/wp-json/wp/v2/categories`);
}
fetchPostsByCategory(category_id: string) {
return this.http
.get(
`${this.baseURL}/wp-json/wp/v2/posts?_embed&categories=${category_id}`
)
.pipe(
map((posts: Array<any>) => posts.map(this.setEmbeddedFeaturedImage))
);
}
}
in the post view every thing loaded without the post images but the images url open in the browser
//home view :
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>
title
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card class="welcome-card" (click)="loadPost(post)" padding-bottom *ngFor="let post of posts$ | async">
<img src="{{post.featured_image}}" >
<ion-card-header>
<ion-card-subtitle>{{post.title.rendered}}</ion-card-subtitle>
<ion-card-title>{{post.title.rendered}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<div>
<div [innerHTML]="post.excerpt.rendered"></div>
</div>
<ion-button href="#">مشاهدة المزيد</ion-button>
</ion-card-content>
</ion-card>
</ion-content>
//
The problem has been resolved successfully for now, I found the problem from the firewall generated by the "All in one security plugin" of the wordpress , I am currently disabled the plugin
firewall roles until there is an exception option for the site's API.
Thanks
Now, is possible with this plugin.
Better Rest API
After you should used in the file .html
<ion-img [src]="noticia?.better_featured_image.media_details.sizes.medium.source_url">
</ion-img>
Regards

ionic async ngFor data

UPDATE ON BOTTOM
I am trying to show data in an *ngFor that i'm getting from an object that is getting retrieved asynchronously from ionic storage. At the moment i am getting a blank screen.
I have tried multiple things like using async pipes in different manners.
Does anybody know the right way?
Here is my storage service method that is getting called:
public getFlow(flowId:number){
return this.storage.get(FLOWS_KEY).then((flows:Map<number,Flow>)=>{
return flows.get(flowId);
});
}
this returns a Promise<Flow>
this is my component code:
import { Component, OnInit } from '#angular/core';
import { ModalController } from 'ionic-angular';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { Flow } from '../../model/Flow';
import { FlowService } from '../../model/services/flowService';
import {CreateTaskPage} from '../create-task/create-task'
import { Task } from '../../model/Task';
#IonicPage()
#Component({
selector: 'page-flow',
templateUrl: 'flow.html',
})
export class FlowPage {
flow;
constructor(public navCtrl: NavController, public navParams: NavParams,private flowService:FlowService,public modalCtrl: ModalController) {
this.flow = this.flowService.getFlow(Number(this.navParams.get("flowId")))
}
ngOnInit(): void {
}
ionViewDidLoad() {
console.log('ionViewDidLoad FlowPage');
}
createTask(){
const modal = this.modalCtrl.create(CreateTaskPage,{flowId:this.flow.flowId});
modal.present();
}
swipe(e,task:Task){
if(e.direction == 2){
console.log("panUp");
task.column--;
}
if(e.direction == 4){
console.log("panDown");
task.column++;
}
}
}
My html:
<ion-content padding>
<div *ngIf="(flow | async)">
<div *ngFor="let col of flow.columns;index as i">
<h2>{{col}}</h2>
<div *ngFor="let task of flow.getTasksFromCol(i)">
<ion-card (swipe)="swipe($event,task)">
<ion-item>
<h2>{{task}}</h2>
<button ion-button item-end clear icon-end>
<ion-icon name='more'></ion-icon>
</button>
<p>{{task}}</p>
</ion-item>
</ion-card>
</div>
</div>
</div>
<ion-fab right bottom>
<button ion-fab color="light"><ion-icon name="arrow-dropleft"></ion-icon></button>
<ion-fab-list side="left">
<button (click)="createTask()" ion-fab><ion-icon name="add-circle"></ion-icon></button>
<button ion-fab><ion-icon name="create"></ion-icon></button>
</ion-fab-list>
</ion-fab>
</ion-content>
Thanks for helping.
UPDATE:
I found one big mistake in my component it now looks like this:
flow:Flow;
constructor(public navCtrl: NavController, public navParams: NavParams,private flowService:FlowService,public modalCtrl: ModalController) {
this.flowService.getFlow(Number(this.navParams.get("flowId"))).then(flow =>{
this.flow = flow;
})
}
i also updated my html but it still isn't working: i now get error:
ERROR TypeError: _co.flow.getTasksFromCol is not a function
at Object.eval [as updateDirectives]
This is weird because this method exists in my Flow Model:
import { Task } from "./Task";
export class Flow {
//PK for 1-n relation with task
flowId:number;
projectName:string;
columns:string[];
tasks: Map<number,Task>;
constructor(flowId:number,projectName:string,columns:string[],tasks:Map<number,Task>){
this.flowId = flowId;
this.projectName = projectName;
this.columns = columns;
this.tasks = tasks;
}
public getTasks(){
return Array.from(this.tasks.values())
}
public getTasksFromCol(colNumber:number){
var tasks = new Array<Task>();
for(let task of Array.from(this.tasks.values())){
if(task.column == colNumber){
tasks.push(task)
}
}
return tasks;
}
}
UPDATE2
i now added this to my service
public getTasksFromCol(flowId:number,colNumber:number){
return this.storage.get(FLOWS_KEY).then((flows:Map<number,Flow>)=>{
var flow:Flow = flows.get(flowId);
var tasks = new Array<Task>();
for(let task of Array.from(flow.tasks.values())){
if(task.column == colNumber){
tasks.push(task)
}
}
return tasks;
});
}
do i just call this in my html page? i'm kinda stuck
I found your mistake.
You have created one variable.
flow:Flow;
You have assigned value to that variable.
this.flow = flow;
Now you need to understand that variable has contains some value related to what you have assigned. So you can't access flow.getTasksFromCol()
Thats the reason you have faced this error.
ERROR TypeError: _co.flow.getTasksFromCol is not a function at Object.eval [as updateDirectives]
Solution:-
Just move this getTasksFromCol() method to service and apply html like following,
I hope it's working. Let try this once and let me know if any error.

Hide toolbar component when it isn't on the top of the page

I have a toolbar like this Its background is transparent. But when i scroll down, this look like
How can i hide this component when the page scroll down and show it when scroll up to the top of the page?
My English is not good. Sorry about this.
EDIT :
I use mat-toolbar
<mat-toolbar color="primary">
<button mat-button routerLink="/" [ngStyle]="{'color': colorStyle === 'WHITE' ? 'white' : 'black'}">
<mat-icon>home</mat-icon>
{{ 'PAGE.HOME' | translate}}</button>
<!-- This fills the remaining space of the current row -->
<span class="fill-remaining-space"></span>
<div fxLayout="row" fxShow="false" fxShow.gt-sm [ngStyle]="{'color': colorStyle === 'WHITE' ? 'white' : 'black'}">
<button mat-button routerLink="['/home']">{{ 'PAGE.HOME' | translate}}</button>
<button mat-button routerLink="['/home']">{{ 'PAGE.D9' | translate}}</button>
<button mat-button routerLink="['/home']">{{ 'PAGE.DThuDuc' | translate}}</button>
<button mat-button routerLink="['/home']">{{ 'PAGE.MORE' | translate}}</button>
<button mat-button [routerLink]="['/add']">{{ 'PAGE.ADD' | translate}}</button>
<button mat-button [routerLink]="['/login']" *ngIf="!loginStatus">{{ 'PAGE.LOGIN' | translate}}</button>
<button mat-button [routerLink]="['/login']" *ngIf="loginStatus">{{ 'PAGE.LOGOUT' | translate}}</button>
<button mat-button [routerLink]="['/show-map']" [queryParams]="{ lat: data.lat, lng: data.lng}">{{ 'PAGE.OVERVIEW' | translate}}</button>
</div>
<button mat-button [mat-menu-trigger-for]="menu" fxHide="false" fxHide.gt-sm>
<mat-icon>menu</mat-icon>
</button>
</mat-toolbar>
.mat-toolbar {
position: fixed;
z-index: 999;
}
Just you use a #HostListener window:scroll
#HostListener("window:scroll", [])
onWindowScroll() {
let number = window.pageYOffset || 0;
console.log(number);
}
Some authors consider a bad practice reference a window directy. Brian Love propouse a "window-provider": see http://brianflove.com/2018/01/11/angular-window-provider/
The Brian Love propouse solution:
****It's a Copy and Paste of the referenced article ********
import { isPlatformBrowser } from "#angular/common";
import { ClassProvider, FactoryProvider, InjectionToken, PLATFORM_ID } from '#angular/core';
/* Create a new injection token for injecting the window into a component. */
export const WINDOW = new InjectionToken('WindowToken');
/* Define abstract class for obtaining reference to the global window object. */
export abstract class WindowRef {
get nativeWindow(): Window | Object {
throw new Error('Not implemented.');
}
}
/* Define class that implements the abstract class and returns the native window object. */
export class BrowserWindowRef extends WindowRef {
constructor() {
super();
}
get nativeWindow(): Window | Object {
return window;
}
}
/* Create an factory function that returns the native window object. */
export function windowFactory(browserWindowRef: BrowserWindowRef, platformId: Object): Window | Object {
if (isPlatformBrowser(platformId)) {
return browserWindowRef.nativeWindow;
}
return new Object();
}
/* Create a injectable provider for the WindowRef token that uses the BrowserWindowRef class. */
const browserWindowProvider: ClassProvider = {
provide: WindowRef,
useClass: BrowserWindowRef
};
/* Create an injectable provider that uses the windowFactory function for returning the native window object. */
const windowProvider: FactoryProvider = {
provide: WINDOW,
useFactory: windowFactory,
deps: [ WindowRef, PLATFORM_ID ]
};
/* Create an array of providers. */
export const WINDOW_PROVIDERS = [
browserWindowProvider,
windowProvider
];
In constructor of the component
constructor(#Inject(WINDOW) private window: Window)
In Module
#NgModule({
declarations: [..]
imports: [..]
providers: [WINDOW_PROVIDERS,...],
})
In style add
Position:fixed;
z-index:1000;
give the style to main div of the header.
use (window:scroll)="eventToBeCalled()" in the body tag
assign an id to toolbar:
<mat-toolbar color="primary" id="matTB">
and in typescript
eventToBeCalled(): void {
const matToolBar = document.getElementById('matTB');
if(window.scrollY > 104)
{
matToolBar.setAttribute('style', 'display:none');
} else {
matToolBar.removeAttribute('style');
}
}

AngularFire5 — Reference.update failed: First argument contains a function in property

I'm trying to save changes to an existing node in my Firebase DB, but I'm getting this error here:
Reference.update failed: First argument contains a function in property 'matatu-list.-L-RMcqjnladFM5-V80b.payload.node_.children_.comparator_' with contents = function NAME_COMPARATOR(left, right) {
return util_1.nameCompare(left, right);
}
I want to edit an item basing on its respective key (which is passed from another page through navParams).
Here is the interface I used to structure the DB:
interface.ts
export interface Matatu {
$key?: string;
matNumberPlate: string;
matSacco: string;
matDriver: string;
matAccessCode: string;
matStatus: string;
matTracker: string;
matLocation: string;
//Optionals
payload?:any;
key?:any;
}
The .ts and .html code that's meant to update the record:
.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AngularFireObject, AngularFireDatabase } from 'angularfire2/database';
import { Matatu } from '../../models/matatu/matatu.interface';
import { Subscription } from 'rxjs/Subscription';
#IonicPage()
#Component({
selector: 'page-edit-ma3',
templateUrl: 'edit-ma3.html',
})
export class EditMa3Page {
matatuRef$: AngularFireObject<Matatu>;
matatuAsync$: any;
matatu = {} as Matatu;
sub: Subscription;
constructor(public navCtrl: NavController, public navParams: NavParams, private database: AngularFireDatabase) {
const matKey = this.navParams.get('matKey');
this.matatuRef$ = this.database.object(`matatu-list/${matKey}`);
this.matatuAsync$ = this.matatuRef$.snapshotChanges();
//console.log(matKey);
this.sub = this.matatuAsync$.subscribe(
matatu => this.matatu = matatu
)
}
editMatatu(matatu : Matatu){
this.matatuRef$.update(matatu);
this.navCtrl.pop();
}
ionViewWillLeave(){
this.sub.unsubscribe();
}
}
.html
<ion-content>
<ion-list>
<ion-list-header>
Matatu Details
</ion-list-header>
<ion-item>
<ion-label>Sacco</ion-label>
<ion-input type="text" [(ngModel)]="matatu.matSacco"></ion-input>
</ion-item>
<ion-item>
<ion-label>Driver</ion-label>
<ion-input type="text" [(ngModel)]="matatu.matDriver"></ion-input>
</ion-item>
<ion-item>
<ion-label> Access Code</ion-label>
<ion-input type="password" [(ngModel)]="matatu.matAccessCode"></ion-input>
</ion-item>
</ion-list>
<ion-list radio-group [(ngModel)]="matatu.matTracker">
<ion-list-header>
Preferred Tracking
</ion-list-header>
<ion-item>
<ion-label>GPS</ion-label>
<ion-radio checked="true" value="GPS"></ion-radio>
</ion-item>
<ion-item>
<ion-label>Driver's Location</ion-label>
<ion-radio value="Driver's Location"></ion-radio>
</ion-item>
</ion-list>
<div padding>
<button ion-button block (click)="editMatatu(matatu)">Save Changes</button>
</div>
</ion-content>
How do I go about rectifying this? I'd appreciate it if it was pointed out to me where I went wrong, and what other approaches can get this done(even the dirty ones!).
You can pass the key in a placeholder variable or you could just concatenate it like so:
this.matatuRef$ = this.database.object(`matatu-list/`+ matKey);
Do keep in mind this is not a good approach, but it'll do the trick.
Firebase fires this error when you try to push data that contains a function, or a datatype instead of data values.
Basing on your interface, and the values you are passing from you template, your
update method should be like this:
editMatatu(matatu : Matatu){
this.matatuRef$.update({
matDriver: this.matatu.matDriver,
matAccessCode: this.matatu.matAccessCode,
matSacco: this.matatu.matSacco
});
}

Making Ionic2 Slides using Firebase data

I stored profile data in firebase and
trying to retrieve them and show them in template with slides.
(I am making a matching service.)
But it seems the template is loaded before data is assigned to variable.
When I am just retrieving one data, not list,
it works fine.
I tried all the solutions on the goole,
like using 'NgZone', *ngIf, etc but nothing worked.
Please help me.
My Error message.
FindMatePage.html:21 ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed
at DefaultIterableDiffer.diff (core.es5.js:7083)
at NgForOf.ngDoCheck (common.es5.js:1699)~~
My find-mate.ts file.
export class FindMatePage implements OnInit{
#ViewChild('profileSlide') slider: Slides;
profileList = [] as Profile[];
constructor(public navCtrl: NavController, public navParams: NavParams,
private databaseService: DataServiceProvider, private auth:
AuthServiceProvider,
) {}
ngOnInit(){
this.auth.getActiveUser().getIdToken()
.then((token: string) => (
this.databaseService.fetchProfileList(token)
.subscribe((list: Profile[]) => {
if(list) {
this.profileList = list;
console.log(this.profileList)
} else {
this.profileList = [];
}
})
))//then ends
}
My find-mate.html file
<ion-content class="tutorial-page">
<ion-slides *ngIf="profileList" #profileSlide pager
(ionSlideDidChange)="slideChanged()">
<ion-slide>
<h2 class="profile-title">Ready to Play?</h2>
<button ion-button large clear icon-end color="primary">
Continue
<ion-icon name="arrow-forward"></ion-icon>
</button>
</ion-slide>
<ion-slide *ngFor="let profile of profileList">
<ion-buttons block>
<button ion-button color="primary">채팅하기</button>
</ion-buttons>
<ion-item> {{profile.username}}</ion-item>
<ion-item> {{profile.gym}</ion-item>
<ion-item> {{profile.goal}}</ion-item>
<ion-item> {{profile.level}}</ion-item>
</ion-slide>
My part of data-service.ts file
//프로필 목록 가져오기
fetchProfileList(token: string) {
return this.http.get('https://fitmate-16730.firebaseio.com/profile-list.json?auth=' + token)
.map((response: Response) => {
return response.json();
})
.do((profileList: Profile[]) => {
if (profileList) {
console.log(profileList);
return this.profileList = profileList;
} else {
return this.profileList = null;
}
});
}

Resources