【问题标题】:Add a directive inside a different directive that has link fn在具有链接 fn 的不同指令内添加指令
【发布时间】:2016-09-16 03:33:26
【问题描述】:

我有一个包装纯 JS 库的指令。 我想添加另一个我拥有的指令并将两者结合起来。

目前我有:

指令

app.directive('voPiechart', ['$window', '$compile',
    function ($window, $compile) {
        return {
            restrict: 'E',
            scope: {
                isReady: '=',
                data: '=',
                clickEvent: '='
            },
            link: function ($scope, $elm) {
                var svg = d3.select('#' + $elm[0].id)
                    .append("svg")
                    .append("g");

                svg.append("g")
                    .attr("class", "slices");
                svg.append("g")
                    .attr("class", "labels");
                svg.append("g")
                    .attr("class", "lines");

                /* more directive logic */

                $scope.unselectSlice = function () {
                    $scope.clickEvent(null);
                }
            }
        };
    }
]);

HTML

<vo-piechart id="pie-chart" data="data" is-ready="!isBusy" click-event="sliceSelected" />

现在,我想添加一个名为 outside-click 的指令,当我在元素外部单击时它会通知我。在本例中 - d3 创建的 SVG 元素。

我知道向指令添加指令通常应该在 compile 函数中完成,但在这种情况下我不能,因为我需要链接才能继续工作。

我试过了:

svg.attr('on-outside-click', '{{unselectSlice()');
svg.attr('watch-outside-click', 'true');
$compile(svg)($scope);

它不起作用,我似乎在理解指令的工作原理方面遗漏了一些东西。

我查看了其他类似的问题,但无法将它们与我的问题相关联

--> A working plunkr

谢谢

