2
votes

I have an AngularJS application with Angular-UI Modal. I'd like to retrieve a DOM element defined inside the modal HTML from the controller, but it returned undefined.

I uploaded my code in Plunker (http://plnkr.co/edit/eoOuJiVaYASH1jMO8t2q?p=preview).

In the ModalInstanceCtrl controller if I tried to retrieve the element myElem defined in the modal template it gave me an undefined exception as below but works well if I commented var elem = $document.getElementById('myElem');.

TypeError: undefined is not a function
    at new  (http://run.plnkr.co/K8SndGsk5DANhGl2/:36:28)
    at invoke (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:3918:17)
    at Object.instantiate (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:3929:23)
    at http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:7216:28
    at resolveSuccess (http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.10.0/ui-bootstrap-tpls.js:1710:32)
    at wrappedCallback (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:11498:81)
    at http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:11584:26
    at Scope.$eval (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:12608:28)
    at Scope.$digest (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:12420:31)
    at Scope.$apply (http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js:12712:24)

Did anything I miss in the code below?

Thanks,

3
You shouldn't be accessing DOM elements in the controller. If you need to access DOM elements you should be using directives, either something built in or a custom directive. Describe more generally what you're trying to achieve. - shaunhusain
blog.nebithi.com/angularjs-dos-and-donts <== see here or the AngularJS Best Practices video on YouTube from Misko for some easy to follow rules while you're just learning the ropes. Doing DOM manipulation in controllers is a cardinal sin, either you or some other future developer will hate you for picking up this habit and not learning how to do this appropriately. - shaunhusain
From the link you provided, accessing DOM from controller is a bad thing because in theory controller should never know DOM. But I would like to know why the code below failed. It looks like the controller was invoked before the DOM was created. - Shaun Xu
There are actually lots of reasons that doing DOM manipulation in controllers is bad. 1 makes it so you can't test the controller independent of the view, 2 isn't clear with regard to what things are manipulating the view from the perspective of the HTML, 3 makes it so your controller can't be easily re-used with alternative views, really the list goes on. The solution to sharing data between controllers is using a service or a factory. - shaunhusain

3 Answers

6
votes

As you said the DOM was constructed after the controller was executed.Try injecting $timeout into the modal controller and set $timeout to 0.

6
votes
$scope.openModal = function () {
  var modal = $modal.open({
    animation: false,
    templateUrl: 'app/modules/demo/modal.html',
    controller: 'MyModalCtrl',
    resolve: {
      vm: function () {
        return 'id';
      }
    }
  });
  modal.rendered.then(function () {
     //process your logic for DOM element
     console.info(document.getElementById('elementIdInModalTemplate');
  });
1
votes

Actually it should be

var elem = document.getElementById('myElem');

instead of

var elem = $document.getElementById('myElem');

Remove the $ sign. It will open up the modal window.