How to customize side menu animation - ionic-framework

I´m developing an Ionic 4 aplication and I want to usea a custom side menu animation like this:
but Ionic only have 3 options: push, overlay and reveal.
I already have my 3dmenu.ts file but I don´t no how to inject it to use It with the Ion-menu componet like the other 3 options, could some one give a hint about how to do this?

I finally can do it, Using workaruond than I found here here. The trick is extend the menu controller class to create a new method registerAnimation:
Step 1: Create a new ts file (extended.ts or the name than you want) and put this code inside:
import { DOCUMENT } from '#angular/common';
import { Inject, Injectable } from '#angular/core';
import { MenuController } from '#ionic/angular';
import { AnimationBuilder } from '#ionic/core';
function proxyMethod(ctrlName: string, doc: Document, methodName: string, ...args: any[]) {
const controller = ensureElementInBody(ctrlName, doc);
return controller.componentOnReady()
.then(() => (controller as any)[methodName].apply(controller, args));
}
function ensureElementInBody(elementName: string, doc: Document) {
let element = doc.querySelector(elementName);
if (!element) {
element = doc.createElement(elementName);
doc.body.appendChild(element);
}
return element as HTMLStencilElement;
}
const CTRL = 'ion-menu-controller';
#Injectable({
providedIn: 'root',
})
export class EloMenuController extends MenuController {
constructor(#Inject(DOCUMENT) private document: any) {
super(document)
}
/**
* Registers a new animation that can be used with any `ion-menu` by
* passing the name of the animation in its `type` property.
*
* #param name The name of the animation to register.
* #param animation The animation function to register.
*/
registerAnimation(name: string, animation: AnimationBuilder) {
return proxyMethod(CTRL, this.document, 'registerAnimation', name, animation);
}
}
Step 2: Create a new ts file with the animation, in my case I use this:
import { Animation, MenuI } from '#ionic/core';
export function menu3D (AnimationC: Animation, baseEl: HTMLElement, menu: MenuI):
Promise<Animation> {
let contentOpenedX: string;
let menuClosedX: string;
const width = menu.width;
const baseAnimation = new AnimationC();
if (menu.isEndSide) {
contentOpenedX = -width + 'px';
menuClosedX = width + 'px';
}
else {
contentOpenedX = width + 'px';
menuClosedX = -width + 'px';
}
const menuAnimation = new AnimationC()
.addElement(menu.menuInnerEl)
.fromTo('z-index', '0', '0')
.fromTo('translateX', menuClosedX, '0px');
const contentAnimation = new AnimationC()
.addElement(menu.contentEl)
.fromTo('translateX', '0px', contentOpenedX)
.fromTo('scale', '1', '0.7');
const backdropAnimation = new AnimationC()
.addElement(menu.backdropEl)
.fromTo('opacity', 0.01, 0.32);
return Promise.resolve(baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(0.0, 0.0, 0.2, 1)')
.easingReverse('cubic-bezier(0.4, 0.0, 0.6, 1)')
.duration(300)
.add(contentAnimation)
.add(menuAnimation)
.add(backdropAnimation));
};
Step 3: import in your app.component.ts the extended class and the animation and register your animation to be able to use it:
import { Component, OnInit, Input } from '#angular/core';
import { Extend } from './animations/extend
import { menu3D } from './animations/menu3D';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
#Input() name: string;
constructor(
private menu: Extend
) {
this.menu.registerAnimation('menu3d', menu3D);
}
ngOnInit() {}
}
Step 4: configure the type to your ion-menu component
<ion-menu side="start" type="menu3d" style="z-index: 10;">
........
</ion-menu>
Step 5: Don't forget to thanks to svallory from github and Enjoy it :-)
I don´t konw if it this the best way to do it but its the only way than I found after 5 days searching, I hope this helps other and if anyone can improve this feel free to comment :-)

Related

How to creat a dynamic text

