web-dev-qa-db-fra.com

Quand connaissons-nous la largeur réelle d'un élément dans Angular?

Je cherche à créer une directive qui centrera une div.

Jusqu'à présent, j'ai ce code:

app.directive("setcenter", function () {
    return {
        scope:{
            setcenter: '='
        },
        link: function (scope, element, attrs) {

            scope.$watch('setcenter', function (newValue) {
                if (newValue == true) {
                    var width = element.width();
                    element.css('position', 'absolute');
                    element.css('top', '80px');
                    element.css('left', '50%');
                    element.css('z-index', '200');
                    element.css('margin-left', '-' + width / 2 + 'px');
                }
            });
        }
    }
});

Le problème est la largeur de l'élément. L'intérêt de cette directive est que la div qui l'utilise n'a pas de largeur définie. Je veux que cette directive détermine la largeur et centre la div. 

Le problème que je rencontre est que lorsque la directive est appelée, la largeur réelle de la div n'est pas encore connue. Lorsque j'utilise ceci dans ma situation, la div est de 800px, mais lorsque le chargement de la page est terminé, la div est de 221px.

Alors, que puis-je faire pour attendre que la largeur réelle soit connue de la div?

27
Martijn

Tout d'abord, je n'ai utilisé cette logique que lorsque j'ai défini une fonction controller pour une fonction directive plutôt qu'une fonction link. Par conséquent, le fait de le définir dans une fonction de lien peut entraîner un comportement différent, mais je vous suggère de l'essayer d'abord et si vous ne pouvez pas le faire fonctionner, passez à l'utilisation d'un contrôleur.

Autant que je sache, le seul changement dont vous auriez besoin pour que cela fonctionne est de changer les appels $ scope to scope et $ element en élément puisque les objets injectés en dépendance deviennent des paramètres standard de fonction de lien.

  $scope.getElementDimensions = function () {
    return { 'h': $element.height(), 'w': $element.width() };
  };

  $scope.$watch($scope.getElementDimensions, function (newValue, oldValue) {
    //<<perform your logic here using newValue.w and set your variables on the scope>>
  }, true);

  $element.bind('resize', function () {
    $scope.$apply();
  });

L'idée de cet usage m'est venue après avoir lu un type d'utilisation très similaire, à savoir regarder la fenêtre $ plutôt que l'élément en cours, le travail original peut être trouvé ici.

Angular.js: définit la hauteur de l'élément lors du chargement de la page

31
James Eby

La réponse de James m'a amené à:

app.directive('measureInto', function () {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                scope.$watch(function() {
                    return element[0].clientWidth;
                }, function(value){
                    scope[attrs.measureInto] = element[0].clientWidth + 10;
                });
            }
        };
    });

Donc, au moment de l'exécution, j'ajoute ceci et assigne à la variable de portée que je veux la largeur de l'élément

7
Michael Burdi

J'ai eu un problème similaire et j'ai constaté que les dimensions étaient correctes de manière fiable lorsque tous les ng-ifs (ou tout ce qui utilise ngAnimate) sur la page avaient été résolus - il est possible que quelque chose de similaire se produise ici. Si oui, cela ferait l'affaire sans ajouter de nouveaux écouteurs:

$scope.tryGetElementDimensions = function () {
    if (!angular.element("your-element") || ((angular.element("your-element")[0].classList).contains("ng-animate")
       $timeout(function() {
           $scope.tryGetElementDimensions()
       })
    }
    else {
        $scope.getElementDimensions()
    } 

$scope.getElementDimensions = function (){
    //whatever you actually wanted to do
}

link: function (scope, element, attrs) {
    $scope.tryGetElementDimensions()
}

Angular ajoute des classes ng-animate et ng-enter, ng-leave pendant son animation et vous pouvez être sûr que c'est terminé lorsque ces classes ont toutes été supprimées. $ timeout sans second argument n'attend que le prochain résumé.

1
strom2357

Vous ne pouvez pas encore commenter, donc cette réponse . Nous avons trouvé une solution similaire à celle proposée par strom2357. $ timeout fonctionne vraiment bien pour vous permettre de savoir quand le dom est prêt, et c'est super simple. J'utilise cette solution pour obtenir la largeur de l'élément ui-view. Je l'ai trouvé dans un violon .

var app = angular.module('app', []);

app.controller('MyController', function($timeout, $scope){

  $timeout(function(){
    //This is where you would get width or height of an element
    alert('DOM ready');
  });

  alert('DOM not ready');

});
1
Jette