2

Здравствуйте, я боюсь при создании общей директивы подтверждения, основанной на директиве Modal-bootstrap Modal.Угловое преобразование в директиве, содержащей ng-шаблон (generic Confirm Modal)

я не могу найти способ transclude моего содержания в нг-шаблоне, используемый для построения модального, поскольку ng-transclude директивы не оценивается, так как это часть ng-template загружены позже при выполнении $modal.open():

index.html (вставка директивы):

<confirm-popup 
    is-open="openConfirmation" 
    on-confirm="onPopupConfirmed()" 
    on-cancel="onPopupCanceled()" 
> 
Are you sure ? (modal #{{index}}) 

confirmPopup .html (шаблон директивы):

<script type="text/ng-template" id="confirmModalTemplate.html"> 
    <div> 
     <div class="modal-header"> 
      <h3>Confirm ?</h3> 
     </div> 
     <div class="modal-body"> 
      {{directiveTranscludedContent}} // ng-transclude do not work here 
     </div> 
     <div class="modal-footer"> 
      <button class="btn btn-warning" ng-click="cancel()">Cancel</button> 
      <button class="btn btn-primary" ng-click="ok()">Validate</button> 
     </div> 
    </div> 
</script> 

confirmPopup.js (директива JS):

.directive('confirmPopup', [ 
    function() { 
     return { 
      templateUrl: 'confirmPopup.html', 
      restrict: 'EA', 
      replace: true, 
      transclude: true, 
      scope: { 
       isOpen: '=', 
       confirm: "&onConfirm", 
       cancel: "&onCancel" 
      }, 
      controller: ['$scope', '$element', '$modal', '$transclude', '$compile', function($scope, $element, $modal, $transclude, $compile) { 

       // watching isOpen attribute to dispay modal when needed 
       $scope.$watch(
        function() { 
         return $scope.isOpen; 
        }, 
        function(newValue) { 
         if (newValue === true) { 
          openModal(); 
         } else { 
          // if a modal is already dispayed : the modal must be canceled/confirmed by the user 
          // else (if no modal is dispayed), then do nothing 
         } 
        } 
       ); 

       // open modal function 
       // create/register ok/cancel callbacks 
       // and open modal 
       // all on one shot 
       function openModal() { 

        $modal.open({ 
         templateUrl: 'confirmModalTemplate.html', 
         controller: ['$scope', '$modalInstance', 'content', function($scope, $modalInstance, content) { 

          $scope.directiveTranscludedContent = content; 

          $scope.ok = function() { 
           $modalInstance.close(); 
          }; 

          $scope.cancel = function() { 
           $modalInstance.dismiss(); 
          }; 
         }], 
         resolve: { 
          content: function() { 
           return $transclude().html(); 
             //return $compile($transclude().contents())($scope); 
          }, 
         } 
        }) 
        .result.then(
         // modal has been validated 
         function() { 
          $scope.confirm(); 
         }, 
         // modal has been dismissed 
         function() { 
          if ($scope.cancel) { 
           $scope.cancel(); 
          } 
         } 
        ); 
       }; 
      }] 
     }; 
    } 
]); 

Если это не достаточно ясно, увидеть эту PLUNKER где я жду, чтобы увидеть "Are you sure ? (modal #2) «только при нажатии на кнопку« open confirm modal #2 ».

ответ

2

ui-bootstrap modal поддерживает только template или templateUrl в качестве способа указания содержимого. Однако содержимое извлекается, оно скомпилировано и связано с предоставленной областью $modal (а точнее, внутренней службой $modalStack).

Итак, по крайней мере, так нет возможности обеспечить переход.

Одним из способов было бы включить директиву-заполнителем, которая добавила бы переведенную DOM, но преобразованная DOM, поскольку она исходит из местоположения, отличного от модального, должна быть передана каким-то образом этой директиве-заполнителю. У вас уже есть content в качестве введенного параметра разрешения. Я буду использовать это с небольшими изменениями - я передам фактический DOM, а не разобранный HTML.

Таким образом, на высоком уровне:

.directive("confirmPopupTransclude", function($parse){ 
    return { 
    link: function(scope, element, attrs){ 
     // could have been done with "=" and isolate scope, 
     // but avoids an unnecessary $watch 
     var templateAttr = attrs.confirmPopupTransclude; 
     var actualTemplateDOM = $parse(templateAttr)(scope); 

     element.append(actualTemplateDOM); 
    } 
    }; 
}) 

И, в функции openModal (опуская несвязанные свойства):

function openModal{ 
    $modal.open({ 
    controller: function($scope, content){ 
     $scope.template = content; 
     // etc... 
    }, 
    resolve: { 
     content: function(){ 
     var transcludedContent; 
     $transclude(function(clone){ 
      transcludedContent = clone; 
     }); 
     return transcludedContent; // actual linked DOM 
     }, 
    // etc... 
} 

Наконец, в самом шаблоне для модального:

<div class="modal-body"> 
    <div confirm-popup-transclude="template"></div> 
</div> 

Your forked plunker

+0

Огромное спасибо за ваш ответ. Это прекрасно и хорошо объяснено. –

+0

Bonus-optionnal вопрос, но это скорее «обзор кода». Есть ли лучший способ открыть модальный, чем использовать наблюдателя в директиве (и область isOpen var в контроллере)? –

+0

@ Cétia, попробуйте сделать это в ответ на щелчок по директиве - если вы намереваетесь, чтобы это была кнопка –