【问题标题】:How to trigger an angular change from a non-angular context e.g. from a D3 event?如何从非角度上下文触发角度变化,例如来自 D3 事件?
【发布时间】:2017-05-30 12:09:52
【问题描述】:

我正在使用 AngularJS 1.6.x 并使用ng-repeat 构建一个表,如下所示。但是,现在我需要根据一些动态布尔条件显示一个新列,即isDynamicVisible:

<table>
    <thead>
    <tr>
        <th id="name">Name</th>
        <th id="mean">Mean</th>
        <th ng-if="isDynamicVisible">Dynamic</th>
    </tr>
    </thead>
    <tbody>
    <tr ng-repeat="data in displayedPathStatistics" ng-class="{selected: (histogramData.selected === data.name)}"
        ng-click="selectPathOutputRow(data.name)">
        <td>{{data.displayName}}</td>
        <td>{{data.Mean}}</td>
        <td ng-if="isDynamicVisible">{{dynamicVal}}</td>
    </tr>
    </tbody>
</table>

在控制器端:

constructor(private $window: IWindowService, private $rootScope: IRootScopeService, private $scope:IReportCtrlScope, private $location:ng.ILocationService, private remoteServices: RemoteServices) {
    $scope.isDynamicVisible = false;

    // ...
    objects.selectAll(".dot")
    .data(data)
    .enter().append("circle")
    .classed("dot", true)
    .attr("r", function (d) {
            return 6 * Math.sqrt(2.0 / Math.PI);
    })
    .attr("transform", transform)
    .style("fill", colorVal)
    .on("mouseover", function(d) {
        $scope.isDynamicVisible = true;
        return tip.show(d);
    })
    .on("mouseout", function(d) {
        $scope.isDynamicVisible = false;
        return tip.hide(d);
    });

问题是条件在开始时只评估一次,在构造表时,以后无论isDynamicVisible范围变量发生变化,它都会保持最初的状态。我也尝试过使用ng-show,但没有成功。

更新:当用户将鼠标悬停在 D3 JS 散点图的数据点上时,控制器会更改 isDynamicVisible

【问题讨论】:

  • isDynamicVisible 是布尔值还是函数?
  • 你能在.on()之前添加东西吗?
  • 有点无关紧要,但没关系。我已经测试过那里的代码可以正确执行等等。
  • 避免使用jquery,并使用ng-mouseoverng-mouseout 指令。

标签: javascript angularjs d3.js


【解决方案1】:

您的问题是由 angularjs 中更改检测的工作方式引起的。当您将代码绑定到 Angular 事件以外的其他东西时,Angular 不会意识到您更新了某些属性,并且不会触发他的 $digest 循环,该循环会更新视图

您需要在模板中使用指令ngMouseOver

<div ng-mouseover="isDynamicVisible = true" ng-mouseout="isDynamicVisible = false">
   some html element
</div>

如果,这个 div 超出了你的控制器(这不应该发生)你应该使用

.on("mouseout", function(d) {
    $timeout(function () {
        $scope.isDynamicVisible = false;
    }
    return tip.hide(d);
});

【讨论】:

  • 那么,您应该使用 $timeout() 而不是 $scope.$apply() 以避免在您的应用程序中并发 $apply。
  • 顺便说一句,我想你应该看看这个:stackoverflow.com/questions/14994391/…
【解决方案2】:

如果您的侦听器是从非角度上下文(即从 D3)触发的,您必须将您的 $scope 属性修改包装在 $scope.$apply 调用下:

.on("mouseover", function(d) {
    $scope.$apply(function () {
        $scope.isDynamicVisible = true;
    }
    return tip.show(d);
})
.on("mouseout", function(d) {
    $scope.$apply(function () {
        $scope.isDynamicVisible = false;
    }
    return tip.hide(d);
})

因此,Angular 摘要循环将开始,您的视图将自行更新。

【讨论】:

【解决方案3】:

您可以尝试使用$timeout。它将保证,您将至少拥有另一个摘要循环,因此您不会被强迫使用$apply。从用户的角度来看,不会有任何区别。

.on("mouseover", function(d) {
    $timeout(function() {
      $scope.isDynamicVisible = true;
      return tip.show(d);
    })
})

【讨论】:

    猜你喜欢
    • 2020-07-30
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 2018-06-28
    • 2017-12-03
    • 2015-08-24
    • 1970-01-01
    相关资源
    最近更新 更多