1

I am working on a workaround using position: absolute that needs the position of a div to be calculated.

<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>

It works fine for static partials like this:

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

but for dynamic partials that have ng-if or ng-show it won't work because the calculated positions will change after rendering.

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

If I can intercept ng-if and ng-show to do the following: ng-if, code to reposition then I can make it work. I was thinking about writing a new directive say ng-hack-if that would do the same.

Here is the codepen. Just toggle the directive's ng-show from true to false. When it is true everything works, reposition works fine. But when it is false, reposition thinks there is a div but Angular removes it in its the evaluation cycle. I simply need to call the moveContainerAccordingToHolder when AngularJS does a DOM modification i.e calls ng-show in this case.

Nishant
  • 20,354
  • 18
  • 69
  • 101

5 Answers5

2

You can delay the executing of the function until DOM has finished rendering by using the setTimeOut function.

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
    };
}]);

This works for ng-show="false" as well.

Dilushika Weerawardhana
  • 1,441
  • 1
  • 12
  • 16
1

You can try with the ngStyle directive of AngularJS. It helps you to dynamically change the CSS of any element. Check this link.

Nishant
  • 20,354
  • 18
  • 69
  • 101
biswajit-rout
  • 377
  • 2
  • 11
  • `ngStyle` is a good direction to think though I don't know if it solves manual DOM manipulation problems. – Nishant May 25 '18 at 05:57
1

Please check this answer,

I made a toggle function and made a variable show to display and hide the div and I called moveContainerAccordingToHolder inside that function.

I added a click to toggle button, please click that button

Here is your directive:

    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

Sravan
  • 18,467
  • 3
  • 30
  • 54
0

Do it in a directive way. And from the directive you will create, put the logic there.

Nishant
  • 20,354
  • 18
  • 69
  • 101
Lawrence Paje
  • 339
  • 3
  • 4
0

The option of over-riding the directive's parent's $scope.$apply and $scope.$digest from within the directive's link function is also nice. This way, any change to the partial would trigger the repositioning which is what I wanted.

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;
};
Nishant
  • 20,354
  • 18
  • 69
  • 101