ng-click 在指令中不起作用

Posted

技术标签:

【中文标题】ng-click 在指令中不起作用【英文标题】:ng-click not working in directive 【发布时间】:2017-11-14 22:56:45 【问题描述】:

所以我正在开发这个 Angular 应用程序。 我有一个名为 visualization 的控制器和一个名为 force-layout 的指令。

在指令的 html 模板中,我创建了三个按钮,并为它们附加了三个我在指令代码中定义的相应函数:

    <div class="panel smallest controls">
        <span ng-click="centerNetwork()"><i class="fa fa-arrows-alt" aria-hidden="true"></i></span>
        <span ng-click="zoomIn()"><i class="fa fa-search-plus" aria-hidden="true"></i></span>
        <span ng-click="zoomOut()"><i class="fa fa-search-minus" aria-hidden="true"></i></span>
    </div>

    <force-layout ng-if=" config.viewMode == 'individual-force' || config.viewMode == 'individual-concentric' "></force-layout>

函数在指令中定义如下:

    scope.centerNetwork = function() 
      console.log("Recenter");
      var sourceNode = nodes.filter(function(d)  return (d.id == sourceId))[0];
      svg.transition().duration(750).call(zoom.transform, d3.zoomIdentity.translate(width/2-sourceNode.x, height/2-sourceNode.y));
    
    var zoomfactor = 1;
    scope.zoomIn = function() 
      console.log("Zoom In")
      svg.transition().duration(500).call(zoom.scaleBy, zoomfactor + .5);
    
    scope.zoomOut = function() 
      console.log("Zoom Out")
      svg.transition().duration(500).call(zoom.scaleBy, zoomfactor - .25);
    

它不会触发任何错误。 它以前可以工作,但不是,我不明白是什么导致了问题,有什么帮助吗?


更新:完整的指令代码。

'use strict';

/**
 * @ngdoc directive
 * @name redesign2017App.directive:forceLayout
 * @description
 * # forceLayout
 */
angular.module('redesign2017App')
  .directive('forceLayout', function() 
    return 
      template: '<svg  ></svg>',
      restrict: 'E',
      link: function postLink(scope, element, attrs) 
        console.log('drawing network the first time');
        // console.log(scope.data);
        var svg = d3.select(element[0]).select('svg'),
          width = +svg.node().getBoundingClientRect().width,
          height = +svg.node().getBoundingClientRect().height,
          nodes,
          links,
          degreeSize,
          sourceId,
          confidenceMin = scope.config.confidenceMin,
          confidenceMax = scope.config.confidenceMax,
          dateMin = scope.config.dateMin,
          dateMax = scope.config.dateMax,
          complexity = scope.config.networkComplexity;

        var durationTransition = 500;


        // A function to handle click toggling based on neighboring nodes.
        function toggleClick(d, newLinks, selectedElement) 

          // Some code for handling selections cutted out from here

        

        svg.append('rect')
          .attr('width', '100%')
          .attr('height', '100%')
          .attr('fill', 'transparent')
          .on('click', function() 
            // Clear selections on nodes and labels
            d3.selectAll('.node, g.label').classed('selected', false);

            // Restore nodes and links to normal opacity. (see toggleClick() below)
            d3.selectAll('.link')
              .classed('faded', false)

            d3.selectAll('.node')
              .classed('faded', false)

            // Must select g.labels since it selects elements in other part of the interface
            d3.selectAll('g.label')
              .classed('hidden', function(d) 
                return (d.distance < 2) ? false : true;
              );

            // reset group bar
            d3.selectAll('.group').classed('active', false);
            d3.selectAll('.group').classed('unactive', false);

            // update selction and trigger event for other directives
            scope.currentSelection = ;
            scope.$apply(); // no need to trigger events, just apply
          );


        // HERE ARE THE FUNCTIONS I ASKED ABOUT

        // Zooming function translates the size of the svg container.
        function zoomed() 
          container.attr("transform", "translate(" + d3.event.transform.x + ", " + d3.event.transform.y + ") scale(" + d3.event.transform.k + ")");
        
        var zoom = d3.zoom();
        // Call zoom for svg container.
        svg.call(zoom.on('zoom', zoomed)); //.on("dblclick.zoom", null);
        //Functions for zoom and recenter buttons
        scope.centerNetwork = function() 
          console.log("Recenter");
          var sourceNode = nodes.filter(function(d) 
            return (d.id == sourceId) )[0];
          svg.transition().duration(750).call(zoom.transform, d3.zoomIdentity.translate(width / 2 - sourceNode.x, height / 2 - sourceNode.y));
          // svg.transition().duration(750).call(zoom.transform, d3.zoomIdentity);
        
        var zoomfactor = 1;
        scope.zoomIn = function() 
          console.log("Zoom In")
          svg.transition().duration(500).call(zoom.scaleBy, zoomfactor + .5);
        
        scope.zoomOut = function() 
          console.log("Zoom Out")
          svg.transition().duration(500).call(zoom.scaleBy, zoomfactor - .25);
        

        // TILL HERE

        var container = svg.append('g');

        // Toggle for ego networks on click (below).
        var toggle = 0;

        var link = container.append("g")
          .attr("class", "links")
          .selectAll(".link");

        var node = container.append("g")
          .attr("class", "nodes")
          .selectAll(".node");

        var label = container.append("g")
          .attr("class", "labels")
          .selectAll(".label");


        var loading = svg.append("text")
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .attr('x', width / 2)
          .attr('y', height / 2)
          .attr("font-family", "sans-serif")
          .attr("font-size", 10)
          .text("Simulating. One moment please…");

        var t0 = performance.now();

        var json = scope.data;

        // graph = json.data.attributes;
        nodes = json.included;
        links = [];
        json.data.attributes.connections.forEach(function(c)  links.push(c.attributes) );
        sourceId = json.data.attributes.primary_people;

        // d3.select('.legend .size.min').text('j')

        var simulation = d3.forceSimulation(nodes)
          // .velocityDecay(.5)
          .force("link", d3.forceLink(links).id(function(d) 
            return d.id;
          ))
          .force("charge", d3.forceManyBody().strength(-75)) //.distanceMax([500]))
          .force("center", d3.forceCenter(width / 2, height / 2))
          .force("collide", d3.forceCollide().radius(function(d) 
            if (d.id == sourceId) 
              return 26;
             else 
              return 13;
            
          ))
          // .force("x", d3.forceX())
          // .force("y", d3.forceY())
          .stop();

        for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) 
          simulation.tick();
        

        loading.remove();

        var t1 = performance.now();

        console.log("Graph took " + (t1 - t0) + " milliseconds to load.")

        function positionCircle(nodelist, r) 
          var angle = 360 / nodelist.length;
          nodelist.forEach(function(n, i) 
            n.fx = (Math.cos(angle * (i + 1)) * r) + (width / 2);
            n.fy = (Math.sin(angle * (i + 1)) * r) + (height / 2);
          );
        

        function update(confidenceMin, confidenceMax, dateMin, dateMax, complexity, layout) 
          // some code for visualizing a force layout cutted out from here
        

        // Trigger update automatically when the directive code is executed entirely (e.g. at loading)
        update(confidenceMin, confidenceMax, dateMin, dateMax, complexity, 'individual-force');

        // update triggered from the controller
        scope.$on('Update the force layout', function(event, args) 
          console.log('ON: Update the force layout')
          confidenceMin = scope.config.confidenceMin;
          confidenceMax = scope.config.confidenceMax;
          dateMin = scope.config.dateMin;
          dateMax = scope.config.dateMax;
          complexity = scope.config.networkComplexity;
          update(confidenceMin, confidenceMax, dateMin, dateMax, complexity, args.layout);
        );

      
    ;
  );

