ng-blur on a DIV - javascript

I am trying to hide a DIV on blur (the focus has been removed from the DIV). I am using angular and bootstrap. So far I have tried setting "focus" on the DIV when it is shown and then an ng-blur function when the user click anywhere else on the screen. This is not working.
Basically the problem is I cannot set focus on my "#lockerBox" through JS, my "hideLocker" function works no problem when focus is given to my DIV with clicking it.
<div class="lock-icon" ng-click="showLocker(result); $event.stopPropagation();"></div>
<div ng-show="result.displayLocker" id="lockerBox" ng-click="$event.stopPropagation();" ng-blur="hideLocker(result)" tabindex="1">
$scope.displayLocker = false;
$scope.showLocker = function ( result ) {
$scope.displayLocker = !$scope.displayLocker;
node.displayLocker = $scope.displayLocker;
function setFocus() {
angular.element( document.querySelector( '#lockerBox' ) ).addClass('focus');
}
$timeout(setFocus, 100);
};
$scope.hideLocker = function ( node ) {
$scope.displayLocker = false;
node.displayLocker = $scope.displayLocker;
};

Just add tabindex="-1" attr to the div and it gives it the same behave like an input -
<div tabindex="-1" ng-blur="onBlur()"></div>
https://jsfiddle.net/ast12nLf/1/
(Inspired from here - https://stackoverflow.com/a/17042452/831294)

Even I had the same problem - but was able to resolve it using 'mouseup' event on the entire document in a custom directive following is the code,
where I am toggling an accordion contained in a div as pop-up using ng-show()="variable"
now this variable is the key here across menu toggle button HTML Element, div pop up HTML Element, and the custom directive to handle mouse up!
var dummyDirective = angular.module(dummyDirective, []);
dummyDirective.directive('hideOnMouseUpElsewhere', function() {
return {
restrict: 'A',
link: function(scope, element, attr) {
$(document).mouseup(function(e) {
var container = $(element);
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0 && scope.status.menuVisible // ... nor a descendant of the container
&& !(e.target.id === attr.excludeClick)) // do not execute when clicked on this
{
scope.status.menuVisible = false;
scope.$apply();
}
});
}
}
})
where container will have the DOM element you applied 'hideOnMouseUpElsewhere' directive on along with added attribute 'excludeClick' and e.target is the one DOM element where you click
Following is the HTML code for a accrodian bootstrap angular popup menu:
<a id="MenuAnchor" href="" data-toggle="dropdown" class="dropdown-toggle" ng-click="status.menuVisible = !status.menuVisible;">
<i id= "MenuIcon" class="glyphicon glyphicon-cog" style="font-size:20px; color: #428bca; cursor:pointer;"></i>
</a>
<div id ="MenuPane" ng-blur="status.menuVisible=false;" hide-on-mouse-up-elsewhere exclude-click='MenuIcon'>
<div class="btn-group favoritesMenu" style="width: 300px;" ng-show="status.menuVisible" >
<accordion close-others="true">
<accordion-group >
<accordion-heading>....</accordion-heading>
<div ng-click="status.menuVisible=false;">Data</div>
</accordion-group>
</accordion>

I ended up just setting the blur event on the element that has the onclick.

Related

probably event bubbled on wrong element in custom directive

My goal is to flip a simple element on page on mouse click. It works but not on every click. I must click several times in different places across the tile and then the tile flip.
Code is executed as I see in the console, but it looks like click on wrong elements is fired.
I have custom directive with link method:
link: function (scope, element, attrs) {
scope.hideClicked = true;
scope.showClicked = false;
scope.backClicked = function () {
console.log('show front')
scope.hideClicked = false;
scope.showClicked = true;
}
scope.frontClicked = function () {
console.log('hide front');
scope.hideClicked = true;
scope.showClicked = false;
}
console.log(scope, element, attrs);
}
and in the template
<div class="tile" ng-class="{'hide-elem': hideClicked,'show-elem': showClicked }">
<span class="front" ng-click="frontClicked()">{{itemData.value}}</span>
<span class="back" ng-click="backClicked();"></span>
</div>
Full code to reproduct is here: https://codepen.io/lkurylo/pen/Laprjx
Both child-span-Elements use absolute positioning, so it seems as if the browser decides that the second element is displayed "on top" of the first. As a result, the click only registers on the back-Element, which happens to be the top-element.
I suggest you display only one element at any given time, e.g. by adding ng-show or ng-if to both elements.
<span class="front" ng-if="showClicked" ng-click="..."></span>
<span class="back" ng-if="hideClicked" ng-click="..."></span>

