Disable animation on specific view/state in ionic - ionic-framework

I have added a custom "in/out" animation on a state called "browser" with Native Page Transitions using this inside my controller
$scope.$on('$ionicView.beforeEnter', function() {
// animate things on devices
window.plugins.nativepagetransitions.slide(
{"direction":"up"},
function (msg) { // called when the animation has finished
console.log("success: " + msg);
},
function (msg) {
alert("error: " + msg);
}
);
});
$scope.$on('$ionicView.beforeLeave', function() {
// animate things on devices
window.plugins.nativepagetransitions.slide(
{"direction":"down"},
function (msg) { // called when the animation has finished
console.log("success: " + msg);
},
function (msg) {
alert("error: " + msg);
}
);
});
It works...kind of. The default transition (slide left/right) still works given my "slide up" animation a feeling of "slide in diagonal".
Is there a way to prevent the default transition of being triggered?
This is my view
<ion-view >
<ion-nav-bar animation="no-animation">
</ion-nav-bar>
<ion-nav-view animation="no-animation"></ion-nav-view>
<ion-nav-buttons>
<span class="ion-android-close close_browser" ng-click="goBack()"></span>
</ion-nav-buttons>
<ion-nav-title>
<img src="img/logo_header.png">
</ion-nav-title>
<ion-content>
<iframe class="browser" src="{{externalURL}}"></iframe>
</ion-content>
Those animation="no-animation" doesn't work...
ionic: 1.1.1

The solution was to put this before the $state.go()
$ionicHistory.nextViewOptions({
disableAnimate: true
});

Related

How can I disable or change the href on a React-Leaflet v4 Popup close button?

