2

Live Demo

I created a confirmationDialogHeader directive which is used like so:

<ul>
  <li ng-repeat="item in items">
    {{item}}
    <button class="btn btn-mini" 
            confirmation-dialog-header="Delete Item" 
            confirmation-dialog-action="deleteItem($index)">
      Delete
    </button>
  </li> 
</ul>

When the button is clicked, it is supposed to open a confirmation dialog, and if user confirms, it should call deleteItem($index), and close the dialog.

My problem is with the last bit: closing the dialog.

Here is the controller (CoffeeScript):

app.controller 'AppCtrl', ['$scope', '$q', '$timeout', ($scope, $q, $timeout) ->
  $scope.items = ['Item 1', 'Item 2'] 
  $scope.deleteItem = (index) ->                         
    deferred = $q.defer()
    $timeout ->
      $scope.items.splice(index, 1)   # All good if this line is removed
      deferred.resolve()
    , 1000
    deferred.promise
]

and here is the directive:

app.directive 'confirmationDialogHeader', ['$compile', '$q', ($compile, $q) ->
  restrict: 'A'
  scope:
    confirmationDialogAction: '@'
  controller: ($scope) ->
    $scope.onConfirm = ->
      $scope.$parent.$eval($scope.confirmationDialogAction).then ->
        $scope.confirmationDialog = off   # Why this doesn't close the dialog?
  link: (scope, element, attrs) -> 
    $confirmationDialog = $ """
      <div modal="confirmationDialog">
        <div class="modal-header">
          <h4>#{attrs.confirmationDialogHeader}</h4>
        </div>
        <div class="modal-body">
          Are you sure?
        </div>
        <div class="modal-footer">
          <button class="btn" ng-click="confirmationDialog = false">
            Cancel
          </button>
          <button class="btn" ng-click="onConfirm()">
            Yes
          </button>
        </div>
      </div>
    """

    $(document.body).append($confirmationDialog)
    $compile($confirmationDialog)(scope)

    $(element).click ->
      scope.$apply ->
        scope.confirmationDialog = yes  

]

As you can see, the dialog is not closed after deleteItem() finishes and $scope.confirmationDialog = off is executed.

The interesting part is that, if $scope.items.splice(index, 1) is wrapped with $timeout, the dialog is closed properly!

$timeout ->
  $scope.items.splice(index, 1)

Why this $timeout wrapping is necessary here?

Are there any guidelines about when should we wrap code with $timeout?


Working version of this directive that uses $dialog.


1 Answer 1

2

Are there any guidelines about when should we wrap code with $timeout?

$timeout is used as a replacement to the native setTimeout. The advantage over the native timeout is that it runs the callback in a try/catch block and any errors occurred will be forwarded to your applications exceptionHandler service.

However from my playing with your demo that is not the issue I am seeing and the code can be simplified.

Update I was hoping to get your specific implementation using modal dialog working, but I didn't have much luck. So implemented it using the $dialog service rather than the modal directive. Maybe it will help - here it is

Also, with your original version I found that the scope was being updated when you clicked yes to close the dialog and it was happening within a digest so it should have fired any watchers and thus close the dialog. In that regard I cannot see a reason why it was not working for whatever reason in my browser it made no difference whether or not timeout was used.

Sign up to request clarification or add additional context in comments.

4 Comments

Code quality aside, this doesn't answer the OP's question. Why does it work with $timeout and not without? I've come across similar issues and sometimes adding the $timeout is necessary.
The demo actually doesn't work for me regardless of using $timeout. The OP asked if there were guidelines for using it - I would say I answered that. There is obviously some rather odd behaviour going on here which I haven't quite worked out.
@DerekEkins: What browser do you use?
I'm on Chrome Version 27.0.1453.110 (Fedora 17)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.