0

I try to get a width from a $element in directive. but, it continues to return 0.

Can you tell me what is the problem? and, can you tell me the solution?

To see problem, i've created a demo :

  • directive

    angular.module('testApp').directive('testDirective', testDirective)
    function testDirective() {
        return {
            restrict: 'E',
            controller: 'TestController',
            controllerAs: 'vm',
            bindToController: true,
            scope: {}
        }
    }
    
  • controller

    angular.module('testApp').controller('TestController', TestController);
    
    TestController.$inject = ['$element'];
    
    function TestController($element) {
        var vm = this;
    
        init()
    
        function init(){
        vm.elWidth0 = $element.find("div")[0].clientWidth; 
        vm.elWidth1 = $element.find("div")[0].offsetWidth; 
        vm.elWidth2 = $element.prop('clientWidth'); 
        console.log(vm.elWidth0); //return 0
        console.log(vm.elWidth1); //return 0
        console.log(vm.elWidth2); //return 0
        }
    }
    
  • html

    <test-directive>
        <div>
            <button>a</button>
            <button>c</button>
            <button>d</button>
            <button>e</button>
            <button>f</button>
        </div>
    </test-directive>
    

Thank you for your advice

Scott Kim
  • 155
  • 1
  • 2
  • 10
  • The most probable explanation is that the element has not actually rendered yet. You should probably use the `link` / `link.post` function to run your height detection code and even then, you may need to run it in a `$timeout` – Phil Feb 02 '16 at 02:13
  • hi @Phil. What should i do if necessary in a controller. and, Is the '$timeout' way a best practice? – Scott Kim Feb 02 '16 at 07:58

1 Answers1

2

Take a look at this plnkr: http://plnkr.co/edit/3D8kQUukMkXRld9kNYJ1?p=preview

It would appear that you're not getting a proper reference to the elements. Try using querySelector instead:

$element[0].querySelector('button').clientWidth;

UPDATE

The best place to put DOM manipulation in a directive is in the link function(which is actually post-link) because link happens after the directive html has been compiled.

The controller also is created after the directive html has been compiled but it's good to use the controller to separate logic that requires communication with an angular service. There's some really good information on directive link vs. controller here.

Your directive could then look something like this:

function testDirective() {
  return {
    restrict: 'E',
    controller: 'TestController',
    controllerAs: 'vm',
    bindToController: true,
    scope: {}, 
    link: function(scope, element, attrs) {
      scope.elWidth0 = element.find("div")[0].clientWidth; 
      scope.elWidth1 = element.find("div")[0].offsetWidth; 

      console.log(scope.elWidth0);
      console.log(scope.elWidth1);
    }
  }
}
Community
  • 1
  • 1
paul trone
  • 702
  • 5
  • 10