Avoid using $ timeout in Angular UI Modal

In this plunk I have an Angular UI Modal wrapped in a directive. From the controller, I call the method to open the modal code, but for this I need to use $timeout , otherwise the DOM did not finish rendering the directive.

This seems to work, however, what happens if everything that needs to be completed does not end after the expiration of $timeout ? $timeout may work in a development environment, but may not work. Is it wrong to use $timeout ? How to avoid using this in this example?

HTML

 <div modal control="modalCtl"></div> 

Javascript

 var app = angular.module('app', ['ui.bootstrap']); app.controller('myCtl', function($scope,$timeout) { $scope.modalCtl = {}; $timeout(function(){ $scope.modalCtl.openModal(); },100); }) .directive('modal', function ($uibModal) { var directive = {}; directive.restrict = 'EA'; directive.scope = { control: '=' }; directive.link = function (scope, element, attrs) { scope.control = scope.control || {}; scope.control.openModal = function() { scope.modalInstance = $uibModal.open({ template: '<button ng-click="close()">Close</button>', scope: scope }) }; scope.close = function () { scope.modalInstance.close(); }; }; return directive; }); 
+5
source share
3 answers

To avoid using $timeout , the directive can notify the controller when everything is ready. Take a look:

 .directive('modal', function ($uibModal) { var directive = {}; directive.restrict = 'EA'; directive.scope = { control: '=', onReady: '&' // <-- bind `onReady` with `onModalReady` }; directive.link = function (scope, element, attrs) { scope.control = scope.control || {}; scope.control.openModal = function() { scope.modalInstance = $uibModal.open({ template: '<button ng-click="close()">Close</button>', scope: scope }) }; scope.close = function () { scope.modalInstance.close(); }; scope.onReady(); // <-- notify controller }; return directive; }); 

HTML output:

  <div modal on-ready="onModalReady()" control="modalCtl"></div> 

Our controller:

  $scope.onModalReady = function(){ $scope.modalCtl.openModal(); } 

Modified Plunger


About comments @Eduardo La Hoz Miranda

You must be ok with a timeout. I would reduce the time to 0, tho, since timeout will send your call to the end of the event loop.

Usually, when we initialize $timeout with 0 milliseconds or without an argument:

  $timeout(function(){ $scope.modalCtl.openModal(); }); 

We hold $scope.modalCtl.openModal() to run until the next digest ae last in the queue loop. Therefore, in this case, the directory link will work from start to finish and only after you enter $timeout .

The $ timeout may work in the development environment, but may not work.

In the Production section, you have the same code. It should work. I believe the problem is something else. If you are not sure about $timeout , use the above method that I posted.

Recorded plunger

+7
source

When the link to the directive is finished, it can convey a message that it is ready.

And the controller listens to this message and displays the modal when it is received.

code:

 var app = angular.module('app', ['ui.bootstrap']); app.controller('myCtl', function($scope,$timeout) { $scope.modalCtl = {}; $scope.$on("hey", function() { $scope.modalCtl.openModal(); }); }) .directive('modal', function ($uibModal) { var directive = {}; directive.restrict = 'EA'; directive.scope = { control: '=' }; directive.link = function (scope, element, attrs) { scope.control = scope.control || {}; scope.control.openModal = function() { scope.modalInstance = $uibModal.open({ template: '<button ng-click="close()">Close</button>', scope: scope }) }; scope.close = function () { scope.modalInstance.close(); }; scope.$emit("hey"); }; return directive; }); 
+1
source

Using a timeout for any arbitrary expectations when executing code is usually bad. As you indicate in your question, depending on the general context of the page being loaded, you have no guarantee that the directive will be ready at the moment your controller starts up.

You seem to have too many levels of abstraction. A div does something, when it is fully displayed, it shows modal.

Wouldn't it make sense to just have a thing that would show the creation of the div and show the modal?

0
source

Source: https://habr.com/ru/post/1272712/


All Articles