2013-07-17 52 views
26

這是一個後續問題這個問題:AngularJS input with focus kills ng-repeat filter of list不知道如何點擊股利之外時,隱藏一個div

基本上我的代碼使用AngularJS彈出出的一個div(抽屜)過濾一系列事物的權利。大多數情況下,這是用來阻止用戶界面的,因此點擊該阻塞格就會關閉抽屜。但在某些情況下,我們不會阻止用戶界面,並且需要允許用戶在抽屜外單擊以取消搜索或在頁面上選擇其他內容。

我最初的想法是在抽屜打開時附加一個window.onclick處理程序,並且如果除抽屜外的任何東西被點擊,它應關閉抽屜。這就是我在純粹的JavaScript應用程序中做到的。但是在Angular中它會更難一些。

這裏是與我基於@ Yoshi的jsBin例的樣品的jsfiddle:http://jsfiddle.net/tpeiffer/kDmn8/

從該樣品有關的代碼如下。基本上,如果用戶點擊抽屜外部,我調用$ scope.toggleSearch,以便$ scope.open設置爲false。

代碼有效,即使$ scope.open從true變爲false,它也不會修改DOM。我確信這與事件的生命週期有關,或者當我修改$範圍(因爲它來自單獨事件)它是一個副本而不是原始的...

最終目標這將是它的最終可重用性指令。如果有人能指出我正確的方向來做到這一點,我將不勝感激。

$scope.toggleSearch = function() { 

    $scope.open = !$scope.open; 

    if ($scope.open) { 
     $scope.$window.onclick = function (event) { 
      closeSearchWhenClickingElsewhere(event, $scope.toggleSearch); 
     }; 
    } else { 
     $scope.$window.onclick = null; 
    } 
}; 

function closeSearchWhenClickingElsewhere(event, callbackOnClose) { 

    var clickedElement = event.target; 
    if (!clickedElement) return; 

    var elementClasses = clickedElement.classList; 
    var clickedOnSearchDrawer = elementClasses.contains('handle-right') 
     || elementClasses.contains('drawer-right') 
     || (clickedElement.parentElement !== null 
      && clickedElement.parentElement.classList.contains('drawer-right')); 
    if (!clickedOnSearchDrawer) { 
     callbackOnClose(); 
    } 

} 

回答

21

抽屜不打烊,因爲點擊事件發生的消化週期外角並不知道$ scope.open已經改變。要修復它,你可以調用$ scope。$ apply.open設置爲false後,$ apply()會觸發摘要循環。

$scope.toggleSearch = function() { 
    $scope.open = !$scope.open; 
    if ($scope.open) { 
     $scope.$window.onclick = function (event) { 
      closeSearchWhenClickingElsewhere(event, $scope.toggleSearch); 
     }; 
    } else { 
     $scope.open = false; 
     $scope.$window.onclick = null; 
     $scope.$apply(); //--> trigger digest cycle and make angular aware. 
    } 
}; 

這是您的Fiddle

我也試圖爲搜索抽屜創建一個指令,如果它有幫助(它需要一些修復:))。這是一個JSBin

+1

非常感謝@Bertrand!那$申請正是我錯過的!我在使用Angular(專業)的第5天 - 仍然需要一段時間來熟悉一些關鍵概念!希望我能在不久的將來回報這份青睞!我將檢查該JSBin的指令,併發布結果,當它完成並工作。 –

2

我無法找到一個解決方案,我很高興的100%,這是我用什麼:

<div class="options"> 
    <span ng-click="toggleAccountMenu($event)">{{ email }}</span> 
    <div ng-show="accountMenu" class="accountMenu"> 
     <a ng-click="go('account')">Account</a> 
     <a ng-click="go('logout')">Log Out</a> 
    </div> 
</div> 

與NG-點擊跨度是用來打開菜單,在div.accountMenu翻轉打開或關閉

$scope.accountMenu = false; 
$scope.toggleAccountMenu = function(e){ 
    if(e) e.stopPropagation(); 
    $scope.accountMenu = !$scope.accountMenu; 
    if ($scope.accountMenu) { 
     $window.onclick = function(e) { 
      var target = $(e.target); 
      if(!target) return; 
      if(!target.hasClass('accountMenu') && !target.is($('.accountMenu').children())){ 
       $scope.toggleAccountMenu(); 
      }    
     }; 
    } else if (!e) { 
     $window.onclick = null; 
     $scope.$apply(); 
    } 
} 

這使用jQuery進行子檢查,但如果需要,您可以不使用它。

我正在與其他國家的人民版本的一些嚴重錯誤,就像試圖調用$適用()它已經在一個週期內,我的版本防止傳播和危害$安全的檢查申請()

12

我建議當添加$ event.stopPropagation();在ng-click之後的視圖中。你不需要使用jQuery。

<button ng-click="toggleSearch();$event.stopPropagation();">toggle</button> 

然後,你可以使用這個簡化的js。

$scope.toggleSearch = function() { 
    $window.onclick = null; 
    $scope.menuOpen = !$scope.menuOpen; 

    if ($scope.model.menuOpen) { 
     $window.onclick = function (event) { 
      $scope.menuOpen = false; 
      $scope.$apply(); 
     }; 
    } 
}; 
3

接受的答案將拋出一個錯誤,如果你點擊按鈕關閉抽屜/彈出,按鈕位於它的外面,因爲$apply()將被執行兩次。

這是一個簡化版本,它不需要再次調用整個toggleSearch()函數並阻止雙重$apply()

$scope.toggleSearch = function() { 

    $scope.open = !$scope.open; 

    if ($scope.open) { 
    $window.onclick = function(event) { 
     var clickedElement = event.target; 
     if (!clickedElement) return; 

     var clickedOnSearchDrawer = elementClasses.contains('handle-right') || elementClasses.contains('drawer-right') || (clickedElement.parentElement !== null && clickedElement.parentElement.classList.contains('drawer-right')); 

     if (!clickedOnSearchDrawer) { 
     $scope.open = !$scope.open; 
     $window.onclick = null; 
     $scope.$apply(); 
     } 
    } 
    } else { 
    $window.onclick = null; 
    } 
}; 
相關問題