Dismiss Ionic 4 popover from its component - popover

I have a standard Ionic 4 page (Home) that creates a popover that uses a component (BusinessDetails) with a button that redirects to a new page (RequestTurn). However, when I click on that button, the popover is not dismissed and is renders on top of my RequestTurn page. I guess I need to manually dismiss it from the component (BusinessDetails), but I don't know how to access the instance of the popover from there, because it was created in the Home page. Is there a way to do this?
home.page.ts
presentModal(business:Business, event: Event) {
this.popoverController.create(({
component: BusinessDetailsComponent,
cssClass: "business-popover",
showBackdrop: true,
componentProps: {
business: business
}
}) as any).then(popover => popover.present()); }
business-detail.component.ts
goToRequestTurn(id: string) {
//Need to dismiss popver here (?)
this.router.navigateByUrl(`/request-turn/${id}`); }
Thanks for your help.

add private popoverController: PopoverController to the component constructor
then write a function like this and call it when you want to dismiss the modal
async DismissClick() {
await this.popoverController.dismiss();
}

I solved this problem as follows:
In parent component I have passed callback as prop to child component:
const popover = await this.popoverController.create({
component: PopoverComponent,
event: ev,
componentProps: {
onClick: () => {
popover.dismiss();
},
},
});
await popover.present();
And in PopoverComponent I have added #Input() onClick; which called when the user clicks:
...
#Input()
public onClick = () => {}
...
afterClick() {
this.onClick();
}

Related

Nativescript angular : handle android back button on different pages

So I use this function to handle android back button :
this._page.on(Page.loadedEvent, event => {
if (application.android) {
application.android.on(application.AndroidApplication.activityBackPressedEvent, (args:AndroidActivityBackPressedEventData) => {
args.cancel = true;
this._ngZone.run(() => {
this.router.navigate(['/parameters']);
});
});
}
})
on different pages (angular components). So on page1.ts I have navigate(['/parameters]) and on page2.ts I have console.log("test"). Problem is wherever I am in the app, pressing back button always do navigate(['/parameters]), also the console.log if i'm on the right page, but it should do console.log only.
It seems to be global, any idea how to override activityBackPressedEvent ?
activityBackPressedEvent is not specific to a page, it's global to your Activity which holds all the pages. Generally, You will not add more than one event listener to this event.
You could do something like below to handle this on page level, probably in app module / main.ts
application.android.on(application.AndroidApplication.activityBackPressedEvent,
(args: application.AndroidActivityBackPressedEventData) => {
const page = frame.topmost().currentPage;
if (page.hasListeners(application.AndroidApplication.activityBackPressedEvent)) {
args.cancel = true;
page.notify({
eventName: application.AndroidApplication.activityBackPressedEvent,
object: page
});
}
});
With above code, activityBackPressedEvent willl be triggered on every page that has a listener.
Now in your page / component in which you want to customise the behaviour you do this,
// Inject Page
constructor(private page: Page) {
this.page.on(application.AndroidApplication.activityBackPressedEvent, this.onBackButtonTap, this);
}
onBackButtonTap(data: EventData) {
this._ngZone.run(() => {
this.router.navigate(['/parameters']);
});
}
I think since you added the handle back button in the event pageLoaded that's why it does not work on other page.
The code that handle back button should be placed in the app starter. I'm using NS Vue & I place this code in my main.js. I think it could be similar in NS angular.
application.android.on(application.AndroidApplication.activityBackPressedEvent, (args:AndroidActivityBackPressedEventData) => {
args.cancel = true;
this._ngZone.run(() => {
this.router.navigate(['/parameters']);
});
});

How to avoid stacking navigation history in tab-bar states

