Ionic v4 `menuController.enable` method not working on first page loaded - ionic4

I use a sidemenu project with ionic v4-beta3
I want to disable sidemenu on some pages, /login for example.
It's working properly when i load /home page first then i navigate to /login page. Sidemenu desapear as expected.
When i reload my application on /login page, menu is not disabled.
import { Component, OnInit } from '#angular/core';
import { MenuController } from '#ionic/angular';
#Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
constructor(
private menuController: MenuController
) {}
ngOnInit() {}
ionViewWillEnter() {
console.log('ionViewWillEnter');
this.menuController.enable(false);
}
ionViewDidLeave() {
console.log('ionViewDidLeave');
this.menuController.enable(true);
}
}
If a use a setTimeout of 100 or 200 ms to call enable method, side menu desapears but it's not very clean...
ionViewWillEnter() {
console.log('ionViewWillEnter');
const timer = setTimeout(() => {
clearTimeout(timer);
this.menuController.enable(false);
}, 100);
}
Another work-around is to show ion-menu when window.location.pathNameis not equal to /login with a *ngIf directive. It's working but i find this not very clean too...
Ionic Infos
Ionic:
ionic (Ionic CLI) : 4.1.1
Ionic Framework : #ionic/angular 4.0.0-beta.3
#angular-devkit/core : 0.7.4
#angular-devkit/schematics : 0.7.4
#angular/cli : 6.1.4
#ionic/ng-toolkit : 1.0.6
#ionic/schematics-angular : 1.0.5

This issue appears to be resolved in 4.0.0-beta.12 with the following:
ionViewDidEnter() {
this.menuController.enable(false);
}
ionViewDidLeave() {
this.menuController.enable(true);
}

The MenuController.enable() method is asynchronous.
You can create a Guest/Authenticated guard and enable it there, and then use it in pages using the canActivate route parameter in your pages. Then, when your page loads, the menu will be configured properly. For example, for authenticated guard:
#Injectable({
providedIn: 'root',
})
export class AuthenticatedGuard implements CanActivate {
constructor(private menuController: MenuController) {}
async canActivate(): Promise<boolean> {
const isAuthenticated = true; // Adjust where you get this value
await this.menuController.enable(isAuthenticated);
return isAuthenticated;
}
}
This will work for Ionic4/5.
You should use menuId property in your <ion-menu/> components for fine-tune identity and be able to use multiple menus. Then you can call .enable(isAuthenticated, menuId);

Related

How can I access ngOffline directive in a component instead of html

I'm using this npm library https://www.npmjs.com/package/ng-offline to alert end user when offline.
<div class="alert alert-danger" ngOffline>You're offline. Check your connection!</div>
stackblitz here: https://stackblitz.com/edit/angular-ngoffline-npm?file=src%2Fapp%2Fapp.component.html
Works great - BUT I want to open a modal with this ngOffline directive, so I'm trying to access the directive from my angular 11 component but not sure how to approach this, any help on this would be greatly appreciated.
Is there away for me to open a ngx-bootstrap modal from the html with this directive?
Because the ng-offline module isn't exporting things as you might expect (i.e. you can't inject a standalone NgOfflineDirective for you to use without having it in your html file), you could add a block like this (where you've used #trigger to identify your ngOnline element):
import { AfterContentChecked, Component, ElementRef, OnDestroy, ViewChild } from '#angular/core';
import { BehaviorSubject, Subscription } from 'rxjs';
import { distinctUntilChanged, filter } from 'rxjs/operators';
#Component({ ... })
export class YourClass implements AfterContentChecked, OnDestroy {
offline$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>();
subscription: Subscription;
#ViewChild('trigger') trigger: ElementRef;
constructor() {
this.subscription = this.offline$.pipe(
distinctUntilChanged(),
filter((offline: boolean) => offline),
).subscribe(() => this.showModal());
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
ngAfterContentChecked() {
if (
this.trigger &&
this.trigger.nativeElement
) {
this.offline$.next(this.trigger.nativeElement.style.display === "none");
}
}
showModal() {
console.log('Show your modal here.');
}
}

How to dynamically go to previous page (ionic 4)?

Currently im migrating my ionic 3 project to ionic 5, in ionic 3 we use this.navCtrl.getPrevious().name;
to get the previous page name by getting the previous page name i will navigate to different pages based on the previous page name can you please help me how can i get previous page name in ionic 4
Ionic 4+ moved away from navCtrl and leverages Angular Router.
To read previous URL (route) you may do it via PreviousRouteService:
import { Injectable } from '#angular/core';
import { Router, RoutesRecognized } from '#angular/router';
import { filter, pairwise } from 'rxjs/operators';
#Injectable({
providedIn: "root"
})
export class PreviousRouteService {
private previousUrl: string;
private currentUrl: string;
constructor(private router: Router) {
this.currentUrl = this.router.url;
this.previousUrl = null;
this.router.events
.pipe(filter((event: any) => event instanceof RoutesRecognized), pairwise())
.subscribe((events: RoutesRecognized[]) => {
this.previousUrl = events[0].urlAfterRedirects;
this.currentUrl = events[1].urlAfterRedirects;
});
}
public getPreviousUrl() {
return this.previousUrl;
}
};
The service imports Router and tracks changes so that any component that needs previous URL information can import this service and access previous route:
constructor(
private previousRouteService: PreviousRouteService
) {}
const prevUrl = this.previousRouteService.getPreviousUrl();