I have a list of titles, and I would like these texts to alternate as I switch to ion-select. How do I do this?
I have no idea how to do this, not even what part of the code to show. I made an attempt here but whenever I use the console the value returned is undefined.
My typescrit code:
import { Titulo } from './../Services/services.service';
import { DataService } from './data.service';
import { Component, OnInit, ViewChild} from '#angular/core';
import {IonSlides} from '#ionic/angular';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-libertacao',
templateUrl: './libertacao.page.html',
styleUrls: ['./libertacao.page.scss'],
})
export class LibertacaoPage implements OnInit {
#ViewChild(IonSlides) slides: IonSlides;
PAGINA_SELECIONADA: number;
// tslint:disable-next-line: variable-name
index_atual: number;
titulo: Titulo;
constructor(private dataservice: DataService, private activatedRoute: ActivatedRoute ){
}
ngOnInit() {
const id = this.activatedRoute.snapshot.paramMap.get('id');
this.titulo = this.dataservice.getTituloById(parseInt(id, 10));
}
OnChange(event: any)
{
if (event.detail.value === this.PAGINA_SELECIONADA) {
this.slides.slideTo(this.PAGINA_SELECIONADA);
}
else {}
console.log(this.titulo);
}
slideChanged() {
this.slides.getActiveIndex().then((index) => {
this.index_atual = index;
});
}
}

Ionic 4. Alternative to NavParams