【问题讨论】:

请添加您的完整指令代码。 “以前工作,现在不行”。因此,文件与以前的版本进行比较。你使用版本控制吗? (如果没有,为什么不呢?)你做备份吗? (如果没有,为什么不呢?)您使用哪个 IDE? (如果没有,为什么不呢?)每次保存代码时,Eclipse 和 Netbeans 都会保留本地历史记录。只需右键单击并选择“与...本地历史比较”,然后将当前版本与上一个版本进行比较,然后再与之前的版本进行比较,等等,直到找到您破坏的内容 哇,你的指令更像是一个控制器而不是一个指令。您的模板显示的是svg,而不是您告诉我们的三个按钮。 感谢您的回复!我们使用版本控制,但我们不了解导致问题的原因。我们是 Angular 的菜鸟,因此指令和控制器可能不遵循最佳实践,对此感到抱歉:) 这三个按钮在我粘贴的上层代码中,它是从控制器模板 HTML 文件中提取的。 嗯,是的。您的代码看起来像你们是大三学生。那么在这种情况下,请阅读使用指令的基础知识并重构您的代码:docs.angularjs.org/guide/directive 【参考方案1】:

所以我想我找到了问题所在。

该指令由&lt;force-layout&gt; 标记调用,该标记显示ng-if='some-condition' 指令。

由于某种原因,在评估控制器代码时,该条件不成立,整个指令,即其 HTML 和 JS,被简单地跳过:ng-click 显然不是能够将点击事件附加到尚不存在的函数。

ng-if 替换为ng-show 解决了这个问题:显然在这种情况下代码会立即执行,并且指令存在隐藏状态,并具有所有声明的属性。

【讨论】:

以上是关于ng-click 在指令中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Angular Ng-click 功能在按钮中不起作用

ng-click 在动态生成的 HTML 中不起作用

ng-click 在 ajax 数据表 + codeigniter 中不起作用

AngularJS指令-使用指令时ng-click不起作用

ng-disable 在 SVG 元素中不起作用

指令在子模块中不起作用