2

We are brand new to AngularJS but are trying to display some html tooltips from a custom directive in Angular and since new new to this technology are struggling to come up with a proper solution to this issue.

We had a version of a solution running using Angular+Web API, but discovered the mouseover events and CRUD functionality belonged in directives instead of the controller, so we're pulling that out and re-building.

Currently in a Plunker POC, we have:

  1. Loaded a very small SVG file.
  2. Loaded a small json data file.
  3. For each SVG element, attached a custom directive hover event
  4. When a particular element is hovered, an alert() executes with the element id.

SVG Sample:

<g id="f3s362c16">
<rect x="577.5" y="533.2" fill="none" width="22.2" height="25.7"/>
<polyline fill="none" stroke="#CEDEED" stroke-width="0.6468" stroke-miterlimit="10" points="590.4,559 577.5,559 577.5,533.2 
    599.5,533.2 599.5,550   "/>
<text transform="matrix(1 0 0 1 590.9561 557.4941)" font-family="arial, sans-serif" font-size="5.1408">362.16</text>

Json sample:

{"Id":1,"empNum":null,"fName":" Bun E.","lName":"Carlos","refacName":null,"deptId":"Drums","divisionId":null,"jobDesc":"Drummer","seatTypeId":1,"officeCode":null,"phone":null,"seatId":"f3s362c12 ","oldSeatId":null,"floor":3,"section":"313 ","seat":"12 "}

we have a scope variable for the json defined in the html file:

{{ **empData** }}

Controller file data load:

 var onLoadComplete = function (response) {
   $scope.**empData** = response.data;
 }

 //error
 var onError = function(reason) {
   $scope.error = "Could not get the data";
 }

 //get data
 $http.get('data.json')
    .then(onLoadComplete, onError);

Directive to load SVG and add directive to cube element

//directive loads SVG into DOM
angular.module('FFPA').directive('svgFloorplan', ['$compile', function ($compile) {
return {
    restrict: 'A',

    templateUrl: 'test.svg',
    link: function (scope, element, attrs) {

        var groups = element[0].querySelectorAll("g[id^='f3']")
        angular.forEach(groups, function (g,key) {
            var cubeElement = angular.element(g);
            //Wrap the cube DOM element as an Angular jqLite element.
            cubeElement.attr("cubehvr", "");
            $compile(cubeElement)(scope);
        })
      }
    }
}]);

Cube Hover Directive:

angular.module("FFPA").directive('cubehvr', ['$compile', function ($compile) {
return {
    restrict: 'A',
    scope: true,
    empData: "=",

    link: function (scope, element, attrs) {

        //id of group 
        scope.elementId = element.attr("id");

        //function call from line 63
        scope.cubeHover = function () {

            //groupId is the id of the element hovered over.
            var groupId = scope.elementId;

            alert(scope.elementId);
            //Here need to get access to scope empdata json to filter and 
            //match to the cube #.
            //IE: If I hover over 362.12, return json data for
            //{"Id":1,"empNum":null,"fName":" Bun E.","lName":"Carlos","refacName":null,"deptId":"Drums","divisionId":null,"jobDesc":"Drummer","seatTypeId":1,"officeCode":null,"phone":null,"seatId":"f3s362c12 ","oldSeatId":null,"floor":3,"section":"313 ","seat":"12 "}
            //since we don't have access to the empData scope variable, cannot run filter.
            var thisData = empData.filter(function (d) {
              return d.seatId.trim() === groupId
            });
            //after we get a match, we need to display a tooltip with save/cancel buttons.


        };
        element.attr("ng-mouseover", "cubeHover()");
        element.removeAttr("cubehvr");
        $compile(element)(scope);
    }
}
}]);

We are getting the alert for the specific cube hover, but I think we need to get access to the page scope variable to do the filter:

var thisData = empData.filter(function (d) {
              return d.seatId.trim() === groupId

});

Once we get a match, I think we should be able to append html to our div tag and display it:

   <div class="tooltip"></div>

Angular:

tooltip.html("Name: " + thisData[0].fName + " " + 
thisData[0].lName  + "<br>Role: " + 
thisData[0].jobDesc + "<br>Extension: " + 
thisData[0].phone)//+ "<br>Avatar: <img src=" + thisData[0].Avatar + ">")
.style("top", (d3.event.pageY + 15) + "px").style("left", (d3.event.pageX + 0) + "px")
.style("visibility", "visible");

At this point, we're not sure how to get the view/page scope variable {{empData}} in the hover (2nd) directive since we're already passing cubeHvr the directive:

angular.module("FFPA").directive('cubehvr', ['$compile', function ($compile)       {...}      

Thanks in advance for any direction you might give us here.

2
  • 1
    I think the easiest way might be to have a service holding empData. Then any other service/component/directive/controller can inject the service and read the latest results. Commented Mar 18, 2017 at 16:46
  • Do you know of an example that we might be able to follow? Thanks Commented Mar 18, 2017 at 18:37

1 Answer 1

1
+50

Define a service as the following code

angular.module('FFPA')
.service('dataService', function () {
    this.getData = function(){
        return $http.get('data.json').then(function(){
             return response.data;
           }, function(){
               return {err:"Could not get the data"};
           }
        );
    }
});

and then inject it to any directive, controller, component or service.

angular.module("FFPA").directive('cubehvr', ['$compile','dataService', function ($compile,dataService) {
return {
    restrict: 'A',
    scope: true,
    link: function (scope, element, attrs) {

        dataService.getData().then(function(data){
            scope.emData=data;
        })
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks.. Needed to add $http to the service function parameter. Question: Since I am now getting the data each time a user hovers over a cube element, do you recommend not getting the data in for all cubes and simply pass a parameter to the web api and get it for each employee on a hover event? Thanks again for your help..
Hi @jazzBox , why not if they won't change .
One additional question please: In the Plunk, we now have a service that gets the data and 2 directives (1 to load SVG. 1 to handle a SVG <g> element hover). Now we have a JS alert that displays the persons name associated to the cube that was hovered over, but need to display a tooltip, which I was thinking of using a page <div>{{emp.name, etc.}}</div> for. If you don't mind, can you tell us the best way to display the hovered data to say a page $scope variable?
you could use services to get or share data among controllers and directives and services , but also you could use rootScope if services aren't easy for now.
Although completely new to Angular, I keep thinking that the hover event that gets the cube data should be called from the controller and set the scope employee data there instead of on the directive...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.