I need to understand the differences between ModalController and NavController in Ionic 2. When should I choose NavController and when to choose ModalController?
In the ModalController doc:
A modal uses the NavController to present itself in the root nav
stack. It is added to the stack similar to how NavController.push
works.
So we can say, in mechanism, they are the same. Lets talk about UX.
A Modal is a content pane that goes over the user's current page
A modal actually go over the page. It is like a popup. In small device, it take all the space of screen so you can not realize the diffentce from it and page. But if you test it in tablet like a ipad you will see the modal just take a part of screen and the current page is behind it.(Image description below).
What should be used?
In most case, you can use modal or page base on what you prefer but to ensure the properly UX modal should be used in case editing, making choice or getting information, other case page should be used
The ModalController is used to create and present modals. Modals are commonly used for galleries, edit forms, and other content that should be push on top of the current page.
import { ModalController } from 'ionic-angular';
import { Page1 } from './pages';
constructor(private modalCtrl: ModalController) {}
let modal = this.modalCtrl.create(Page1);
modal.present();
modal.onDidDismiss(() => {
// Action done after dismissing the modal.
});
The NavController is used for navigation functionality (think about Tabs or just basic page navigation). This controller also contains your navigation history.
import { NavController } from 'ionic-angular';
import { Page1 } from './pages';
constructor(private navCtrl: NavController) {
}
this.navCtrl.push(Page1);
So there are two different approaches to present the desired page. For more information/options/methods please ready the provided links, containing all available features available on the Modal- and NavController components.
Related
I am trying to simply execute code on a click of a bluetooth headset button in a SwiftUI 2.0 app, but after trying many different codes, nothing have worked... Does someone have solved this issue?
Based on apple docs and some answer I found on StackOverflow (https://stackoverflow.com/a/58249502/13207818), I tried this simple code
import SwiftUI
import MediaPlayer
struct ContentView: View {
init() {
MPRemoteCommandCenter.shared().pauseCommand.isEnabled = true
MPRemoteCommandCenter.shared().pauseCommand.addTarget(handler: { (event) in
print("Pause")
return MPRemoteCommandHandlerStatus.success
})
MPRemoteCommandCenter.shared().playCommand.isEnabled = true
MPRemoteCommandCenter.shared().playCommand.addTarget(handler: { (event) in
print("Play")
return MPRemoteCommandHandlerStatus.success
})
MPRemoteCommandCenter.shared().togglePlayPauseCommand.addTarget (handler: { (event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus in
// middle button (toggle/pause) is clicked
print("event:", event.command)
return .success
})
}
var body: some View {
Text("Hello World")
}
}
Of course Enabling Background Audio as per Apple doc
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
Even tried to activate my app audio session:
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, mode: .default, options: [.duckOthers, .allowBluetooth, .allowBluetoothA2DP])
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
print("audioSession is Active")
} catch {
print("audioSession properties weren't set because of an error.")
print(error)
}
But everything failed...
Would someone know what I am doing wrong or would have faced such issue with swiftUI 2.0?
Thank in advance for your support
In general you shouldn’t do actions in the initializers of views. Since they represent the state of the UI, not the actual UI they could be broken down and created again whenever SwiftUI thinks it needs to.
Im not at my pc but You can probably get a Publisher for the pause button which you can bind to a view with onReceive
Finally, I got a solution for my issue.
I don't know how it works really behind but the audio focus wasn't on my app. So I've just played a silent sound for a second and I could play properly with my play/pause button. I know that it's not a proper solution, but it works!
This reminds me of a similar bug on the galaxy s8...
If I find a better one, I'll keep you posted.
I have some flow on my app that, in some moment, I push a page to the stack and, on that page, I call a loading dialog for some data load. The problem is that the loading dialog didn't showed up. Then I realized that when I got back to the previous page, the loading was there, under my page that was being showed up. If in my navigation flow, instead of nav.push I use nav.setRoot, it works fine, so I think it's some glitch with that navigation stack. I really wanna use nav.pushcause it makes more sense for my app.
Any ideas?
EDIT:
my function that call the page:
onViewUnidade(unidade){
if (unidade.tipo == "Unidade Consumidora"){
this.nav.push(UnidadeConsumidoraPage, unidade);
}else if (unidade.tipo == "Usina"){
this.nav.push(UsinaPage, unidade);
}
}
my onInit method:
ngOnInit(){
console.log("show loading");
this.loading = this.loadingCtrl.create({
content: "some message"
});
this.loading.present();
}
My console.log executes, and I even didn't dismissed it, so I could see it correctly. The Loading and LoadingController are properly imported and injected.
EDIT 2:
I noticed that issue only happens when the page that redirects to my last page with the loading is a modal. If I change it for a regular page, it works correctly. Also, tried to dismiss the modal and popToRoot before navigate to new page... but still gotting same issue. Any ideas?
got my answer on documentation:
Instead of injecting navigation controller, when you wanted to navigate from an overlay component (popover, modal, alert, etc), we have to get a reference of the root NavController in our app, using the getRootNav() method:
this.appCtrl.getRootNav().push(SecondPage);
Hope this helps who got the same problem!
Have a look at LoadingOptions
export interface LoadingOptions {
spinner?: string;
content?: string;
cssClass?: string;
showBackdrop?: boolean;
dismissOnPageChange?: boolean;
delay?: number;
duration?: number;
}
You can set dismissOnPageChange(to true). Make sure you dismiss the loading dialog or set duration.
I want to have the android back button to close the app if the user is on one of the two main pages. Both pages can be navigated to with two tabs button, which are shown on those both pages. But on any other pages I want to keep normal stack pages behaviour.
I read about registerBackButtonAction and also got some information in this thread concerning Ionic 1.
I created a custom behaviour to close the app:
private registerSpecificActionOnBackButton = () => {
if(this.platform.is('android')||this.platform.is('windows')){
this.platform.registerBackButtonAction(function(e){
this.platform.exitApp();
}.bind(this),101);
}
}
My idea is to call the registerSpecificActionOnBackButton() function in the ionViewWillEnter() function on the pages where this behaviour is needed.
But I don't manage to cancel that behaviour on the ionViewWillLeave() function with a deRegisterSpecificActionOnBackButton() function, I've tried among other things:
private deRegisterSpecificActionOnBackButton = () => {
if(this.platform.is('android')||this.platform.is('windows')){
this.platform.registerBackButtonAction(function(e){return true},101);
}
}
Or
private deRegisterSpecificActionOnBackButton = () => {
if(this.platform.is('android')||this.platform.is('windows')){
this.platform.registerBackButtonAction(function(event){event.unbind()},101);
}
}
But I happen to be stuck. Has anyone any idea about canceling a custom registerBackButtonAction?
I've managed to make this work as I expect: When the app is on one of the pages that can be reached thru the tabs menu, it closes when the back button is hitten (on Android).
First, forget about the registerBackButtonAction() for the moment because as quoting what is explained in this thread of 2016-08-05:
it suggests not trying to override the default back button behavior.
So I've looked for other solutions. I've found one that is not really clean but works.
To begin with, I looked if I could reset the stack with the NavControler using remove(startIndex, removeCount, opts). But that doesn't work out because the two main pages are embeded in the tab page (like it is shown there).
So when you're on one of those pages the NavController is a Tab and the parent of that is a Tabs.
In Tabs there is a Array variable named _selectHistory. The _selectHistory array seems to have a role similar to the stack. So when navigating from one page to another using the two tab buttons, one can see in a console.info(this.[NavControler var of the page].parent._selectHistory) that the array grows as the tab buttons are hitten alternatively. And when trying on a real device, the back button take you back switching from one page to another until the array is empty and then the next back button hit closes the app.
Hence I thought: Let see what happens if I override the value of that array. It cannot be done thru a function to apply on a Tabs object (unlike what is possible with NavController).
So in the Page concerning my pages embedded in the Tab page, I added the following in ionViewWillEnter():
ionViewWillEnter(){
this.navCtrl.parent._selectHistory=[];
}
This.navCtrl is my NavController object passed in the constructor of the page.
That's it.
I have an element which's height expands upon hover, however the page does not scroll down when the element extends beyond the view box.
I've heard using jquery to focus on the element upon mouseEnter allows this to work properly.
Here's what I have so far:
export default Ember.Component.extend({
mouseEnter() {
$(this).focus();
}
});
I've just started using Ember and am not 100% on how components work, so any information is welcome.
You were almost there.
export default Ember.Component.extend({
mouseEnter() {
this.$().focus();
}
});
I am struggling to document the router for my design of a shop. The shop consists mainly of a article/product slider. See the image below:
As you see:
on top an article navigation slider
in the center the current selected article
on the left the menu, which pages will be a popup over the current article
when the user clicks the shoppingcart, go to checkout, open up a page, log in their account, or whatever they do, there will be always an active article.
The router
So I thought - and correct me if I am wrong - to the design my router as follows:
Router.map(function() {
this.resource('articles', function() { // to fill the articles slider above
this.resource('article', function(path: ':article_id') { // to show the current selected article in the slider
// large popups - covers the current article almost
// completely with a little transparancy
this.resource('page', function(path: ':page_id')); // shows a page from the menu
this.resource('checkout', function(path: ':step_id')); // the checkout with multiple steps
// small popups at the bottom of the page
this.route('info'); // shows the additional product info popup
this.route('shipping'); // shows the shipping info popup
});
});
});
Additional information: I use Ember App Kit for developing and the slider will be Flexslider 2 mainly because they have touch support.
It looks like a valid router, however the question is whether it is the Ember way.