user1027620
user1027620

Reputation: 2785

Injecting DOM elements AngularJS using Directives

I have a <ul> as such with <li>'s:

    <li ng-repeat="x in xs" ng-class-odd="'x'" ng-class-even="'y'">
    // inject here
        <span>
            {{x.v}}
        </span>
    </li>

I'd like on a certain event to inject a context menu (DOM position described above) that looks like this:

        <ul id="context" class="col">
            <li class="three"><span>1</span></li>
            <li class="three"><span>2</span></li>
            <li class="three"><span>3</span></li>
        </ul>

What's the best way to implement this? 1, 2 and 3 above have the same functions to handle the repeated list items in the parent container. So I'm not sure if injecting the context menu as described above is a smart idea since It would generate unseeded repetitions of the context menu.

Thanks.

Upvotes: 0

Views: 175

Answers (1)

charlietfl
charlietfl

Reputation: 171698

Here's a really basic example of a set of contextmenu directives where menu is inserted once in body.

One directive is used to bind the contenxtmenu event and send data to the directive that controls the menu itself.

The item selected and the mouse position get passed as data in the broadcast

HTML

  <ul>
    <li ng-repeat="item in items" context="item">{{item.title}}</li>
  </ul>

  <ul menu id="context" ng-show="menu_on">
    <li ng-click="itemAlert('id')">Alert ID</li>
    <li ng-click="itemAlert('title')">Alert Title</li>
  </ul>

JS

app.directive('context', function($rootScope) {
  return {
    restrict: 'A',
    scope: {
      item: '=context'
    },
    link: function(scope, elem) {
      elem.bind('contextmenu', function(evt) {
        evt.preventDefault();
        var data = {
          pos: { x: evt.clientX, y: evt.clientY},
          item: scope.item
        }
        scope.$apply(function(){
          $rootScope.$broadcast('menu', data);
        });

      });
    }
  }
})

 app.directive('menu', function($rootScope) {
  return {
    restrict: 'A',
    link: function(scope, elem) {
      scope.$on('menu', function(evt, data) {
        scope.menu_on = true;
        scope.item = data.item;
        var cssObj = {
          left: data.pos.x + 20 + 'px',
          top: data.pos.y - 40 + 'px'
        };
        elem.css(cssObj)
      });
      scope.itemAlert = function(prop) {
        scope.menu_on = false;
        alert(scope.item[prop])
      }
    }
  }
});

Would need some additional document listeners to close menu when user clicks outside of it. Objective here was to just create basic mechanics of being able to display menu and pass data.

I haven't looked but there are probably some open source directives already available that are far more advanced than this.

DEMO

Upvotes: 1

Related Questions