In react-leaflet v4, the Popup component has a default href associated with the close button that directs to #close. Is there a way in React to modify this href or disable the href redirection? It's breaking my react-dom HashRouter.
Of note, Popup.js in Leaflet 1.8 has the following code:
var closeButton = this._closeButton = DomUtil.create('a', prefix + '-close-button', container);
closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399
closeButton.setAttribute('aria-label', 'Close popup');
closeButton.href = '#close';
closeButton.innerHTML = '<span aria-hidden="true">×</span>';
The same issue is also in angular - means it seems to be the leaflet Lib:
// leaflet.js
close: function () {
if (this._map) {
this._map.removeLayer(this);
}
return this;
},
The close function has not even the $event as an argument and the "default" isn't prevented. This leaves us only dirty hacks:
Get the close button after the marker was displayed
Add a click handler more
Add a prefentDefault
yourMethodOpensTheToolTip(marker: Marker) {
if (marker && marker.openPopup) {
marker.openPopup();
// 1. get the close buttons, after the opened the popup
const closeButtons = document.getElementsByClassName('leaflet-popup-close-button');
// 2. add the event handler - if you have more than one, loop here
if (closeButtons && closeButtons.length > 0) {
L.DomEvent.on(closeButtons[0] as HTMLElement, 'click', function(ev){
ev.preventDefault(); // 3. stop it here
});
}
Just for reference the #close button as HTML:
Try something like this. It will probably disable any other hrefs that you may have in the popup though.
document.querySelector('.leaflet-pane.leaflet-popup-pane')!.addEventListener('click', event => {
event.preventDefault();
});
You can utilize useRef hooks and create a click event in the marker
const mapRef = useRef(null);
// event listener to handle marker click
const handleClick = () => {
mapRef.current._popup._closeButton.addEventListener('click', (event) => {
event.preventDefault();
})
};
const map = (<MapContainer center={position} zoom={13} scrollWheelZoom={false} style={{ height: '350px', width: '100%' }} ref={mapRef}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker
position={position}
eventHandlers={{
click: (e) => handleClick(),
}}
>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>)
if you are using GeoJSON you can use onEachFeature props
const onEachCountry = (country, layer) => {
const countryName = country.properties.ADMIN;
layer.on('click', function (e) {
layer
.bindPopup(countryName)
.openPopup()
._popup._closeButton.addEventListener('click', (event) => {
event.preventDefault();
});
});
};
const map = (<MapContainer style={{ height: '300px' }} zoom={1} center={[20, 100]}>
<GeoJSON style={countryStyle} data={mapData.features} onEachFeature={onEachCountry} />
</MapContainer>)
In my React project with react-leaflet v4, I had the same issue and I solved it with the "popupopen" event :
https://leafletjs.com/reference.html#marker-popupopen
<Marker
position={position}
eventHandlers={{
popupopen: (e) => {
e.popup._closeButton.removeAttribute("href");
e.popup._closeButton.style.cursor = "pointer";
}
}}
>
<Popup>
<p>Lorem ipsum dolor sit amet</p>
</Popup>
</Marker>
I hope it will help.
Building on Paul's answer. Here is the solution if you have multiple popups. This will handle the close button click event on all the popups that are open on the leaflet map.
// This is a stopgap till Leaflet fixes its issue with close buttons in popups in Leaflet maps
let popupCloseButtonsHTMLCollection = document.getElementsByClassName('leaflet-popup-close-button');
if(popupCloseButtonsHTMLCollection && popupCloseButtonsHTMLCollection.length > 0){
//convert the popupCloseButtonsHTMLCollection to array
var popupArray = [].slice.call(popupCloseButtonsHTMLCollection);
popupArray.forEach(button =>{
L.DomEvent.on(button as HTMLElement, 'click', function(ev){
ev.preventDefault();
});
});
}

SAILS - How to close modal with ajax-form after receiving "notFound" error from action

So, I am using Sailsjs - and I am using a modal form to confirm deletion of an item. What I want to do is to detect a double deletion (someone deleted an item - while it was in someone else's page - and the second person tries to delete it too).
I managed to do that - my action is returning "notFound".
The problem is - how can I make the Modal close when getting "notFound" back from the action instead of success?
Here is an excerpt of my action code:
exits: {
forbidden: {
description: 'The user making this request is not the owner of this thing and therefore cannot delete it.',
responseType: 'forbidden'
},
notFound: {
description: 'The item was not found in the database. Maybe it has already been deleted?',
responseType: 'notFound'
}
},
fn: async function (inputs, exits) {
var thing = await Thing.findOne({
id: inputs.id
});
if (!thing) {
throw 'notFound';
}
if (thing) {
if (thing.owner !== this.req.me.id ) {
throw 'forbidden';
}
}
await Thing.destroy({ id: inputs.id });
return exits.success();
}
and here is an excerpt of my modal using ajax-form component:
<% /* Confirm DeleteThing Modal */%>
<modal v-if="confirmDeleteThingModalOpen" #close="closeDeleteThingModal()">
<ajax-form action="destroyOneThing" :syncing.sync="syncing" :cloud-error.sync="cloudError" :handle-parsing.sync="handleParsingDeleteThingForm" #submitted="submittedDeleteThingForm()">
<div class="modal-header">
<h3 class="modal-title">Are you sure?</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
You can use #rejected on your ajax-form. So somethinglike:
<ajax-form action="destroyOneThing" #rejected="rejectedDeleteOneThing"
Then tell it what you want it to do on your page script
something like:
rejectedDeleteOneThing: function() {
this.confirmDeleteThingModalVisible = false;
}

Using Protractor: Switch to iframe using browser.switchTo().frame

So I have already written the testing script which:
1) Logs into the application framework, then
2) Clicks menu to launch the app which I am testing ("MyAwesomeApp.html" for this post)
And my main problem is: In navpanel-spec.js below, I want to target the https://server/apps/Default.aspx?r=1 URL, then click within the iframe where MyAwesomeApp is running.
**** ERROR Trying to switch to the iframe this way, but it does NOT work:
browser.switchTo().frame(element(by.id('1')).getWebElement());
Error in cmd prompt:
Started
[15:43:29] E/launcher - No element found using locator: By(css selector, *[id="\31 "])
...
sat-navpanel-spec.js:52:24)
So there are two URLs going on here:
1) https://server/apps/Default.aspx?r=1 (the main app framework with menu system in top nav).
2) https://server/apps/MyAwesomeApp.html (the web app which the test script launches within the <iframe> tag.
The html looks like this, where the application renders within the <iframe> :
<body>
<div id="top">
<!-- top nav menu systems rendered here -->
</div>
<div id="middle">
<div id="m1">
<div id="m2" class="hidden">
<div id="m3">
<div id="right" class="hidden">
<div>
<div id="frame_holder" style="height: 940px;">
<iframe style="width: 100%; height: 100%;" name="1" id="1" src="https://server/apps/MyAwesomeApp.html">
</iframe>
</div>
</div>
</div>
</div>
<div id="left" style="display: none;"></div>
</div>
</div>
</div>
</body>
In my Protractor.config.js file I have a few specs :
specs: [
'spec/login.js',
'spec/launch-awesome-app.js',
'spec/navpanel-spec.js',
'spec/another-spec.js',
'spec/yet-another-spec.js'
]
login.js and launch-awesome-app.js work fine. They log into the menu system, then click thru the menus in order to launch myAwesomeapp - no problem.
MY PROBLEM:
In navpanel-spec.js I want to target the https://server/apps/Default.aspx?r=1 URL, then click within the iframe where MyAwesomeApp is running.
However, it is NOT selecting any of my elements.
If I target https://server/apps/MyAwesomeApp.html in navpanel-spec.js, of course it launches a new browser window and runs the test just fine.
Here's my navpanel-spec.js test spec:
describe('Testing My Awesome App', function () {
var panelObj = new PanelObjects();
var urlDefault = 'https://server/apps/Default.aspx?r=1';
var urlApp = 'https://server/apps/MyAwesomeApp.html';
browser.get(urlApp); // Runs my AwesomeApp tests okay, HOWEVER it launches a new browser window.
browser.get(urlDefault); // Launches app framework with top nav menus and embedded <iframe>,
// HOWEVER I cannot select iframe and successfully run tests here.
beforeEach(function () {
browser.sleep(5000);
browser.waitForAngular();
});
// USE-CASE OBJECT !!
var items = browser.params.useCaseJsonFile["navigatePanels"];
browser.getAllWindowHandles().then(function (handles) {
handles.map(function (win, idx) {
browser.driver.getCurrentUrl().then(function (curr) {
if (curr.indexOf('Default.aspx') >= 0) {
browser.driver.switchTo().window(handles[idx]);
}
});
});
});
browser.switchTo().frame(element(by.id('1')).getWebElement());
var testId = element(by.id('middle'));
console.log(testId);
items.map(function (item) {
if (item.enableTest) {
var specItem = it(item.name, function () {
console.log('------------------------------');
console.log('---- ' + item.describe);
browser.waitForAngular();
// select panels, etc..
panelObj.panelClick(item.panelName).then(function () {
// ...
});
panelObj.getPanelText(item.panelName).then(function (title) {
expect(title).toContain(item.panelTitle);
});
});
}
});
});
UPDATE
var LoginObjects = require('../pageObjects/login-objects.js');
describe('Testing My Awesome App', function () {
var panelObj = new PanelObjects();
var loginObj = new LoginObjects();
//var urlDefault = 'https://server/apps/Default.aspx?r=1';
//browser.get(urlApp); // Runs my AwesomeApp tests okay, HOWEVER it launches a new browser window.
browser.ignoreSynchronization = true;
// LOGIN AND LAUNCH APP !!!
loginObj.Login();
loginObj.Launch();
beforeEach(function () {
browser.sleep(5000);
browser.waitForAngular();
});
// USE-CASE OBJECT !!
var items = browser.params.useCaseJsonFile["navigatePanels"];
// SWITCH TO iframe ELEMENT
loginObj.switchWindowAndFrame();
items.map(function (item) {
if (item.enableTest) {
var specItem = it(item.name, function () {
console.log('------------------------------');
console.log('---- ' + item.describe);
browser.waitForAngular();
// select panels, etc..
panelObj.panelClick(item.panelName).then(function () {
// ...
});
panelObj.getPanelText(item.panelName).then(function (title) {
expect(title).toContain(item.panelTitle);
});
});
}
});
});
and my page objects :
module.exports = function(){
this.Login = function(){
var url = browser.params.loginUrl;
browser.driver.get(url);
browser.sleep(200);
var userName = browser.params.credential.userId;
var password = browser.params.credential.password;
element(by.id('username')).clear().then(function(){
element(by.id('username')).sendKeys(userName);
element(by.id('password')).sendKeys(password);
});
browser.sleep(1000);
var that = this;
var submitElement = element(by.id('bthLogin'));
submitElement.click().then(function () {
browser.getAllWindowHandles().then(function (handles) {
// LOGIN MESSAGE WINDOW
browser.driver.getCurrentUrl().then(function(curr){
if (curr.indexOf('LoginMsg.aspx') >= 0){
// Do we really need to close the login successful browser ???
browser.driver.close();
}
});
browser.driver.switchTo().window(handles[1]);
});
});
},
this.Launch = function(){
var sel = '#TheMenu1 > ul > li:first-child';
var elem = element(by.css(sel));
elem.click().then(function(){
browser.sleep(1000);
var elem2 = element(by.cssContainingText('.rmLink', 'The First Menu Item'));
elem2.click();
// Select menu item; sleep before attempting to click().
var subElem = element(by.cssContainingText('.rmLink', 'My Awesome App'));
browser.sleep(1000);
subElem.click();
browser.waitForAngular();
});
},
this.switchWindowAndFrame = function(){
browser.getAllWindowHandles().then(function (handles) {
handles.map(function(win, idx){
browser.driver.getCurrentUrl().then(function(curr){
if (curr.indexOf('Default.aspx') >= 0){
browser.driver.switchTo().window(handles[idx]);
}
});
});
});
browser.switchTo().frame(element(by.css('[name="1"]')).getWebElement());
}
};
As mentioned in the comments above, protractor has a bug which prefixes '\3' to your id element with number.
The temporary way is to change you locator. :P