I am using ionic 4. It does not accept to receive data using navparams.
Here is my sender page method:
//private route:Router
gotoFinalView(intent) {
this.route.navigateByUrl(`${intent}`, this.destination);
}
Receiver page line;
//private navParams:NavParams
this.destination = navParams.data;
What is the right approach to doing this in ionic 4. I am also uncertain whether gotoFinalView method is valid.
This is how I solved my problem:
I created a Service with a setter and getter methods as;
import { Injectable } from "#angular/core";
#Injectable({
providedIn: "root"
})
export class MasterDetailService {
private destn: any;
constructor() {}
public setDestn(destn) {
this.destn = destn;
}
getDestn() {
return this.destn;
}
}
Injected the Service and NavController in the first page and used it as;
gotoFinalView(destn) {
this.masterDetailService.setDestn(destn);
this.navCtrl.navigateForward("destn-page");
}
Extracted the data at the final page by;
constructor(
private masterDetailService: MasterDetailService
) {
this.destination = this.masterDetailService.getDestn();
}
This is the efficient way to solve your problem
user Angular Routers concepts in your application.
just declare your router like the following
Your app routing module like the following
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import {ViewComponent} from "./crud/view/view.component";
import {CreateComponent} from "./crud/create/create.component";
import {UpdateComponent} from "./crud/update/update.component";
import {ReadComponent} from "./crud/read/read.component";
const routes: Routes = [
{path: '', component: ViewComponent},
{path: 'create', component: CreateComponent},
{path: 'update/:id', component: UpdateComponent},
{path: 'view/:id', component: ReadComponent}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
:id is the parameter what i want to send to that page.
this.router.navigate([link + '/' + id]);
share your parameter like this in your first page.
In your second page inject the activated route using DI(Dependency Injection)
constructor(private actRoute: ActivatedRoute)
Then Get your parameters using the following code
this.productID = this.actRoute.snapshot.params['id'];
This is the simple way. You can send multiple parameter at a time.
{path: 'update/:id/:name/:price', component: UpdateComponent}
and get those parameters like the following
this.productID = this.actRoute.snapshot.params['id'];
this.productName = this.actRoute.snapshot.params['name'];
this.productPrice = this.actRoute.snapshot.params['price'];
While Routing you can write like this:
this.router.navigate(["/payment-details",{
prev_vehicle_type: this.vehicle_type,
prev_amt: this.amt,
prev_journey:this.whichj
}]);
To get this parameters on the next page you can write:
constructor(
public router: Router,
public activateroute: ActivatedRoute){
this.activateroute.params.subscribe((data: any) => {
console.log(data);
this.vehicle_type = data.prev_vehicle_type;
this.amt = data.prev_amt;
this.whichj = data.prev_journey;
});
}
ionic 4 navigation with params
sender page
1. import the following
import {NavController} from '#ionic/angular';
import { NavigationExtras } from '#angular/router';
constructor(private navCtrl:NavController)
sender page
gotonextPage()
gotonextPage()
{
let navigationExtras: NavigationExtras = {
state: {
user: 'name',
parms:Params
}
};
this.navCtrl.navigateForward('pageurl',navigationExtras);
}
4.Receiver Page
import { ActivatedRoute, Router } from '#angular/router';
constructor( private route: ActivatedRoute, private router: Router)
{
this.route.queryParams.subscribe(params => {
if (this.router.getCurrentNavigation().extras.state) {
this.navParams = this.router.getCurrentNavigation().extras.state.parms;
}});
}
Send data with Router service and extract with global variable, history
//sender component
// private router: Router
nextPage() {
this.router.navigate(['history'],
{ state: [{ name: "covid-19", origin: "china" },{ name: "ebola", origin: "us" }] }
)
}
//receiver page
ngOnInit() {
let data = history.state;
console.log("data-->",data);
// ** data**
//0:{name: "covid-19", origin: "china"} 1: {name: "ebola", origin: "us"} navigationId: 2
}
The item, icon and title variables you want to send should be written in the state in this way.
this.nav.navigateForward('/myUrl', {
state: {
'items': this.substances,
'icon': ICONS.substance,
'title': 'Etken Maddeler'
}
});
We take incoming variables this way.
//receive
constructor(
protected route: ActivatedRoute,
protected router: Router,
) {
this.selectedItem = null;
this.route.paramMap.subscribe(params => {
let st = this.router.getCurrentNavigation().extras.state;
if (st) {
this.selectedItem = st.items;
}
});
}
Very very simply, you can do something like this:
In the "calling screen" :
this.router.navigate(['url', {model: JSON.stringify(myCustomObject)}])
In the "called screen" :
this.myvar = JSON.parse(this.activatedRoute.snapshot.paramMap.get('model')
Et voilà !
//in home.ts
import{ Router,ActivatedRoute, NavigationExtras } from '#angular/router';
getProductStatics(productObject : any) {
var object1 = {
id: productObject,
}
const navigationExtras: NavigationExtras = {state : {object:
JSON.stringify(object1)}};
this.router.navigate(["/product-statics"], navigationExtras);
}
//in product-statics.ts
import{ Router,ActivatedRoute,NavigationExtras } from '#angular/router';
if(self.router.getCurrentNavigation().extras.state) {
var object1
= this.router.getCurrentNavigation().extras.state.object;
var object = JSON.parse(object1);
var newObjectData = object.id;
}

angular2-mdl table component with server side data

I experiment with Angular 2 - Material Design Lite especially with the table component but I can not figure out how would I pass data from server on ajax request. Here is the example provided for table initialisation.
How would I pass data from restAPI to table component?
Here I have a kind of working example. I placed the initial data on my Component Init method where I call the DataService which populates the table. I'm not sure if is the right workaround but at this point I have data in table.
import { Component, ViewChild, ViewContainerRef, OnInit, Pipe, PipeTransform } from '#angular/core';
import { MdDialog, MdDialogConfig, MdIcon } from "#angular/material";
import { AuthenticationService, DialogsService, DataService } from '../../../services/';
import { RouterModule, Routes, Router } from '#angular/router';
import {
IMdlTableModelItem,
MdlDefaultTableModel
} from 'angular2-mdl';
export interface ITableItem extends IMdlTableModelItem {
username: string;
email: string;
role: string;
unitPrice: number;
}
#Component({
selector: 'employees',
templateUrl: 'app/layouts/secure/employees/employees.html',
providers: [DialogsService, MdIcon]
})
export class EmployeesComponent implements OnInit {
public message: string;
public employees: any[];
public result: any;
public showSearchBar: false;
public tableData:[ITableItem];
public selected;
public tableModel = new MdlDefaultTableModel([
{key:'username', name:'Username', sortable:true},
{key:'email', name:'Email', sortable:true},
{key:'role', name:'Role', sortable:true},
{key:'status', name:'Status', sortable:true},
{key:'unitPrice', name:'Test', numeric:true}
]);
constructor(
private dialogsService: DialogsService,
public viewContainerRef: ViewContainerRef,
private _dataService : DataService,
private router: Router
) {
}
openDialog() {
this.dialogsService
.confirm('User Form', 'Are you sure you want to do this?', this.viewContainerRef)
.subscribe(res => this.result = res);
}
toggleSearch() {
console.log(this)
}
ngOnInit() {
var self = this;
this._dataService
.GetAll('employees')
.subscribe( data => {
data = Object.keys(data).map((key)=>{ return data[key]})
this.employees = data;
this.tableData = data;
this.tableModel.addAll(this.tableData);
}, error => console.log(error),
() => function ( data ) {
this.tableData = this.employees;
this.tableModel.addAll(this.tableData);
this.selected = this.tableData.filter( data => data.selected);
},
);
}
generateArray(obj){
return Object.keys(obj).map((key)=>{ return obj[key]});
}
selectionChanged($event){
this.selected = $event.value;
}
}
#fefe made it a little more difficult than it had to be, at least with the current version. The magic of the as keyword can do the heavy lifting.
For example my class setup looks like:
import...
export interface IUnreadMessage extends IMdlTableModelItem {
messageId: number;
subject: string;
from: string;
}
#Component ...
export class ...
private unreadMessagesTable = new MdlDefaultTableModel([
{key: 'messageId', name: 'Message ID'},
{key: 'subject', name: 'Subject'},
{key: 'from', name: 'From'}
]);
Then in my ajax call I have:
...ajax call here).subscribe(value => {
const messages = value as Array<IUnreadMessage>;
this.unreadMessagesTable.addAll(messages);
},
error => {
...error handler here...
});
Make sure your interface is EXACTLY (including case) the same as your returned ajax data and it should hook right up!

