首页 > 解决方案 > 指令中的重置值

问题描述

我有一个指令:timelineItem通过ng-repeat. 因此,应用程序中可以有 1-100 个(或更多)指令实例。

所有这些时间线项目元素中都有嵌套模板,我想等到ng-includes完成加载然后做一些事情。所以我把一个onload="vm.templateFinishedLoading()"包括在内。

这是被调用的函数:

public templatesFinishedLoading() {
    this.i += 1;
    if (this.i === this.activities.items.length) {
        this.$rootScope.$broadcast('templatesFinishedLoading');
    }
}

由于可以加载多个模板,我不想$broadcast多次调用我放入 for 循环的次数。因此,当所有模板加载完成后,它就会进行广播。

我想在模板加载完成后调用一个函数,以便将$broadCast其捕获在timelineItem指令中。由于指令的每个实例都捕获了$broadcast并且我只想为单击的元素设置动画,因此我必须将 DOM 中单击的 HTML 元素与指令的 HTML 元素进行比较:

element.on('click', () => {
    clickedElement = attr.$$element[0].parentElement;
}

然后在$broadcast我将 clickedElement 与属性元素进行比较:

scope.$on('templatesFinishedLoading', () => {
    if (attr.$$element[0].parentElement === clickedElement) {
        console.log('true');
    }
});

这始终等于 true,因为我只更新clickedElementclicked 指令上的变量。其他实例中的clickedElement变量不会更新,因为它们超出了当前指令的范围。

所以我$broadcast在点击中添加了另一个:

element.on('click', () => {
    $rootScope.$broadcast('resetClickedElement');
    clickedElement = attr.$$element[0].parentElement;
}

然后在同一个指令中我捕捉到广播:

scope.$on('resetClickedElement', () => {
    clickedElement = document.createElement('div');
});

所以现在当我点击具有指令的元素时:

<div class="activity-header" timeline-item>

我首先将重置广播到指令的所有其他实例,以将clickedElementdiv 元素更改为空。然后我将当前点击的元素设置为 clickedElement 变量。所以现在当模板完成加载指令的所有实例时if (attr.$$element[0].parentElement === clickedElement),只有单击的指令才会正确clickedElement,因为所有其他指令都是空的。

所以现在我的问题。是否有其他方法可以“重置”clickedElement每个指令实例中的变量?

标签: angularjs

解决方案


我对你的建议是你实现这样的东西:

<div ng-app="app">
  <div ng-repeat="item in [].constructor(10) track by $index">
    <div timeline-item></div>
  </div>
</div>

在您的应用程序中:

angular.module('app', [])
.controller('timelineController', TimelineController)
.directive('timelineItem', TimelineItem)
.factory('timelineService', TimelineService);

function TimelineController ($scope, $element, timelineService) {
    timelineService.updateLoadedItems();

    if (timelineService.isLoadFinished()) {
        console.log('finished load the directives');
    }

}

TimelineController.$inject = ['$scope', '$element', 'timelineService'];

function TimelineItem (timelineService) {
    return {
        template: '<div> timeline item {{selectedItem}}</div>',
        link: function (scope, element, attrs) {
            element.on('click', function () {
                scope.$apply(function () {
                    timelineService.setClickedElement(element);
                });
            });

            scope.$watch(function() {
              return timelineService.getClickedElement();
            }, function () {
                scope.selectedItem = timelineService.getClickedElement() === element;
            });
        },
        controller: TimelineController
      }
}

TimelineItem.$inject = ['timelineService'];

function TimelineService () {
  var loadedAllItems = false;
  var clickedElement = null;
  var itemsLength = 10;
  var loadedItems = 0;

  return {
    getClickedElement: function () {
        return clickedElement;
    },

    setClickedElement: function (element) {
        clickedElement = element;
    },

    resetClickedElement: function () {
        clickedElement = null;
    },

    isLoadFinished: function () {
        return loadedAllItems;
    },
    updateLoadedItems: function () {
      loadedItems++;
      loadedAllItems = loadedItems == itemsLength;
    }
  }
}

这样做你不需要你的广播,并且会产生同样的效果。


推荐阅读