You need to make a context menu in the form of the directive AngularJS. So far I have done this:
<span class="myelem" dd-ctx-menu="menuobj">Π’Π΅ΡΡΠΎΠ²ΡΠΉ ΡΠ»Π΅ΠΌΠ΅Π½Ρ</span> Where menuobj is an object with a list of required fields in the context menu, well, ddCtxMenu is a directive. In the directive itself, for the time being, I do everything "manually", that is, I create the element var menu = angular.element('<div class="ctxmenu"></div>'); , then in the cycle I fill it, put the handlers and display it on the screen. Everything works, but I was told there is a more correct way.
Interested in how to use the directive template to do so in advance to write the context menu construction and the framework would do the work for me to fill it.
For example, a template for a start:
<div class="ctxmenu"> <span ng-repeat="elem in menulist">{{elem}}</span> </div> As I read in the documentation and made sure in practice, if you specify a template directive through templateUrl: 'template.html' , then it will overwrite the element in accordance with the template, and I need this template to be activated by click to create the menu. I still donβt know the framework and I donβt express my thoughts clearly, but I hope you understand me.
Directive code:
(function(angular) { 'use strict'; angular.module('ctxMenuModule', []) .directive('ddCtxMenu', ['$document', function($document) { return { // ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡ Ρ Π½Π°ΡΡΡΠΎΠΉΠΊΠ°ΠΌΠΈ ΠΌΠ΅Π½Ρ scope: { menuobj: '=ddCtxMenu' }, link: function(scope, element, attr) { // ΠΎΠ±ΡΠ΅ΠΊΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΈΠΊΠ°ΠΌΠΈ ΠΈ Π΄Π»Ρ isEnabled() var state = {}; //ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΌΠ΅Π½Ρ ΠΈ Π½Π°Π²Π΅ΡΠΈΠ²Π°Π΅ΠΌ Π²Π½ΡΡΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ function createCtxMenu(menuobj) { var menu = angular.element('<div class="ctxmenu"></div>'); for (let prop in menuobj) { let itemobj = menuobj[prop]; let item = angular.element('<div>' + itemobj.name + '</div>'); if (itemobj.isEnabled(state)) { item.addClass('ctxmenuitem'); item.on('click', function() { console.log('44'); itemobj.handler(element, state); }) //Π΅ΡΠ»ΠΈ Π΅ΡΡΡ ΠΏΠΎΠ΄ΠΌΠ΅Π½Ρ if (itemobj.submenu) { var submenu = createCtxMenu(itemobj.submenu); menu.submenu = submenu; item.on('mouseover', function(e) { e.stopPropagation(); var rect = item[0].getBoundingClientRect(); $document.find('body').append(submenu); //ΡΠΌΠ΅ΡΠ°Π΅ΠΌ ΠΌΠ΅Π½Ρ. submenu.css({ top: rect.top + 'px', left: rect.right + 'px' }); }); item.on('mouseout', function(e) { var rt = e.relatedTarget ? e.relatedTarget : e.toElement; if (submenu[0] != rt && submenu[0] != rt.parentNode) { submenu.removeAll(); } }); } } else { item.addClass('ctxmenudisabled'); } menu.append(item); } //ΡΠ΄Π°Π»ΡΠ΅ΠΌ ΠΌΠ΅Π½Ρ ΠΈ Π²ΡΠ΅ ΠΏΠΎΠ΄ΠΌΠ΅Π½Ρ ΡΠ΅ΠΊΡΡΡΠΈΠ²Π½ΠΎ menu.removeAll = function() { menu.submenu ? menu.submenu.removeAll() : 0; menu.remove(); } menu.on('mouseover', function() { menu.submenu ? menu.submenu.removeAll() : 0; }); return menu; } //ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°Π΅ΠΌ ΠΏΡΠ°Π²ΡΠΉ ΠΊΠ»ΠΈΠΊ Π½Π° ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ΅ element.on('contextmenu', function(event) { event.preventDefault(); event.stopPropagation(); // ΡΠ΄Π°Π»ΡΠ΅ΠΌ ΡΠ΅ΠΊΡΡΠ΅Π΅ ΠΌΠ΅Π½Ρ var tmp = angular.element(document.querySelectorAll('.ctxmenu')); tmp.length ? tmp.remove() : 0; //ΡΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΠΎΠ΅ var ctxMenu = createCtxMenu(scope.menuobj); $document.find('body').append(ctxMenu); //ΡΡΠ°Π²ΠΈΠΌ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΊΠ»ΠΈΠΊΠΎΠ² var removeMenu = function() { ctxMenu.removeAll(); $document.off('click', removeMenu); $document.off('contextmenu', removeMenu); } $document.on('click', removeMenu); $document.on('contextmenu', removeMenu); //ΡΠΌΠ΅ΡΠ°Π΅ΠΌ ΠΌΠ΅Π½Ρ. ctxMenu.css({ top: event.pageY + 'px', left: event.pageX + 'px' }); }); } }; } ]); })(window.angular); The menuobj itself is an array of objects of the form:
$scope.menuobj = [ { name: 'Π£Π΄Π°Π»ΠΈΡΡ', handler: function(element, state) { element.remove(); }, isEnabled: function(state) { return true; } }, ...];