ionic 2: how to dismiss loader after data is ready?

In my Ionic 2 app, I have i have component that GET to fetch data.
i want to maker loader and dismiss it after data is ready.
i tried to look on other posts around the stack overflow but my issue is different.
i did something but the loader is forever and its not helps me.
It looks like following:
import { Component,ViewChild } from '#angular/core';
import { NavController,LoadingController,AlertController,ViewController} from 'ionic-angular';
import { Facebook } from 'ionic-native';
//import pages
import {LoginPage} from "../../pages/login/login";
import {User} from '../../models/user'
import { Storage} from '#ionic/storage';
//import provider
import { ProfileData } from '../../providers/profile-data';
import { NotesData } from '../../providers/notes-data';
import firebase from 'firebase'
import {AddNote} from "../add-note/add-note";
/*
Generated class for the NotesList page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-notes-list',
templateUrl: 'notes-list.html'
})
export class NotesList {
//facebook user
userProfile: any = null;
uid: any = null;
fireUid:any=null;
name:string=null;
photo: any =null;
user:User=null;
photos:any=null;
currentUser:any=null;
photonew:any=null;
//notes list
notes:any=null;
data:any;
pages: Array<{title: string, component: any}>;
constructor(public navCtrl: NavController,public profileData:ProfileData,private viewCtrl: ViewController,public notesData:NotesData,private loadingCtrl: LoadingController,private alertCtrl: AlertController,public storage:Storage) {
this.data={};
this.data.title="";
this.data.desc="";
}
ionViewDidLoad() {
//if i do that the loader is forever
/*
let loader = this.loadingCtrl.create({
dismissOnPageChange: true,
});
loader.present();
*/
// here i want the loader to be until the data is ready.
this.getNotesList(); //this functions not returns data so i can't do this.getNotesList().then(()=>
}
getNotesList(){
console.log("get event");
var that=this;
this.notesData.getNotesLIst().on('value', snapshot => {
let notesList= [];
snapshot.forEach( snap => {
console.log("id note"+snap.val().id);
notesList.push({
id: snap.val().id,
title: snap.val().title,
desc: snap.val().desc,
color:snap.val().color,
photo:snap.val().photo,
});
});
that.notes = notesList;
});
}
addNote(){
this.navCtrl.push(AddNote);
}
logOutFacebook(){
Facebook.logout().then((response)=>
{
this.navCtrl.push(LoginPage);
alert(JSON.stringify(response));
},(error)=>{
alert(error);
})
}
}
At first, you should show how do you implement your loading page. Is it a splash screen with cordorva? Or just as div displaying some image?
If it is a splash screen, you can add this code in your component after you get data, (it is from starter template, you can see the detail by creating a new project with ionic start):
this.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();
});
And, if you use a div in your index page, it is similar, you can just get that element and remove it, with pure js.
okay it succeed to do that
this is my answer
ionViewDidLoad() {
let loader = this.loadingCtrl.create({});
loader.present();
this.getNotesList().then((x) => {
if (x) loader.dismiss();
});
}
getNotesList(){
return new Promise(resolve => {
var that=this;
this.notesData.getNotesLIst().on('value', snapshot => {
let notesList= [];
snapshot.forEach( snap => {
console.log("id note"+snap.val().id);
notesList.push({
id: snap.val().id,
title: snap.val().title,
desc: snap.val().desc,
color:snap.val().color,
photo:snap.val().photo,
});
});
that.notes = notesList;
resolve(true);
});
})
}

