Trying to fire a function inside an angular controller after bootstrap modal is dismissed - angularjs

I'm basically trying to figure out how to do a certain event listener within an angular controller. More specifically, when a bootstrap modal is dismissed I would like to fire a function within the angular controller. In jquery you can normally do something like:
$(.some-class).on('click', function() {
// do something
});
What i have is a side navigation with images as buttons. I have gray buttons for when they're inactive and red buttons when they're active. Each button launches a bootstrap modal.
I'm using:
<a type="button" data-toggle="modal" data-target="#overview" ng-click="launchOverview()">
<img ng-src="{{ sideNavActive.overviewSrc }}" /><br />
</a>
and I have an object in my controller:
$scope.sideNavActive = {
"overviewSrc": "img/side-nav/tab-overview-off.png",
"detailsSrc": "img/side-nav/tab-details-off.png",
"contactSrc": "img/side-nav/tab-contact-off.png"
}
When the user clicks one of the side-nav buttons i have an ng-click function that changes the button to "img/...-on.png" so the button turns red (active). When the user clicks another side-nav button it turns that button red and the rest gray.
What I'm trying to do is when the user clicks in the faded area around the modal to dismiss it, i also want the buttons to all reset to gray. According to the bootstrap documentation I should be able to fire a function on the 'hidden.bs.modal' event but I can't get it to work in my angular controller. I have the following function where '#overview' is my id for my modal.
$('#overview').on('hidden.bs.modal', function() {
console.log('function fired!!!!!🔥');
$scope.sideNavActive = {
"overviewSrc": "img/side-nav/tab-overview-off.png",
"detailsSrc": "img/side-nav/tab-details-off.png",
"contactSrc": "img/side-nav/tab-contact-off.png"
}
})
However, this function doesn't fire when the modal is dismissed and I can't figure out why.
One thing I've done to see if the function is actually listening is changed it to:
$('body').on('click', function() {
// function code here
}
and it works. It fires whenever I click anywhere since it's listening on the 'body' element. So I know it's listening but for some reason the 'hidden.bs.modal' event isn't working.

I would use the angular-ui-bootstrap modal if you're not already: http://angular-ui.github.io/bootstrap/#!#modal. There is a callback function on the modal instance that is executed when the modal is dismissed:
modalInstance.result.then(function (someObj) {
// success
}, function () {
// this code will be executed when the modal is dismissed
console.log('Modal dismissed at: ' + new Date());
});

Figured out how to fire a function in an angular controller when modal is dismissed.
angular.element(document).find('.modal').on('hidden.bs.modal', function(){
// do something
console.log('function fired');
});

Related

Ionic popover not hiding second time

I am using Ionic version "1.1.0" and angular version "1.4.3"
I am facing issues with Ionic popover, I have created ionic popover out of html template, popover is opened based on user action, i have two buttons on the popup, and in the button handler i am writing code =>$scope.popover.hide() to close the popover, It works fine for the first time, it closes, Second time again when the popup is opened its not getting closed
need your advice and wanted to know if i am missing something
and on hide method promise, i am doing the state transition, second time when we click on the popover buttons, state transition is happening but popover is not getting closed
below is the code snippet i am using
$ionicPopover.fromTemplateUrl('app/layout/eo-confirmation-popup.html', {
scope: $scope,
backdropClickToClose: false
}).then(function (popover) {
$scope.dataLossPopover = popover;
$scope.dataLossPopover.show(angular.element(document.querySelector('.popupPosition')));
});
and on click of button calling below code
$scope.dataLossPopover.hide().then(function () {
$state.go(...);
});
Thanks,
Mallik
Try something like this
$ionicPopover.fromTemplateUrl('app/layout/eo-confirmation-popup.html', {
scope: $scope,
backdropClickToClose: false
}).then(function (popover) {
$scope.dataLossPopover = popover;
});
$scope.openPopover = function(event) {
$scope.dataLossPopover.show(event)
}
$scope.closePopover = function(event) {
$scope.dataLossPopover.hide(event).then({
$state.go();
})
}
If you are opening popup on click
<button ng-click="openPopover($event)"></button>
<button ng-click="closePopover($event)"></button>

how to make custom directive in angular?

I am trying to make custom directive in angular .I try to add input field in my view when I click on button .In other words I am trying to make one custom directive in which when user press the button it add one input field in the browser .I think it is too easy if I am not use custom directive Mean If I use only controller then I take one array and push item in array when user click on button and button click is present on controller.
But when need to make custom directive where I will write my button click event in controller or directive
here is my code
http://play.ionic.io/app/23ec466dac1d
angular.module('app', ['ionic']).controller('appcontrl',function($scope){
$scope.data=[]
}).directive('inputbutton',function(){
return {
restrict :'E',
scope:{
data:'='
},
template:'<button>Add input</button> <div ng-repeat="d in data"><input type="text"></div>',
link:function(s,e,a){
e.bind('click',function(){
s.data.push({})
})
}
}
})
I just need to add input field when user click on button using custom directive ..could you please tell me where i am doing wrong ?
can we make button template and click event inside the directive
The reason it doesn't work is because your registering your click handler with jQuery. So when the click handler fires it is out of the scope of angular so angular does not know it needs to update its bindings.
So you have two options, the first is to tell angular in the click handler, 'yo buddy, update your bindings'. this is done using $scope.$apply
$apply docs: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply
e.bind('click',function(){
s.$apply(function() {
s.data.push({});
});
});
However angular already has built in directive for handling things like mouse clicks you can just use that and let angular do the work for you. This would be the better option.
so first in your view register a click handler on your button
<button ng-click="add()">Add input</button> <div ng-repeat="d in data"><input type="text"></div>
Then in your link simply add the add() method of your scope
s.add = function () {
s.data.push({});
}
Heres a working fiddle showing both examples. http://jsfiddle.net/3dgdrvkq/
EDIT: Also noticed a slight bug in your initial click handler. You registering a click but not specifying the button to apply it to. So if you clicked anywhere in the directive, not just the button, the handler would fire. You should be more specific when registering events manually, using ids, class names attributes etc.
The e or element property of the link function is a jqlite or full jQuery object of the entire directive. If you have jQuery included before angular it will be a full jQuery object. If not it will a jqlite object. A thinned out version of jQuery.
Here is a basic example for your logic .
var TestApp = angular.module('App', []);
// controller
TestApp.controller('mainCtrl', function mainCtrl($scope) {
$scope.data = [];
$scope.addDataItem = function () {
$scope.data.push({
someFilield: 'some value'
});
console.log('pushing value ... ');
}
});
// view
<div ng-app="App" class="container" ng-controller="mainCtrl">
<button type="button" ng-click="addDataItem()">Add an input</button>
<div ng-repeat="d in data track by $index">
<custom-directive model="d"></custom-directive>
</div>
</div>
// directive
TestApp.directive('customDirective', function customDirective() {
return {
restrict: 'E',
scope: {
model: '='
},
template: 'item -> <input type = "text" />',
link: function (scope, elem, attrs) {
console.log('scope.model', scope.model);
},
controller: function ($scope) {
// do staff here
}
}
});

How can I remove :active from bootstrap button

I have a website, where I have multiple buttons. Once a button is pressed I populate a list, though my problem is that the last pressed button keeps to be looking pressed (has the :active class). I thought about using angular's $timeout to reset the button, though the removeClass function doesn't do the trick.
My view looks like this:
div(ng-controller='productButtonController')
div(ng-repeat='product in products')
div.col-md-4
button.btn.btn-block.sell-button(id='{{product._id}}' ng-click='sell()'){{product.name}}
and my controller:
app.controller('productButtonController', ['$scope', '$timeout', 'productServices', 'flash',
function($scope, $timeout, productServices, flash) {
productServices.getProducts()
.success(function(result) {
$scope.products = result.data
})
.error(showErrorMessage(flash))
$scope.sell = function() {
console.log(this.product)
that = this
$('#' + that.product._id).removeClass('active')
}
}
])
Add the angular $window service to your dependencies for the
controller
Call the blur method on the document's active element, which will be
your button.
$window.document.activeElement.blur();
See How do you clear the focus in javascript?.
This code from Justin Poehnelt's handy GIST solves this elegantly.
app.directive('blur', [function () {
return {
restrict: 'A',
link: function (scope, element) {
element.on('click', function () {
element.blur();
});
}
};
}]);
Add the blur attribute to a button/element you need blurred after click. Eg.
<button type="button" blur>Click me</button>
If you simply want to override the focus status of the bootstrap buttons you could do it with:
.btn:focus{
outline: none;
}
Then your buttons should look like:
<button class="btn btn-default">My button 1</button>
It's also important that the stylesheet which overrides the button status is loaded after the bootstrap stylesheet.
EDIT:
Sorry, but the previous step only removes the outline. The background-color of the button still remains the same.
Since bootstrap doesn't append any active classes to the clicked element as far as i know you need to change the :focus status of the button:
$('#' + that.product._id).blur();
Let me know if this works for you.

Click event gets executed even after window.confirm returns false in angular confirmation dialog

Based on the example given here I have written a directive to display a confirmation dialog in Angular when a button is clicked. The problem is even after the user clicks on the cancel button on the confirmation dialog, the ng-click action gets triggered.
This is the directive:
app.directive('ngConfirmClick',function(){
return {
link: function(scope, element, attr) {
var msg = attr.ngConfirmClick;
var clickAction = attr.ngClick;
attr.ngClick = "";
element.bind('click', function(event) {
if(window.confirm(msg)){
scope.$eval(clickAction);
}
});
}
}
});
This is the section of my index.html that has the ng-confirm-click directives:
<input class="delete" type="button" value="" ng-click="delete(item._id)"
ng-confirm-click="Are you sure you want to delete?">
I tried setting a priority of -1 for the ng-confirm-click directive and that did not help either.
When I was debugging the code on firebug, I found that window.confirm DOES return false when the user clicks on Cancel, so I am not sure why the ng-click (clickAction in the directive code above) is getting executed.
Is there a way to stop propagating the click action if window.confirm returns false?
Any help would be appreciated.

Hide angular-ui tooltip on custom event

I've been looking around and trying out different things but can't figure it out. Is it possible to hide an angular-ui tooltip with a certain event?
What I want to do is to show a tooltip when someone hovers over a div and close it when a users clicks on it because I will show another popup. I tried it with custom trigger events but can't seem to get it working. I made this:
<div ng-app="someApp" ng-controller="MainCtrl" class="likes" tooltip="show favorites" tooltip-trigger="{{{true: 'mouseenter', false: 'hideonclick'}[showTooltip]}}" ng-click="doSomething()">{{likes}}</div>
var app = angular.module('someApp', ['ui.bootstrap']);
app.config(['$tooltipProvider', function($tooltipProvider){
$tooltipProvider.setTriggers({
'mouseenter': 'mouseleave',
'click': 'click',
'focus': 'blur',
'hideonclick': 'click'
});
}]);
app.controller('MainCtrl', function ($scope) {
$scope.showTooltip = true;
$scope.likes = 999;
$scope.doSomething = function(){
//hide the tooltip
$scope.showTooltip = false;
};
})
http://jsfiddle.net/3ywMd/
The tooltip has to close on first click and not the 2nd. Any idea how to close the tooltip if user clicks on div?
I tried #shidhin-cr's suggestion of setting $scope.tt_isOpen = false but it had the rather significant issue that, while the tooltip does fade out, it is still present in the DOM (and handling pointer events!). So even though they can't see it, the tooltip can prevent users from interacting with content that was previously behind the tooltip.
A better way that I found was to simply trigger the event used as tooltip-trigger on the tooltip target. So, for example, if you've got a button that's a tooltip target, and triggers on click...
<button id="myButton"
tooltip="hi"
tooltip-trigger="click">
</button>
Then in your JavaScript, at any point, you can trigger the 'click' event to dismiss your tooltip. Make sure that the tooltip is actually open before you trigger the event.
// ... meanwhile, in JavaScript land, in your custom event handler...
if (angular.element('#myButton').scope().tt_isOpen) {
angular.element('#myButton').trigger('click');
}
Since this triggers the actual internals of AngularUI's Tooltip directive, you don't have the nasty side-effects of the previous solution.
Basically you cannot play with the tooltip-trigger to make this work. After digging through the ToolTip directive code, I found that the ToolTip attribute exposes a scope attribute called tt_isOpen.
So in your ng-click function, if you set this attribute to false, that will make the tooltip hide.
See the updated demo here
http://jsfiddle.net/3ywMd/10/
Like this
app.controller('MainCtrl', function ($scope) {
$scope.likes = 999;
$scope.doSomething = function(){
//hide the tooltip
$scope.tt_isOpen = false;
};
})
Michael's solution got me 90% of the way there but when I executed the code, angular responded with "$digest already in progress". I simply wrapped the trigger in a timeout. Probably not the best solution, but required minimal code
// ... meanwhile, in JavaScript land, in your custom event handler...
if (angular.element('#myButton').scope().tt_isOpen) {
$timeout( function(){
angular.element('#myButton').trigger('click');
}, 100);
}
For future reference, the accepted answer angular.element('.yourTooltip').scope().tt_isOpen will not work in new versions as tooltip has been made unobservable. Therefore, the entire tootlip is removed from DOM. Simple solution is to just check if tooltip is present in DOM or not.
Borrowing from #liteflier's answer,
// ... meanwhile, in JavaScript land, in your custom event handler...
if (angular.element('.yourTooltip').length) { //if element is present in DOM
setTimeout( function(){
//Trigger click on tooltip container
angular.element('.yourTooltipParent').trigger('click');
}, 100);
}

Resources