Reputation: 4801
Let's say we have many items in the UI. When a user clicks an item, the UI should present a popup/dialiog/overlay element with some options, actions and etc.
Currently I see two options:
Duplicate the overlay element for each item and hide it until associated item is clicked. Like in this fiddle: http://jsfiddle.net/urPww/1/
<div ng-show="currentItem">
showing options for: {{currentItem.name}}
</div>
<li ng-repeat="item in items" ng-click="showOptions(item)">
{{item.name}}
</li>
Place overlay UI once and keep track wich item was clicked last. Demo: http://jsfiddle.net/aVnPT/5/
<li ng-repeat="item in items" ng-click="showOptions(item)">
{{item.name}}
<span ng-show="item.showingOptions">
<br/>showing options for: {{item.name}}
</span>
</li>
The first solution is not efficient. Yet I can't figure out a clean way how to show overlay UI besides the clicked element in second one. Any ideas?
Upvotes: 6
Views: 2697
Reputation: 28949
Option 2 could work with a directive that dynamically places the options overlay alongside the clicked element using dom manipulation (see @charlietfl's answer). You end up with simpler HTML, but much more complicated js/angular code.
However I think option 1 is the right idea, and can just be cleaned up a bit. You can get rid of the directive, and have a controller method as simple as:
$scope.showOptions = function(item) {
$scope.currentItem = item;
}
See here:
I'll gladly add some (minimal) duplication in my view/template if it greatly simplifies my controllers and avoids the need for a custom directive.
Upvotes: 0
Reputation: 171690
You can use a single element by passing in $event
as param to your ng-click
function. Then can get position of mouse click relative to document
app.directive('container', function () {
var offset = {
left: 40,
top: -20
}
return function (scope, element, attributes) {
var $oLay = angular.element(document.getElementById('overlay'))
scope.showOptions = function (item,$event) {
var overlayDisplay;
if (scope.currentItem === item) {
scope.currentItem = null;
overlayDisplay='none'
}else{
scope.currentItem = item;
overlayDisplay='block'
}
var overLayCSS = {
left: $event.clientX + offset.left + 'px',
top: $event.clientY + offset.top + 'px',
display: overlayDisplay
}
$oLay.css(overLayCSS)
}
}
});
Am not sure if angular normalizes clientX
and clientY
the way jQuery does for different browsers. Not all browsers use same convention for event position properties Have removed ng-show
from overlay element so it's style attributes can be controlled from directive, not by angular compiler due to timing, and given it an id.
DEMO: http://jsfiddle.net/jJyTf/
Upvotes: 2