在 ng-if、ng-show 等发生在 AngularJS 之后,我该如何做一些动作?

How do I do some action after ng-if, ng-show etc happens in AngularJS?

我正在使用 position: absolute 处理 workaround,需要计算 div 的位置。

<html>
  <!-- this iframe will positioned by an angular partial through a directive -->
  <iframe style="position: absolute; width: 400px; height: 400px";></iframe>
  <div id="angular"></div>
<html>

它适用于像这样的静态部分:

<div id="dummy" style="width: 400px; height: 400px;"></div>
<reposition></reposition>

但对于具有 ng-ifng-show 的动态部分,它将不起作用,因为计算的位置将在渲染后发生变化。

<div ng-if="variable" style="width: 200px; height: 200px"></div>
<div id="dummy" style="width: 400px; height: 400px;"></div>
<reposition></reposition>

如果我可以拦截 ng-ifng-show 来执行以下操作:ng-ifcode to reposition 那么我就可以让它工作。我在考虑写一个新指令说 ng-hack-if 会做同样的事情。

这里是codepen。只需将指令的 ng-showtrue 切换为 false。当它是 true 时一切正常,reposition 工作正常。但是当它是 false 时,reposition 认为有一个 div 但 Angular 在其评估周期中将其删除。我只需要在 AngularJS 进行 DOM 修改时调用 moveContainerAccordingToHolder,即在这种情况下调用 ng-show

您可以尝试使用 AngularJSngStyle 指令。它可以帮助您动态更改任何元素的 CSS。检查这个 link.

以指令的方式进行。从您将创建的指令中,将逻辑放在那里。

请检查这个答案,

我制作了一个切换函数并制作了一个 variable show 来显示和隐藏 div 并且我在该函数中调用了 moveContainerAccordingToHolder

我添加了一个click to toggle按钮,请点击那个button

这是你的指令:

    directiveTemplate = `
    <div id="directive">
        <span ng-click="toggleShow()"> Click to Toggle </span>
        <div id="pre" style="width: 102.4px; height: 35.9px" ng-show="show">
            Pre
        </div>
        <div id="holder" style="width: 102.4px; height: 76.8px; border:1pt dashed gray;">
        </div>
        <div id="post" width="102.4">
            Post
        </div>
    </div>`;

    // Integration Begins

    function moveContainerAccordingToHolder(holder) {
        var reposition = document.getElementById('reposition');
        reposition.style.border = "1pt solid green";
        reposition.style.position = "absolute";
        var holderTop = holder.getBoundingClientRect().top;
        var holderLeft = holder.getBoundingClientRect().left;
        var scrollTop = document.documentElement.scrollTop;
        var scrollLeft = document.documentElement.scrollLeft;
        holderTop = holderTop + scrollTop + 1;
        holderLeft = holderLeft + scrollLeft + 1;
        holderTop = String(holderTop) + "px";
        holderLeft = String(holderLeft) + "px";
        reposition.style.top = holderTop;
        reposition.style.left = holderLeft;
        reposition.style.display = "block";
    }

    // Integration Ends

    // Angular Begins

    (function(angular) {
        'use strict';
        var module1 = angular.module('module', []);
        module1.controller('Controller', ['$scope', function($scope) {

        }]);
        module1.directive('reposition', [function() {
            return {
                restrict: 'E',
                replace: true,
                link: function(scope, element, attrs) {
                    scope.show = true;
                    var holder = angular.element(
                        document.getElementById("holder")
                    )[0];
                    window.moveContainerAccordingToHolder(holder);
                    scope.toggleShow = function(){
                      scope.show = !scope.show
                      window.moveContainerAccordingToHolder(holder);

                    }
                },
                template: directiveTemplate
            };
        }]);
    })(window.angular);

// Angular Ends

Here is a DEMO for the same

您可以延迟函数的执行,直到 DOM 使用 setTimeOut 函数完成渲染。

module1.directive('reposition', [function() {
    return {
        restrict: 'E',
        replace: true,
        link: function(scope, element, attrs) {
            var holder = angular.element(
                document.getElementById("holder")
            )[0];
            setTimeout(function() {
              window.moveContainerAccordingToHolder(holder);
            },0);
        },
        template: directiveTemplate
    };
}]);

这也适用于 ng-show="false"。

指令的 link 函数中的 over-riding 指令的父项 $scope.$apply$scope.$digest 的选项也很好。这样,对局部的任何更改都会触发重新定位,这正是我想要的。

var parentApply = scope.$parent.$apply;
var parentDigest = scope.$parent.$digest;
scope.$parent.$apply = function() {
    console.log("Apply was called");
    var r = parentApply.call(scope.$parent);
    moveContainerAccordingToHolder(holder);
    return r;
};
scope.$parent.$digest = function() {
    console.log("Digest was called");
    var r = parentDigest.call(scope.$parent);
    moveContainerAccordingToHolder(holder);
    return r;
};