Vue.js + Bootstrap - question - invoking $bvToast from store.js

I have probably very profoundly simple question: how to invoke methods located in components from store.js, for instance I want a toast popup from store mutation. Any ideas?
The $bvToast can be found in BToast export. You can import it to use it.
import { BToast } from 'bootstrap-vue'
Example Class
import { BToast } from 'bootstrap-vue'
class uiUtils
{
showToast(message : string,title : string){
let bootStrapToaster = new BToast();
bootStrapToaster.$bvToast.toast(message, {
title: title,
toaster: "b-toaster-top-right",
solid: true,
appendToast: false
})
}
}
export default new uiUtils();
The documentation does show the individual component exports at the bottom of the page and can be found here Bootstrap Vue Documentation.

How to create a loader Spinner in Angular 5

I am new in angular 5. I want to create a mock json data in my service and i want to create a Spinner loader when i clicked the button .To display the spinner few seconds,in Angular 5 .
Thank you.
you can use ngx-spinner in your project. It's very easy to install and you have many options of spinner.
First Step: Install the lib
npm install ngx-spinner --save
Second step:
Import the lib in your module (app.module.ts)
// Import library module
import { NgxSpinnerModule } from 'ngx-spinner';
#NgModule({
imports: [
// ...
NgxSpinnerModule
]
})
export class AppModule { }
Third step: Add (or edit) the code below in your app.component.html
<ngx-spinner bdColor="rgba(51, 51, 51, 0.8)" size="medium" color="#dd8f44" type="line-scale-pulse-out-rapid"></ngx-spinner>
Fourth step: Use in your component or service
import { NgxSpinnerService } from 'ngx-spinner'; <--
#Component({
selector: 'app-client',
templateUrl: './client.component.html',
styleUrls: ['./client.component.scss']
})
export class ClientComponent implements OnInit {
constructor(
private spinner: NgxSpinnerService <--
) { }
ngOnInit() {
this.spinner.show(); <---
setTimeout(() => {
this.getClients();
this.spinner.hide(); <---
}, 1000);
}
}
I hope I helped you
You can use Angular Material Progress Bar.

defining providers for an angular2 component using dart

I'm writing an angular2 dart application using Intellij.
I created a provider called Auth that should be injected to the app component.
I defined the Auth service using the following code:
import 'package:angular2/core.dart';
import 'package:auth0_lock/auth0_lock.dart';
import './config.dart';
#Injectable()
class Auth {
Auth0Lock lock;
Auth() {
this.lock = new Auth0Lock(configObj.auth0.apiKey, configObj.auth0.domain);
}
updateProfileName(data) {
var profile = data['profile'] != null ? data['profile'] : data;
print(profile['name']);
}
login() {
this.lock.show(popupMode: true, options: {'authParams': {'scope': 'openid profile'}}).then(this.updateProfileName);
}
}
and the app component using the following code:
import 'package:angular2/core.dart';
import 'package:angular2/router.dart';
import 'welcome_component.dart';
import 'auth_service.dart';
#Component(
selector: 'my-app',
templateUrl: '/www/my-app.html',
providers: [Auth]
)
#RouteConfig(const [
const Route(path: '/welcome', component: WelcomeComponent, name: 'welcome')
])
class AppComponent {
Auth auth;
AppComponent(Auth auth) {
this.auth=auth;
}
}
now intellij is complaning about the providers array with the error message arguments of constant creation must be constant expressions.
I'm new to dart... but if the Component configuration needs consts, how can I provide classes to be used there ?
thanks
Just adding const should do:
providers: const [Auth]
The error you're seeing is because [Auth] creates a List that — although it contains only a const memeber — is itself not constant. (For example, it could be added to, or cleared.) Dart requires you to specify explicitly that the List is constant.