How to make a simple menu navigation in angularjs

I'm not really satisfied with what I can find. I just want a simple example of a menu system in Angularjs with hover effect and selection effect.
I understand that 'hover' effects can be done in CSS, but this is more of an exercise for me to understand angularjs better.
What I am trying to do is pretty basic stuff.
Basically I have some HTML which has some DIVs (or menu items) :
<div NavCtrl id="header">
<div class="item" ng-click="click(1)" ng-mouseenter="hoverIn()" ng-mouseleave="hoverOut()">
1
</div>
<div class="item" ng-click="click(2)" ng-mouseenter="hoverIn()" ng-mouseleave="hoverOut()">
2
</div>
<div class="item" ng-click="click(3)" ng-mouseenter="hoverIn()" ng-mouseleave="hoverOut()">
3
</div>
</div>
I want to do two things.
listen on click
listen on mouseIn and mouseOut
I understand..
It is probably nicer to do the hover effect in CSS
It is possible to do some inline logic in the HTML with angularjs
...because I want to have flow on effects from these events. A hover event needs to pull information out related to that menu item, and a click event should also be able to perform some action related to that menu item. Cheap CSS tricks are not going to solve this!
For my hover logic, I thought this would do the trick :
$scope.hoverIn = function($event){
angular.element($event.srcElement).addClass('hover')
};
$scope.hoverOut = function($event){
angular.element($event.srcElement).removeClass('hover')
};
However $event is undefined :( . How do I get to the element object from a mouseover event?
My click logic looks like this :
$scope.click = function(position, $event) {
elem = angular.element($event.srcElement);
if (elem.hasClass("clicked")) {
elem.removeClass("clicked")
}else {
elem.addClass("clicked")
}
// if (position == 1) //do something etc...
};
Same problem : $event is undefined. I also want to pass in the index, so that I can do something special for certain menu items.
My Fiddle is here :
https://jsfiddle.net/zxjg3tpo/5/
ng-mouseenter="hoverIn($event)"
How it works: ng-mouseenter is kinda clever and it has $event in its scope in addition to what you have (i.e. you have hoverIn). So when it parse provided expression, it launches hoverIn with event.
All work with elements, like addClass should be done in directives where you have direct access to html element. Sometimes you may need angular.element(...) but in most cases you are happy with current element. (In directive link : function(scope, element, attrs))
In angularjs you can get the event by using $event in your html code
<div class="item" ng-click="click(1,$event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
Hover Logic
$scope.hoverIn = function($event){
angular.element($event.target).addClass('hover')
};
$scope.hoverOut = function($event){
angular.element($event.target).removeClass('hover')
};
Click logic
$scope.click = function(position, $event) {
elem = angular.element($event.target);
if (elem.hasClass("clicked")) {
elem.removeClass("clicked")
}else {
elem.addClass("clicked")
}
// if (position == 1) //do something etc...
};
Updated Fiddle : https://jsfiddle.net/zxjg3tpo/6/
Here is another updated Fiddle where the siblings have their class removed (to make the click work correct)
https://jsfiddle.net/zxjg3tpo/9/
You missed to pass $event from html and the srcElement was wrong.
Please try the following:
HTML
<body ng-app="navTest" ng-controller="NavTestCtrl">
<div id="header">
<div class="item" ng-click="click(1, $event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
1
</div>
<div class="item" ng-click="click(2, $event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
2
</div>
<div class="item" ng-click="click(3, $event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
3
</div>
</div>
</body>
JS Code:
var app = angular.module('navTest', [
]);
app.controller('NavTestCtrl', function ($scope, $location, $http) {
$scope.click = function(position, $event) {
elem = angular.element($event.target);
if (elem.hasClass("clicked")) {
elem.removeClass("clicked")
}else {
elem.addClass("clicked")
}
// if (position == 1) //do something etc...
};
$scope.hoverIn = function($event){
angular.element($event.target).addClass('hover')
};
$scope.hoverOut = function($event){
angular.element($event.target).removeClass('hover')
};
});

Can Bootstrap popovers not be destroyed?

Is it possible to have a bootstrap (v3) popovers to have it's div loaded right at the start of pageload and not be destroyed when it is being toggled?
I have a popover content in a div:
<div id="popoverContent">
<h1>Stuff</h1>
<p>I'm in a popover!</p>
</div>
And a button that toggles the popover:
<a id="floating_tab" data-toggle="popover" data-placement="left">Button</a>
Here is my Javascript code that handles the button pushes:
<script>
var x = false;
$('[data-toggle=popover]').popover({
content: $('#popoverContent').html(),
html: true
}).click(function() {
if (x) {
$(this).popover('hide');
x = false;
}
else {
$(this).popover('show');
x = true;
}
});
</script>
The thing is, that when $(this).popover('show'); is called, a div is created. Something like this shows up in the inspect element (chrome):
<div class="popover fade left in" role="tooltip" id="popover460185" style="top: 430.5px; left: 2234px; display: block;"><div class="arrow" style="top: 50%;"></div><h3 class="popover-title" style="display: none;"></h3><div class="popover-content">
<h1>Stuff</h1>
<p>I'm in a popover!</p>
</div></div>
But when the button is clicked again, the whole div itself is removed and obliterated from the page.
Is it possible to have the popover div to be created during pageload (hidden though) and can be toggleable without having the div to be deleted?
As stated in the comments, it is not presently possible with Bootstrap 3. The Popover (which is an extension of the Tooltip) is dynamically created on show and detached (using jQuery.detach) from the DOM on hide.
It is probably best to roll your own JavaScript and simply utilize Bootstrap's CSS. However, you could easily patch the functionality using the Popover's event API -the following can be used as a starting place:
$(function () {
var content = $('#popover-content'), // Pre defined popover content.
popover = $('#popover-anchor').popover();
popover.on('inserted.bs.popover', function () {
var instance = $(this).data('bs.popover');
// Replace the popover's content element with the 'content' element
instance.$tip = content;
});
popover.on('shown.bs.popover', function () {
var instance = $(this).data('bs.popover');
// Remove the reference to 'content', so that it is not detached on hide
instance.$tip = null;
});
popover.on('hide.bs.popover', function () {
// Manually hide the popover, since we removed the reference to 'content'
content.removeClass('in');
content.addClass('out');
});
});
Codepen

Focusout with autocomplete

I'm trying to figure out how to direct the focus on these objects to get auto complete to go away when it's not needed.
I'll post the code and then explain what I've tried. The only issue with writing too much is that it scares some people away so I'll be brief yet thorough!
This is the library I'm using http://complete-ly.appspot.com/
jQuery
var autocontainer = link.siblings('.food-input-div');
autocontainer.show();
link.hide();
var autoobj = completely(autocontainer[0]);
autoobj.options = ['chicken', 'cheese', 'chobani', 'chocolate', 'chum', 'cherries', 'coka-cola', 'coconut', 'crack', 'cocain', 'creme brule'];
autoobj.repaint();
autoobj.input.focus();
var wrapper = $(autoobj.wrapper);
console.log(wrapper);
console.log(document.activeElement);
wrapper.attr("tabindex", "0");
wrapper.focusout(function() {
autocontainer.hide();
link.show();
this.remove();
});
The DOM
<td class="left">
<a class="add-food-link">+ Add food</a>
<div class="food-input-div" style="display:none;"></div>
</td>
Complete.ly adds code similar to this directly inside the 'food-input-div' element
<div>
<div>
<input>
<input>
<div>
<div>list item</div>
<div>list item</div>
<div>list item</div>
<div>list item</div>
</div>
</div>
</div>
My jQuery gives the first 'wrapper' element of complelys code a tabindex of 0 so that it is able to having a focus.
The issue is this:
When I click the link:
Link is removed
completely box is rendered
completely wrapper input has focus
When a item from the dropdown is clicked:
Everything is removed and link is rendered
I don't understand why this is happening because focusout is bound to those individual element's parent element.
I toyed around with the assumption that children elements receive focus here and found that is false. http://jsfiddle.net/adiakritos/nU988/
So now I need to get it so that only when ANY element outside of "food-input-div" is clicked, said element and it's children are removed, and the link is redisplayed.
How do I do this?
Playing with this right now:
Use jQuery to hide a DIV when the user clicks outside of it
This is the code I have working nicely right now. Except I still can't click list items.
$(document).mouseup(function (e){
if (!wrapper.is(e.target) && wrapper.has(e.target).length === 0){
autocontainer.hide();
link.show();
autoobj.wrapper.remove();
console.log(e);
};
});
Now when I get click the drop down e.target returns the element directly under the div I'm clicking.
So if I click "cheese" and there's a h4 element that is part of the layout under it, e.target returns that h4 instead of the drop down div list item.
Implementing Dropped.On.Caprica's Code
var showFoodSearch = function(link) {
var autocontainer = link.siblings('.food-input-div');
autocontainer.show();
link.hide();
var autoobj = completely(autocontainer[0]);
autoobj.options = ['chicken', 'cheese', 'chobani', 'chocolate', 'chum', 'cherries', 'coka-cola', 'coconut', 'crack', 'cocain', 'creme brule'];
autoobj.repaint();
autoobj.input.focus();
var wrapper = $(autoobj.wrapper);
wrapper.on('blur', 'input', function(){
autocontainer.hide();
link.show();
autoobj.wrapper.remove();
$(document).mouseup(function(e){
console.log(e.target);
});
});
};
Same exact behavior as described above this try.
This is how I got the JS to work exactly how I wanted it to:
var autocontainer = link.siblings('.autocomplete');
autocontainer.show();
link.hide();
var autoobj = completely(autocontainer[0]);
autoobj.options = ['chicken', 'cheese', 'chobani', 'chocolate', 'chum', 'cherries', 'coka-cola', 'coconut', 'crack', 'cocain', 'creme brule'];
autoobj.repaint();
autoobj.input.focus();
var wrapper = $(autoobj.wrapper);
$(document).click(function() {
var focus = document.activeElement;
if ( focus === document.body ) {
autocontainer.hide();
link.show();
autoobj.wrapper.remove();
}
});
The $(document).click(function() { part checks for any clicks to the main doc element... then it determines what the focus is... if it's on the body (where users normally click to close out of something) it'll hide the drop down.

Jquery click - thinks its the parent element, not the child

When I click on a child element inside a div (the 'butMedWhite ' class) - the jquery thinks that I am clicking on the parent element ('.alternative') - even when I dump 'this' inside the console it says i have clicked on the class 'alternative' (see code below) - not the 'butMedWhite ' class - does anyone have any ideas why?
Here is the html:
<div class="alternative _activeCategory">
<div class="alternative_inner"></div>
<div class="expandable" style="display: block;">
<div class=" criteriaContainer">
<a class="butMedWhite altCreator">add rule</a>
</div>
</div>
</div>
and here is the jquery:
$('.altExpander').on('click', '.alternative', function(e) {
console.log(this);
if(!$(this).hasClass('_activeCategory')){
expandCategory($(this));
}else{
closeCategory();
}
});
Thanks for any help!
jQuery provides as context to your callback the element on which you bound the event handler, just like the native DOM functions.
If you want the clicked element instead, don't use this but e.target :
$('.altExpander').on('click', '.alternative', function(e) {
var clicked = $(e.target);
console.log(clicked);
if(!clicked.hasClass('_activeCategory')){
expandCategory(clicked);
}else{
closeCategory();
}
});
That's because your selector is ".alternative" in this line:
$('.altExpander').on('click', '.alternative', function(e)
If you want this to be the anchor tag, you need to use
$('.altExpander').on('click', '.alternative a', function(e)

Categories

Resources