2013-07-17 18 views
26

の外側をクリックしたときのdivを非表示にするにはわからない:基本的に私のコードは、ポップアウトするDIV(引き出し)の上AngularJSを使用しているAngularJS input with focus kills ng-repeat filter of listこれは、この質問へのフォローアップの質問であるかのdiv

物事のリストをフィルタリングする権利。ほとんどの場合、これはUIがブロックされているので、そのブロックdivをクリックするとドロワーが閉じられます。しかし、場合によってはUIをブロックせず、検索をキャンセルしたり、ページ上の何かを選択したりするために、ユーザーが引き出しの外側をクリックできるようにする必要があります。

私の最初の考えは、引き出しが開いているときにwindow.onclickハンドラを付けることでした。引き出し以外のものがクリックされた場合、引き出しを閉じなければなりません。それが私が純粋なJavaScriptアプリでやる方法です。しかしAngularでは少し難しいです。ここで

は、私はヨッシーjsBin例@に基づいて、試料とjsfiddleです:このサンプルからコードのhttp://jsfiddle.net/tpeiffer/kDmn8/

関連する作品は以下の通りです。基本的に、ユーザーが引き出しの外側をクリックすると、$ scope.openをfalseに戻すように$ scope.toggleSearchを呼び出します。

コードは機能し、$ 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.openがfalseに設定された後に$ scope。$ 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

大変ありがとうございます。その$ applyはまさに私が行方不明だったものでした!私は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

を防止し、その際

I)は$を呼び出す(適用しようとしているような、他の人々のバージョンでいくつかの厄介なエラーを得ていました$ 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()が2回実行されますので、ボタンは、それの外側に配置されています。

これは簡略化されたバージョンであり、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; 
    } 
}; 
関連する問題