Tab A - Tab B - Tab C
States like below;
tabs.a, tabs.b, tab.c
I want to close app like there is no navigation history when switching in each of tab states
For example: I was in Tab A then I clicked to Tab B and then I clicked to Tab C from now on if user pushes back button the app should close. In normal behaviour navigation history stacks up and if I push back button I'll go to Tab B from Tab C. How to avoid this behaviour
Below is my codes;
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
.state('tabs.a', {
url: "/a",
views: {
'a-tab': {
templateUrl: "templates/a.html",
controller: 'AController'
}
}
}).state('tabs.b', {
url: "/b",
views: {
'b-tab': {
templateUrl: "templates/b.html",
controller: 'BController'
}
}
}).state('tabs.c', {
url: "/c",
views: {
'c-tab': {
templateUrl: "templates/c.html",
controller: 'CController'
}
}
});
<ion-tabs class="tabs-royal tabs-striped">
<ion-tab title="A" href="#/tab/a">
<ion-nav-view name="a-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="B" href="#/tab/b">
<ion-nav-view name="b-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="C" href="#/tab/c">
<ion-nav-view name="b-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
You can intercept the back button in each of your controllers.
From the documentation:
registerBackButtonAction(callback, priority, [actionId]) Register a
hardware back button action. Only one action will execute when the
back button is clicked, so this method decides which of the registered
back button actions has the highest priority.
For example, if an actionsheet is showing, the back button should
close the actionsheet, but it should not also go back a page view or
close a modal which may be open.
The priorities for the existing back button hooks are as follows:
Return to previous view = 100 Close side menu = 150 Dismiss modal =
200 Close action sheet = 300 Dismiss popup = 400 Dismiss loading
overlay = 500
Your back button action will override each of the above actions whose
priority is less than the priority you provide. For example, an action
assigned a priority of 101 will override the 'return to previous view'
action, but not any of the other actions.
In your controllers you can register a listener for the back button and exit if it has been pressed:
.controller('AController', function($scope, $ionicPlatform){
var deregister = $ionicPlatform.registerBackButtonAction(
function () {
ionic.Platform.exitApp();
}, 100
);
$scope.$on('$destroy', deregister)
})
.controller('BController', function($scope, $ionicPlatform){
var deregister = $ionicPlatform.registerBackButtonAction(
function () {
ionic.Platform.exitApp();
}, 100
);
$scope.$on('$destroy', deregister)
})
.controller('CController', function($scope, $ionicPlatform){
var deregister = $ionicPlatform.registerBackButtonAction(
function () {
ionic.Platform.exitApp();
}, 100
);
$scope.$on('$destroy', deregister)
});
NOTES:
Your last tab (C TAB) should have the name: c-tab:
<ion-tab title="C" href="#/tab/c">
<ion-nav-view name="c-tab"></ion-nav-view>
</ion-tab>
I have done it with a simple way
Added a function in controller scope of tabs state
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html",
controller: function($scope, $ionicTabsDelegate, $ionicHistory) {
$scope.rt = function(e, index) {
$ionicTabsDelegate.select(index);
//e.preventDefault();
$ionicHistory.nextViewOptions({historyRoot:true});
}
}
})
and added ng-click on each ion-tab directive in tabs.html template like below;
<ion-tab ng-click="rt($event, 0)" title="A" href="#/tab/a">
The second parameter of rt function is the index of tab
I used $ionicHistory.nextViewOptions({historyRoot:true});
From the documentation
nextViewOptions()
Sets options for the next view. This method can be
useful to override certain view/transition defaults right before a
view transition happens. For example, the menuClose directive uses
this method internally to ensure an animated view transition does not
happen when a side menu is open, and also sets the next view as the
root of its history stack. After the transition these options are set
back to null.
Available options:
disableAnimate: Do not animate the next transition.
disableBack: The next view should forget its back view, and set it to null.
historyRoot: The next view should become the root view in its history stack.
That way I achieved what I want

Kendo UI droppable drop event not firing

I have a simple application that binds to a view model using Knockout JS. It uses a foreach loop that fires the Knockout afterAdd event when a new item is added to the view model. The result is supposed to be a Kendo draggable that can be dropped on a target. For some reason I can't get the drop event on the target to fire.
JSFiddle
<button data-bind="click: $root.add">Add</button>
Drop target
var ViewModel = function () {
this.operations = ko.observableArray([]);
this.add = function () {
this.operations.push("drag");
}.bind(this);
this.bind = function () {
$(".draggable").kendoDraggable({
hint: function (e) {
$("#console").append("<li>firing hint</li>");
return e.clone();
},
});
$(".droptarget").kendoDropTarget({
drop: function (e) {
$("#console").append("<li>firing drop</li>");
}
});
};
};
ko.applyBindings(new ViewModel());
The problem is that you're instantiating the KendoDropTarget widget multiple times. If I click the Add button in your example kendoDropTarget() is invoked three times. If I add a guard against this (see http://jsfiddle.net/tj_vantoll/rk6qwsy4/1/) the drop event works as expected.

emberjs: how to trigger a custom event in a View

I would like to turn a primitive event (a click) into a semantic event, like "deleteTodo"
This is described here, but not how to implement :(
I have the following code:
App.TodoView = Em.View.extend({
click: function(e) {
this.trigger("deleteTodo");
}
});
App.Router.map(function(match) {
match('/').to('index');
});
App.IndexRoute = Ember.Route.extend({
deleteTodo: function(e) {
// this code is never executed :(
}
}) ;
After I perform the 'click', I see that the TodoView click function is called, but not the deleteTodo function from the IndexRoute. Any suggestions what might go wrong here ?
CHeers
You can use this.get("controller").send("deleteTodo"). This will send a message to the controller, if the controller doesn't handle deleteTodo it will bubble to the router and be handled there.
click: function(e) {
this.get('controller').send("deleteTodo");
}
In your router you will also need to define the event:
events: {
doStuff: function(e) {
alert("Do stuff") ;
}
}
http://jsfiddle.net/9Xasr/7/
I would typically do record deletion in the controller. Seems like putting that in a router event would not be ideal.

Reference a button created in constructor from Controller on Sencha Touch 2?

I've been researching on how to reference methods of a button using MVC on Sencha Touch, but none of the articles has worked fine for me since I declare all my controls on the constructor of my views.
Here is an example of my code:
Ext.define('TPTMOBILE.view.Login',{
extend: 'Ext.Panel',
...
config: {
...
},
constructor: function(){
var submitButton = Ext.create('Ext.Button', {
text: 'Login'
});
}
});
So I'd like to know how to reference the onTap method of my 'submiButton' button.
Thanks in advance.
Your constructor method will not working, try this instead:
constructor: function(config){
this.callParent(config);
this.add(
{
xtype: "button",
text: 'Login',
action: 'doTap'
}
);
}
Your constructor method must contain a call to callParent in order to pass the config object to the parent constructor otherwise it won't work.
After that, you have several ways to achieve your onTap method on the button but since you want to use MVC on Sencha Touch so you can set an action for the button
action: 'doTap'
Then in your controller you can do as following to run your code when tapping on that button:
refs: {
doTap: 'button[action=doTap]'
},
control: {
doTap: {
tap: 'doTap'
},
},
doTap: function() {
alert('doTap function activvated');
}
Hope it helps :)

Resources