繁体   English   中英

AngularJS $ watch仅在初始化时触发

[英]AngularJS $watch only firing on intitialize

我有一个使用d3来显示项目的有角度的应用程序,并且有一个infoPanel来显示单击的项目的信息。 这是有效的,但是单击该项目以激活/打开信息面板不起作用。

在d3数据控制文件中,我有:

'use strict';

var settings ;


angular.module('App')
    .directive('data', ['sessionmgmt', 'thedata', 'gui', function (session, data, gui) {
        return {
            link: function postLink(scope, element, attrs) {

                var promise = angular....getData...;
                promise.then(function () {

                    settings = session.settings;

                    svg = ...

                    createItems(svg, items);
                }, function () {});
            }
        };
  }]);

function createItems(svg, items) {


    let item = svg.append("g")
        .attr("class", "nodes")
        .selectAll(".node")
        .data(items, function (d) {
            return d.id;
        });


    appendIcons(item);

}

function appendIcons(nodes){
  nodes = nodes.enter().append("g")
    .attr("class", "node");

    nodes.append("title")
      .text(function (d) {
          return d.data['label'];
      });

  nodes.on("click",function(d){
    if(settings.selectedItem === d.id){
      settings.selectedItem = null;
    }else{
      settings.selectedItem = d.id;
    }

  });

}

然后在我的infoPanel控制器中,我有:

'use strict';

angular.module('App')
  .controller('ContentpanelCtrl', ['$scope', 'sessionmgmt', function ($scope, sessionmgmt) {
    var contentPanel = this;

    this.settings = sessionmgmt.settings;

    $scope.activate = function activate() {
      contentPanel.settings.contentPanelOpen = true;
    };


    $scope.getSelected = function getSelected(){
      return contentPanel.settings.itemSelected;
    } 

    $scope.isNodeSelected = function isSelected(){
      return contentPanel.settings.itemSelected !== null;
    } 

    $scope.$watch("contentPanel.settings.itemSelected", function(newVal, oldVal) {
      console.log(newVal);
      if (newVal !== oldVal){
        $scope.activate();
      }
    });


  }]);

首次加载页面时,console.log正在运行,但是当我单击这些项目时,不会触发该手表。 我知道“点击”有效,因为getSelected在我的信息面板上显示了正确的数据。 'watch'和getSelected都使用完全相同的设置变量。

有两种方法可以做到这一点。 第一个是我在注释中建议的内容,在该注释中,您将指令的范围作为参数appendIcons给调用scope.$apply();createItemsappendIcons函数scope.$apply(); 在点击事件中。

从指令:

createItems(svg, items, scope);

以及其他功能:

function createItems(svg, items, scope) {

    let item = svg.append("g")
       /* ... */

    appendIcons(item, scope);

}

function appendIcons(nodes, scope){
    nodes = nodes.enter().append("g")
        /* ... */

    nodes.on("click",function(d){
        if(settings.selectedItem === d.id){
            settings.selectedItem = null;
        }else{
            settings.selectedItem = d.id;
        }
        scope.$apply();
    });

}

另一种方法是更改$scope.$watch()函数。 您要注意的contentPanel.settings.itemSelected不在范围内,因为您正在使用this而不是$scope (我假定是controllerAs一部分)。 为了使手表正常工作,您需要使用一个函数作为手表函数中的第一个参数,如下所示:

$scope.$watch(function(){
    return contentPanel.settings.itemSelected;
}, function(newVal, oldVal) {
    if (newVal !== oldVal){
        $scope.activate();
    }
});

也许您可以尝试将确切的对象而不是字符串传递给观察器?

$scope.$watch(function() {
  if (contentPanel && contentPanel.settings) {
    return contentPanel.settings.itemSelected;
  }
}, function(newVal, oldVal) {
  console.log(newVal);
  if (newVal !== oldVal){
    $scope.activate();
  }
});

作为我的评论的补充。

在控制器中:

$scope.toggleSelectedItem = function(item) {
   if(contentPanel.settings.itemSelected && 
      contentPanel.settings.itemSelected === item.id){
     contentPanel.settings.itemSelected = null;
   } 
   else {
     contentPanel.settings.itemSelected = item.id;
   }
}

HTML:

<div ng-repeat="item in items" ng-click="toggleSelectedItem(item)">
   <!--Content-->
</div>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM