Clicking Hastily Causes Routing Issue - ionic-framework

I have a simple Ionic v1 app that displays a list of items. Clicking on an item navigates the user to a new view displaying info about the item.
If the user selects a second before the first item is loaded, the app will navigate to both views respectively, which is an issue.
Is there a way to prevent this via an ionic config or angular?
Note I am using Ionic Native Transitions, but this issue seems to be independent
*Edit * I know I can use something like a 'loading' modal to prevent clicks, but then I'll have to do this for every single list in the application that loads data, so that doesn't sound ideal

I ended up utilizing inoicNativeTransition.beforeTransition in order to render a modal-style backdrop that prevents users from clicking for 300ms
$rootScope.$on('ionicNativeTransitions.beforeTransition', function(){
$rootScope.stateTransitioning = true;
$timeout(function(){
$rootScope.stateTransitioning = false;
}, 300)
});
HTML
<div ng-show="stateTransitioning === true" id="inivisible-backdrop"> </div>
I don't hide the backdrop on the success of the transition, because there seems to be an inconsistent lag between when the view is changed and the transition is marked as 'successful'. 300ms seems to work just fine

Related

Does Ionic 5 has swipe events?

I have an Ionic page on which I'd like to be redirected to a custom page when swiping left. Just redirecting me back isn't good enough, since I can have that page open from a deep link, meaning I have no back on my window's history.
I saw that there's a gesture API, but it's a bit too much for such a common cause. Also, I saw that on previous versions there where swipe left/right events, but no reference for it on Ionic 4/5.
Doesn't Ionic 5 has an on-swipe-left event?
Another solution, if you didn't want to add a hammerjs dependency and just use Ionic would be to use the official ion-slides component to manage your pages as slides.
I've implemented this on a couple of apps and it works really well.
In your example, you would want to setup an <ion-slides> container and then your 'pages' would exist inside as <ion-slide> components.
You can then easily tap into the (ionSlideDidChange) event as follows:
<ion-slides
*ngIf="!isLoading && pages"
[options]="slideOptions"
(ionSlideDidChange)="onSlideChange()"
class="em-height-full"
#pages
>
Then in your .js or .ts file just create a method like:
async onSlideChange() {
this.pageIndex = await this.slides.getActiveIndex();
}
Then you could track the page with pageIndex. So in your case, you'd open the page from the deepLink (maybe have it route to 'page 2') and then when you swipe left on the slide component you could go to page 1.
You are looking for this: https://ionicframework.com/docs/utilities/gestures
Adding HammerJS is not a great idea since you might encounter buggy scenarios.

Ionic content not updating after callback from external plugin

As part of the functionality of the app we are developing, when an android alarm is fired, a dialog box is to appear with an "Accept" or "Reject" button. Selecting reject does nothing, but selecting "Accept" triggers a callback from the plugin, which I have passed a function into. This function causes the ionic app to navigate to the root page of the app.
The issue I am having is, when I then navigate to another page after that where the user selects a value, and this value is displayed back to them and a button is enabled, the value display is not updating, and the button is not becoming enabled. Nothing seems to be updating.
What I have found is that pressing the back button on my android device will cause the page to update, which is not ideal.
This functionality works without the callback from the plugin.
What is happening here? And how do I fix it?
Passing the function into the plugin.
alarms_plugin.onAlarmRecieved = (alarmId) =>{
this.events.publish('alarmRecieved', alarmId);
}
Plugin-side functions
alarmRecieved: function(alarmId){
alarms_plugin.onAlarmRecieved(alarmId);
}
onAlarmRecieved: null
Navigating to root page on alarmRecieved
this.events.subscribe('alarmRecieved', (alarmId) =>{
if(alarmId != 'TIMEOUT')
this.nav.setRoot(HomePage);
});
Fix found by surrounding the this.nav.setRoot(HomePage) in this.zone.run(..).
Supposedly calling navigation within a subscription event causes issues like I was having.

Ionic- need an event after page is backed

I need an event of page which is backed.
IonWillEnter or ionViewDiEnter events aren't fired when page is backed.
Ionic framework seems to show page simply when a back button is clicked.
Would you like to teach me?
Sorry for my poor English.
Thanks
For your info.. Ionic 2 lifecycle method
ionViewDidLoad - works the same way as ngOnInit, fires once when the view is
initially loaded into the DOM
ionViewWillEnter and ionViewDidEnter - hooks that are available before and after the page becomes active
ionViewWillLeave and ionViewDidLeave - hooks that are available before and after the page leaves the viewport
ionViewWillUnload - is available before the page is removed from the DOM
You should use ionViewWillLeave / ioniViewDidLeave to track the page back/close event
According to https://ionicframework.com/blog/navigating-lifecycle-events/
ionViewWillEnter: It’s fired when entering a page, before it becomes the active one. Use it for tasks you want to do every time you enter in the view (setting event listeners, updating a table, etc.).
ionViewDidEnter: Fired when entering a page, after it becomes the active page. Quite similar to the previous one.
So you can use any of above. I prefer ionViewDidEnter more in this scenario so screen render faster if you call any API.

Enable tap or click events for toggle buttons in ionic in Accessibility

