2013-07-17 3 views
26

이이 질문에 대한 후속 질문은 AngularJS input with focus kills ng-repeat filter of list 기본적으로확실하지

내 코드는 팝 아웃하기에 사업부 (서랍) AngularJS와를 사용하고 있습니다 사물 목록을 필터링하는 데 적합합니다. 대부분이 시간은 UI가 차단되어 블로킹 div를 클릭하면 서랍이 닫힙니다. 그러나 경우에 따라 UI를 차단하지 않으므로 사용자가 서랍 외부를 클릭하여 검색을 취소하거나 페이지에서 다른 항목을 선택할 수 있도록해야합니다.

처음에는 서랍이 열리면 window.onclick 처리기를 부착하고 서랍 이외의 다른 것이 클릭되면 서랍을 닫아야한다고 생각했습니다. 이것이 내가 순수한 자바 스크립트 앱에서하는 방법입니다. 그러나 Angular에서는 좀 더 어려워졌습니다. http://jsfiddle.net/tpeiffer/kDmn8/

이 샘플에서 코드의 관련 부분은 다음과 같습니다 : 여기

내가 요시의 jsBin 예 @ 기반으로 샘플과 jsfiddle입니다. 기본적으로 사용자가 서랍 외부를 클릭하면 $ scope.open이 false로 다시 설정되도록 $ scope.toggleSearch를 호출합니다.

코드가 작동하며 $ scope.open이 true에서 false로 변경 되더라도 DOM은 수정되지 않습니다. 나는 이것이 이벤트의 수명주기와 관련이 있거나 아마도 $ scope (별도의 이벤트에서 온 것임)를 복사했을 때 원본이 아닌 복사본이라고 생각합니다.

궁극적 인 목표는 다음과 같습니다. 이것은 궁극적 인 재사용을위한 지침이 될 것입니다. 누구든지 저를 올바른 방향으로 인도 할 수 있다면 감사 할 것입니다. 클릭 이벤트가 다이제스트주기 외부에서 발생하기 때문에

$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입니다.

내가 100 % 행복했다 해결책을 찾을 수 없습니다
+1

@Bertrand 대단히 감사합니다! 그 $ apply는 정확히 제가 누락 된 것입니다! 저는 Angular (전문적으로)를 사용하는 날 5에 있습니다 - 여전히 익숙해지기까지 잠시 시간을 할애 할 핵심 개념! 바라기를 나는 가까운 장래에 부탁을 돌려받을 수 있습니다! JSBin에서 지시문을 확인하고 작업이 완료되면 결과를 게시합니다. –

2

이 내가 사용하는 것입니다 :

<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를 사용하지만 필요에 따라 수행 할 수 있습니다. 이미주기, 내 버전은 I가 제안 전파 및 $에 대한 안전 검사 신청()

12

을 방지 그 때

나는) $ 전화 (적용하려고처럼, 다른 사람들 버전 성가신 오류를 얻고 있었다 $ event.stopPropagation()을 추가하십시오. 클릭 후 바로보기에서 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() 함수를 다시 호출 할 필요가 없으며 double $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; 
    } 
}; 
관련 문제