package
package

Reputation: 4801

Best (most efficient) way to show dynamic options menu in angularjs

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:

  1. 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>

  2. 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

Answers (2)

jszobody
jszobody

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:

http://jsfiddle.net/qxF3A/3/

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

charlietfl
charlietfl

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

Related Questions