ng-click and ngRouting on mobile devices

I am completely new to Angularjs and haven’t been doing any code for ages. I started setting up my website again with Angularjs. I have a main page and an about page, to which the user gets via ngRoute on ng-click (or hitting space). Once on the about page, the user can go back by clicking somewhere on the page and so on.
App.js
var app = angular.module("MyApp", ["ngRoute"]);
app.config(function($locationProvider, $routeProvider) {
$routeProvider
.when("/teaser", {
controller:"teaserCtrl",
templateUrl:'teaser.html'
})
.when("/about", {
controller:"aboutCtrl",
templateUrl: "about.html"
})
.otherwise({
redirectTo:"/teaser"
})
});
app.controller("mainCtrl", function($scope, $http, $location) {
$scope.v = {
inverted: false,
display: true,
offwhite: true,
}
$scope.$on("space", function() {
if ($scope.v.teaser) {
$location.path("/about")
$scope.v.teaser = false
} else {
$location.path("/teaser")
$scope.v.teaser = true
}
$scope.$apply()
})
$scope.goHome = function(){
$scope.$broadcast("goHome")
}
});
app.directive("ngMobileClick", [function () {
return function (scope, clickElement, attrs) {
clickElement.bind("touchstart click", function (e) {
e.preventDefault();
e.stopPropagation();
scope.$apply(attrs["ngMobileClick"]);
});
}
}])
HTML
<body ng-controller="mainCtrl as main" ng-mobile-click="goHome()" ng-class="{inverted: v.inverted, bg: v.offwhite}" space>
<div class="content" ng-view ng-hide="v.display"></div>
//My body code
<script ng-init="sw = 'some website'; id="about.html" type="text/ng-template">
<div class="about">
<p class="text" ng-click="next(); $event.stopPropagation()">
<p>some text</p>
<br>
<a ng-href="{{mail}}" ng-click="$event.stopPropagation()">some address</a>
</p>
</div>
</script>
</body>
The code for the about page is written into a script and it has hyperlinks (ng-href). Now my issue: As you can see, I changed my ng-click to ng-mobile-click for the body-section. If I also change it in the script for the hyperlinks, something weird is happening which I can’t really figure out (links change to hover color, but still no redirection to the ng-href.
For the desktop version, the click is triggering ngRoute, but I can also click the links. For the mobile version this is not possible any more. Any ideas how I can fix this? I know, there is no hovering possible, but somehow I need to detect the hyperlinks also on mobile devices without being redirected to the main-page.
As I said: this is my first try with Angularjs and I haven’t done any code for a while, please be as clear as possible!
There is another controller for teaser/about which I haven’t put here, as well as the directive for the keyup.
Any ideas or suggestions? Thank you so much in advance!

Why is the title not showing on ion-nav-bar?

I have an ion-nav-bar that is hid during login/signin process. After signing in I have tabs on the bottom with the nav bar at the top. The ion-nav-bar can be seen but the title isn't showing anything. What am I doing wrong? Any help would be appreciated.
index.html
<body ng-app="mychat">
<!--
The nav bar that will be updated as we navigate between views.
-->
<ion-nav-bar class="bar-header bar-assertive">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<!--
The views will be rendered in the <ion-nav-view> directive below
Templates are in the /templates folder (but you could also
have templates inline in this html file if you'd like).
-->
<ion-nav-view></ion-nav-view>
</body>
app.js
.config(function($stateProvider, $urlRouterProvider) {
console.log("setting config");
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
// State to represent Login View
.state('login', {
url: "/login",
templateUrl: "templates/login.html",
controller: 'LoginCtrl',
resolve: {
// controller will not be loaded until $waitForAuth resolves
// Auth refers to our $firebaseAuth wrapper in the example above
"currentAuth": ["Auth",
function (Auth) {
// $waitForAuth returns a promise so the resolve waits for it to complete
return Auth.$waitForAuth();
}]
}
})
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html",
resolve: {
// controller will not be loaded until $requireAuth resolves
// Auth refers to our $firebaseAuth wrapper in the example above
"currentAuth": ["Auth",
function (Auth) {
// $requireAuth returns a promise so the resolve waits for it to complete
// If the promise is rejected, it will throw a $stateChangeError (see above)
return Auth.$requireAuth();
}]
}
})
// Each tab has its own nav history stack:
.state('tab.home', {
url: '/home',
views: {
'tab-home': {
templateUrl: 'templates/tab-home.html',
controller: 'HomeCtrl'
}
}
})
.state('tab.movies', {
url: '/movies',
views: {
'tab-movies': {
templateUrl: 'templates/tab-movies.html',
controller: 'MoviesCtrl'
}
}
})
.state('tab.people', {
url: '/people',
views: {
'tab-people': {
templateUrl: 'templates/tab-people.html',
controller: 'PeopleCtrl'
}
}
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/login');
});
tab-home.html
<ion-view title="Home">
<ion-content class="padding">
</ion-content>
</ion-view>
Use "view-title" attribute in tab-home.html
<ion-view view-title="my custom title" >
The most probable cause is the path of your templates not being correct. I have created this JSBin and it works fine with minor tweaks to the path of the login.html template. https://jsbin.com/loluva/1/edit?html,js,console,output
<script id="login.html" type='text/ng-template'>
<ion-view title="Login">
<ion-content class="padding">
</ion-content>
</ion-view>
</script>