I am working on a mobile application that has a list of items, each of which contain toggle buttons. When the Accessibility (Voice over) mode is turned on, the focus on these list items is enabled but double-tapping the item does not turn ON/OFF the toggle button.
Here's the code sample that I am using. It reads the content but the on-tap or ng-click methods are not triggered.
The below code focuses on the item but when it is double tapped, the toggle does not turn ON/OFF. Same behavior is observed on iOS and Android. Any ideas?
HTML
<ion-list>
<ion-toggle role="option" toggle-class="toggle-balanced" ng-repeat=“item in items" tabindex="-1" ng-model="item.isToggleOn" ng-change=“item.isToggleOn" on-tap=“updateSettings(item)" aria-label=“Item description,, Double Tap to toggle setting." >
<div class="pref-item-text-wrap” >Item description</div>
</ion-toggle>
</ion-list>
In the Controller:
$scope.updateSettings = function (item) {
console.log("In update settings");
}
Heres a little hack to get it working.
In you SASS, after importing Ionic, you need to overwrite the pointer-events property of the toggle component:
// accessible toggles
.item-toggle {
pointer-events: all;
.toggle {
pointer-events: none;
}
}
Please note that this makes the toggle not react to click events unless you handle that event manually on item level, eg:
<ion-toggle role="checkbox" aria-checked="{{isChecked}}" ng-model="isChecked" ng-click="isChecked=!isChecked">Toggle item</ion-toggle>
Events like gestures and keyboard events are intercepted by screen readers. You can use the correct roles to allow the screen reader to pass the appropriate event through to your JavaScript event handlers.
Also, note that when the screen reader is turned on, the gestures change. A single-tap becomes a double-tap on iOS and a double-tap becomes a triple-tap. See http://axslab.com/articles/ios-voiceover-gestures-and-keyboard-commands.php
Similar changes happen on Android.
That being said, you have many things wrong with that little bit of code:
If the tabindex is -1, it will not be focusable for a keyboard-only user and is therefore not accessible by all users. You need to make sure that the tabindex is set to 0
The behavior you are describing is more akin to a checkbox or radio role than it is to an option. You should probably be using the checkbox role.
The parent of an option must be a listbox role as can be clearly seen in the spec http://www.w3.org/TR/wai-aria/roles#option, if you do use listbox in combination with option, you need to set aria-multiselectable to true
In any case, when you implement one of these roles, you must maintain the appropriate aria-* state properties and then you must use a device-independent event handler. You may have to use the ng-click in combination with ngAria to get the required behavior. Make sure that you test with a keyboard only and no screen reader (on Android) and with a keyboard and a screen reader (on iOS and Android) as well as touch and a screen reader (on iOS and Android).

Wicket AjaxLink javascript handler shows strange behaviour

I have a ListView that displays a list of Panels, one below the other. Every panel features a button (implemented via AjaxLink) that closes the panel and removes it from the list.
This is how the ListView is initalized and how the panels are created:
panelsList = new ArrayList<MyPanel>();
pnlContainer = new WebMarkupContainer("pnlContainer");
ListView<MyPanel> pnlItems = new ListView<MyPanel>("pnlItems", panelsList) {
#Override
protected void populateItem(final ListItem<MyPanel> item) {
item.add(item.getModelObject());
item.add(new AjaxLink<Void>("pnlClose") {
#Override
public void onClick(AjaxRequestTarget target) {
panelsList.remove(item.getModelObject());
target.add(pnlContainer); // repaint panel container
}
});
}
};
pnlContainer.setOutputMarkupId(true);
pnlContainer.add(pnlItems);
add(pnlContainer);
This works so far - the actions that trigger adding new panels (usually also AjaxLinks) do what they should and the new panel is added and displayed correctly. But I have problems getting the close button to fully work.
Please see the following steps:
1) I start the server and navigate to the main page. The ListView is initially populated with one panel.
Close-button-code of this panel:
<a wicket:id="pnlClose" id="pnlClose7" href="javascript:;">Close</a>
Searching the page code for pnlClose7 finds the following javascript code that makes the button work as expected:
Wicket.Ajax.ajax({"u":"./?0-1.IBehaviorListener.0-pnlContainer-pnlItems-0-pnlClose","e":"click","c":"pnlClose7"});;
Note: I do not press the button now, if i would, it would work as expected (thoroughly tested).
2) I trigger an action that opens a second panel. The panel is displayed below the first one as expected.
Close-button of the first panel:
<a wicket:id="pnlClose" id="pnlClosef" href="javascript:;">X</i></a>
Close-button of the second panel:
<a wicket:id="pnlClose" id="pnlClose10" href="javascript:;">X</i></a>
But now, neither searching for pnlClosef nor pnlClose10 finds some javascript code. The buttons (both!) do not work. I can still find the javascript code for pnlClose7.
3) I reload the page via pressing F5.
The button IDs change to pnlClose1a and pnlClose1b. Both IDs have javascript counterparts and work.
4) I press the first button (upper panel, ID pnlClose1a). The panel is closed as expected.
The remaining button's ID changes to pnlClose1c, again without a javascript counterpart. Javascript code for pnlClose1a and pnlClose1b is still present.
To make a long story short, the javascript handlers for my AjaxLinks seem to have shyness issues and only appear after I press F5 or reload the whole page in any other manner. I guess thats because repainting the pnlContainer changes the IDs of the current panels - but why is the linked javascript not updated at the same time? Is there anything I can change in my code to update the whole page without completely reloading it?
Wierd thing is that I am pretty sure this worked before... But I checked the whole class history and can't find any major change that would have triggered that. The ListView-code is mainly static since I added it.
I was had similiar problem. if you have any hardcoded javascript code in your page or panels html file (using <script> tag) remove it and set that js code in renderHead of your panel.