Ionic 2 Slides Component - How to Access Swiper API

Using ion-slides component (4 slides) on app welcome page/slides. I need ability for user to skip to last slide. Docs say ion-slides implementation of Swiper API. I need to access methods like: mySwiper.slideTo(index, speed, runCallbacks);
Tips on how to implement?
You can pass a function within the options property.
Original answer.
#Component({
selector: 'my-component',
template: '<ion-slides [options]="options">
<ion-slide>Slide1</ion-slide>
<ion-slide>Slide2</ion-slide>
</ion-slides>',
directive: [IONIC_DIRECTIVES]
})
export class MyComponent {
public slider: any;
constructor() {
this.options = {
onlyExternal: false,
onInit: (slides: any) =>
this.slider = slides
}
}
click() {
this.slider.sliderNext(true, 250);
}
}
For further options have a look at the swiper api.
If you are looking for a simple solution without custom directives, you can try this
constructor(
private _app: IonicApp
){}
ngAfterViewInit() {
this._slider = this._app.getComponent('my-slider');
}
goToSlide(slideIndex){
this.slider.slider.slideTo(slideIndex);
}
You can make a service with your Swiper
#Injectable()
export class HomeSwiper {
swiper = null;
initSwiper(selector) {
this.swiper = new Swiper(selector, {
pagination: '.home-swiper-pagination',
speed: 400,
spaceBetween: 100,
nextButton: '.swiper-button-next',
prevButton: '.swiper-button-prev'
});
}
goTo(index) {
this.swiper.slideTo(index);
}
}
And use it into your #Page
#Page({
templateUrl: 'build/pages/home/home.html',
providers: [HomeSwiper]
})
export class Home {
constructor(private swiperService: HomeSwiper) {
this.swiperService.initSwiper('.home-modal-swiper-container');
}
skipSlides() {
this.swiperService.goTo(indexOfTheLastSlide);
}
}