【问题讨论】:

  • 我也在研究如何动态添加 attr-restrict-directive,但没有得到答案。我有兴趣看看你得到什么答案。祝你好运。
  • 当您$compile 时,请使用$scope,因为它应该知道从哪里获取属性或方法。在这种情况下$compile(svg)($scope),尽管这可能不是问题。顺便说一句,我没有看到您为第二条指令提供信息。
  • @Lightfooted 对您认为好的/有趣的问题投赞成票,以便获得更多关注(希望
  • @Bettimms 感谢已编辑,但仍然无法正常工作。
  • 我认为您应该为此使用本机 d3 方法。它自己有一个点击事件。

标签: angularjs svg directive


【解决方案1】:

我最终为每个切片点击事件和整个 svg 点击事件注册并自己处理它(没有附加指令)。

这是一个有效的小提琴:http://jsfiddle.net/Lvc0u55v/4116/

.on('click', function(item, index, alwayzZero) {
    if (selectedThis) {
        d3.select(selectedThis).transition().attr("d", arc);
        selectedThis = null;
        selectedSlice = null;
    }
})

不过,我仍然希望知道原始问题的答案。

【讨论】:

    【解决方案2】:

    这种方法怎么样(我没有删除其余的事件,也许它们不再需要了)

    var myApp = angular.module('myApp', []);
    myApp.controller('myCtrl', ['$scope', '$timeout', function($scope, $timeout) {
        $scope.data = [{
          label: "Neutral",
          value: 20,
          color: "#FF9E3B",
          from: "-0.3",
          to: "0.3",
          name: "-0.3-0.3"
        }, {
          label: "Negative",
          value: 40,
          color: "#FD2626",
          to: "-0.3",
          name: "*--0.3"
        }, {
          label: "Positive",
          value: 10,
          color: "#0DCF71",
          from: "0.3",
          name: "0.3-*"
        }];
    
        $scope.sliceSelected = function(data, index) {
          $timeout(function() {
            $scope.selectedSentiment = data != null ? $scope.data.find(function(item) {
              return item.label == data.label;
            }) : null;
          });
        }
        
        $scope.directiveRunTimes = 0;
        
        $scope.thisDirectiveWorks = function() {
           $scope.directiveRunTimes++;
        }
        
      }])
      .directive('onOutsideClick', function () {
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                var stopProp;
                attr.$observe('watchOutsideClick', function (value) {
                    //console.log("observed: " + value);
                    if (attr.onOutsideClick && attr.watchOutsideClick && scope.$eval(attr.watchOutsideClick)) {
                        $(document).bind('click', function(event) 
                        {
                          if(event.target.nodeName === "path") {
                            event.stopPropagation();
                            return false
                          }
                            console.log("Clciked Anywhere");
                            scope.$apply(function() {
                                scope.$eval(attr.onOutsideClick);
                            });
                        });
                        $(element).bind('click', function(event) {
                            //console.log("In-element click");
                            event.stopPropagation();
                        });
                    } else {
                        $(document).unbind('click');
                        $(element).unbind('click');
                    }
                });
            }
        }
    })
      .directive('voPiechart', ['$window', '$compile',
        function($window, $compile) {
          return {
            restrict: 'E',
            scope: {
              isReady: '=',
              data: '=',
              clickEvent: '='
            },
            link: function($scope, $elm) {
              var container = $($elm[0]).parent();
              var data, width, height, radius, svg, pie, arc, outerArc, key, color;
    
              $scope.$watch('isReady', function(newVal) {
                if (newVal) {
                  if (svg) {
                    change(true);
                  } else {
                    setTimeout(function() {
                      createPiechart();
                    }, 100);
                  }
                }
              });
    
              $scope.$watch(function() {
                return $window.outerWidth;
              }, function(newVal, oldVal) {
                if (newVal !== oldVal) {
                  createPiechart();
                }
              });
    
              function createPiechart() {
                duplicateData();
    
                if (svg) {
                  svg.remove();
                  $('#' + $elm[0].id).empty();
                }
    
                updateDimensions();
    
                /****************************** Important code here! ************************************/
    
                svg = d3.select('#' + $elm[0].id)
                  .append("svg")
                  .append("g");
    
                svg.attr('on-outside-click', '{{unselectSlice()');
                svg.attr('watch-outside-click', 'true');
                $compile(svg)($scope);
    
                /****************************** end Important code here! ************************************/ 
    
                svg.append("g")
                  .attr("class", "slices");
    
                pie = d3.layout.pie()
                  .sort(null)
                  .value(function(d) {
                    return d.value;
                  });
    
                arc = d3.svg.arc()
                  .outerRadius(radius * 0.8)
                  .innerRadius(radius * 0.65);
    
                outerArc = d3.svg.arc()
                  .innerRadius(radius * 0.9)
                  .outerRadius(radius * 0.9);
    
                svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
                change(false);
              }
    
              function updateDimensions() {
                if (container.width() > 0) width = container.width();
                if (container.height() > 0) height = container.height();
                if (Math.min(width, height) / 2 > 0) radius = Math.min(width, height) / 2;
              }
    
              function getTotalValues() {
                return data.map(function(item) {
                  return item.value;
                }).reduce(function(prev, current) {
                  return prev + current;
                }, 0);
              }
    
              function duplicateData() {
                data = $scope.data.filter(function(item) {
                  return item.value > 0;
                });
    
                if (data.length == 0) {
                  data.push({
                    label: '$$empty',
                    value: 1,
                    color: '#f7f8f8'
                  })
                }
              }
    
              function change(shouldDuplicateData) {
                if (shouldDuplicateData) {
                  duplicateData();
                }
    
                var totalValues = getTotalValues();
    
                key = function(d) {
                  return d.data.label;
                };
                color = d3.scale.ordinal()
                  .domain(data.map(function(item) {
                    return item.label;
                  }))
                  .range(data.map(function(item) {
                    return item.color;
                  }));
    
                /* ------- PIE SLICES -------*/
                var slice = svg.select(".slices").selectAll("path.slice")
                  .data(pie(data), key);
    
                //watch-outside-click="{{ !rangePicker.startDateCollapse || !rangePicker.endDateCollapse }}" o on-outside-click="rangePicker.startDateCollapse = true; rangePicker.endDateCollapse = true;"
                slice.enter()
                  .insert("path")
                  .style("fill", function(d) {
                    return color(d.data.label);
                  })
                  .attr("class", "slice");
    
                slice.on("click", function(item, index, alwaysZero) {
                  $scope.clickEvent(item.data, index);
                });
    
                slice
                  .transition().duration(1000)
                  .attrTween("d", function(d) {
                    this._current = this._current || d;
                    var interpolate = d3.interpolate(this._current, d);
                    this._current = interpolate(0);
                    return function(t) {
                      return arc(interpolate(t));
                    };
                  });
    
                slice.exit()
                  .remove();
    
                if (data.length == 1 && data[0].label == '$$empty') {
                  var text = svg.select(".labels").selectAll("text")
                    .remove();
                  var polyline = svg.select(".lines").selectAll("polyline")
                    .remove();
                  return;
                }
    
              }
    
              /****************************** Important code here! ************************************/
    
              $scope.unselectSlice = function() {
                console.log('It worked!');
                alert('workssss');
                $scope.clickEvent(null);
              }
              
              /****************************** end Important code here! ************************************/
            }
          };
        }
      ]);
    .pie-chart-container {
            position: absolute;
            top: 5px;
            bottom: 5px;
            left: 5px;
            right: 5px;
    }
    
    .pie-chart-container svg {
                width: 100%;
                height: 100%;
            }
    
    .pie-chart-container path.slice {
                stroke-width: 2px;
            }
    
    .pie-chart-container polyline {
                opacity: .3;
                stroke: black;
                stroke-width: 2px;
                fill: none;
            }
        
    <!DOCTYPE html>
    <html>
    
    <head>
      <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
      <script src="https://code.angularjs.org/1.4.7/angular.min.js"></script>
      <script src="http://d3js.org/d3.v3.js"></script>
      <link rel="stylesheet" href="style.css">
      <script src="script.js"></script>
    </head>
    
    <body ng-app="myApp">
    
      <div class="pie-chart-container" ng-controller="myCtrl">
        <button on-outside-click="thisDirectiveWorks()" watch-outside-click="true"> mooooooooooooooo {{directiveRunTimes}}</button>
        <div>{{selectedSentiment.label}}</div>
        <vo-piechart id="pie-chart" data="data" is-ready="!isBusy" click-event="sliceSelected"></vo-piechart>
      </div>
    </body>
    
    </html>

    【讨论】:

      猜你喜欢
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-23
      • 2015-06-24
      • 1970-01-01
      • 2014-04-02
      相关资源
      最近更新 更多