AngularJS + JQuery : angularjs에서 동적 콘텐츠를 작동시키는 방법


84

jQuery와 AngularJS를 모두 사용하는 Ajax 앱에서 작업 중입니다.

jQuery의 html함수를 사용하여 div의 콘텐츠 (AngularJS 바인딩 포함)를 업데이트 할 때 AngularJS 바인딩이 작동하지 않습니다.

다음은 내가하려는 코드입니다.

$(document).ready(function() {
  $("#refreshButton").click(function() {
    $("#dynamicContent").html("<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: {{count}} </span>")
  });
});
</style><script src="http://docs.angularjs.org/angular-1.0.1.min.js"></script><style>.ng-invalid {
  border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="">
  <div id='dynamicContent'>
    <button ng-click="count = count + 1" ng-init="count=0">
        Increment
      </button>
    <span>count: {{count}} </span>
  </div>


  <button id='refreshButton'>
    Refresh
  </button>
</div>

ID가있는 div 내부에 동적 콘텐츠 #dynamicContent가 있고 새로 고침을 클릭하면이 div의 콘텐츠를 업데이트하는 새로 고침 버튼이 있습니다. 콘텐츠를 새로 고치지 않으면 Increment가 예상대로 작동하지만 새로 고치면 AngularJS 바인딩이 작동을 멈 춥니 다.

이것은 AngularJS에서 유효하지 않을 수 있지만 처음에는 jQuery로 애플리케이션을 빌드하고 나중에 AngularJS를 사용하기 시작했기 때문에 모든 것을 AngularJS로 마이그레이션 할 수 없습니다. AngularJS에서이 작업을 수행하는 데 도움을 주시면 대단히 감사하겠습니다.


1
이 기능에 JQuery를 사용하는 특별한 이유가 있습니까? <이이기 때문에 친절하고 쉽게 각도에 의해 덮여 jsfiddle.net/pkozlowski_opensource/YCrFD/2 >
— pkozlowski.opensource

3
이것은 문제를 보여주는 실제 사용 사례의 단순화 된 버전입니다. 실제 애플리케이션에서 동적 콘텐츠는 html로 jquery에 전달되는 grails taglib에 의해 생성됩니다. 그래서 나는 grails taglib의 모든 로직을 angularjs로 포팅하여 순수한 angularjs로 만들 수 없습니다.
— Raja

1
@ pkozlowski.opensource, 그 링크가 죽었습니까? 또한 outdoors.stackexchange.com에 가입해야합니다. :)
— Liam

답변:


115

$compileangular가 바인딩을 수행 할 수 있도록 DOM에 삽입하기 전에 HTML 문자열 을 호출해야합니다 .

바이올린에서는 다음과 같이 보일 것입니다.

$("#dynamicContent").html(
  $compile(
    "<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: {{count}} </span>"
  )(scope)
);

물론, $compile이 작업을 수행하려면 컨트롤러에 주입해야합니다.

$compile문서 에서 더 많은 것을 읽으십시오 .


2
감사합니다 Noah, 컨트롤러 메서드에서 수행하고 해당 컨트롤러 메서드를 버튼의 클릭 이벤트에 직접 바인딩하면 컴파일이 작동합니다. 다음은 작업 예 입니다. 하지만 실제 앱에서는 다른 jquery 함수에서 컨트롤러 메서드를 호출해야했습니다. 그래서 범위 개체에 대한 참조를 잡고 작동하지 않는 다시 컴파일하기 위해 refresh 메서드를 호출했습니다. 여기에 예가 있습니다. 이 예제가 작동하도록 도와 줄 수 있습니까?
— Raja

1
@Raja 각도 프레임 워크 외부에서 각도 메서드 / 표현식을 호출 할 때 $ scope. $ apply () 를 호출 하여 예외 처리, 감시 실행 등의 적절한 범위 수명주기를 수행해야합니다. jsfiddle.net/fABdD/14
— Artem Andreev

1
@ArtemAndreev 정확히 맞습니다. @Raja 아키텍처에 적합한 경우 함수 자체 $scope.$apply()로 호출을 이동할 수도 있습니다 refresh(). jsfiddle.net/nfreitas/8xkeh/1
— Noah Freitas

3
angular-1.0.1.min.js원래 예제 의 링크 는 404입니다. 다음은 @ ArtemAndreev-s 예제의 업데이트 된 작업 버전입니다. jsfiddle.net/pmorch/fABdD/186 및 @NoahFreitas 예제 : jsfiddle.net/pmorch/8xkeh/43
— Peter V. Mørch

1
$ compile을 사용하고 컨트롤러 내에서 DOM을 조작하면 테스트 할 수없는 코드를 갖게됩니다. 컨트롤러가 아닌 DOM을 변경하기 위해 지시문을 사용해야합니다.
— Enzey

57

동적 콘텐츠를 제어 할 수없는 경우를위한 또 다른 솔루션

이것은 지시문을 통해 요소를로드하지 않은 경우 작동합니다 (예 : 주석 처리 된 jsfiddles의 예제에서와 같이).

콘텐츠 정리

JQuery를 사용하는 경우 선택할 수 있도록 콘텐츠를 div로 래핑합니다 . 요소를 얻기 위해 네이티브 자바 스크립트를 사용하도록 선택할 수도 있습니다.

<div class="selector">
    <grid-filter columnname="LastNameFirstName" gridname="HomeGrid"></grid-filter>
</div>

Angular Injector 사용

$ compile에 대한 참조가없는 경우 다음 코드를 사용하여 얻을 수 있습니다.

$(".selector").each(function () {
    var content = $(this);
    angular.element(document).injector().invoke(function($compile) {
        var scope = angular.element(content).scope();
        $compile(content)(scope);
    });
});

요약

원래 게시물은 $ compile 참조가 편리하다고 가정 한 것 같습니다. 참고 문헌이 있으면 분명히 쉽지만 나는 그렇지 않았습니다.

이전 코드의 한 가지주의 사항

minify 시나리오와 함께 asp.net/mvc 번들을 사용하는 경우 릴리스 모드에서 배포 할 때 문제가 발생합니다. 문제는 잡힌 오류 : [$ injector : unpr]의 형태로 나타납니다.이 문제는 각 자바 스크립트 코드를 엉망으로 만드는 미니 파이어로 인해 발생합니다.

이를 해결하는 방법은 다음과 같습니다 .

이전 코드 조각을 다음 오버로드로 바꿉니다.

...
angular.element(document).injector().invoke(
[
    "$compile", function($compile) {
        var scope = angular.element(content).scope();
        $compile(content)(scope);
    }
]);
...

이것은 내가 그것을 모으기 전에 많은 슬픔을 일으켰습니다.


1
위의 코드가 범위와 컴파일에 대한 설명을 사용할 수 있도록 해주었으므로 감사합니다. 때때로 당신은 쉬운 부분을 놓친다 :)
— Abs

컴파일 후 $ digest를해야했습니다.
— Knu

2
절대 생명, I는 각 응용 프로그램에 연결 할 때 모든 각도 선 (善)을 사용할 수 있습니다 내 코드에서 각도에 대한 조건부 검사 추가
— LiamRyan

18

@jwize의 답변에 추가

angular.element(document).injector()오류가 발생 했기 때문에 injector is not defined AJAX 호출 후 또는 jQuery를 사용하여 DOM을 변경할 때 실행할 수있는 함수를 만들었습니다.

  function compileAngularElement( elSelector) {

        var elSelector = (typeof elSelector == 'string') ? elSelector : null ;  
            // The new element to be added
        if (elSelector != null ) {
            var $div = $( elSelector );

                // The parent of the new element
                var $target = $("[ng-app]");

              angular.element($target).injector().invoke(['$compile', function ($compile) {
                        var $scope = angular.element($target).scope();
                        $compile($div)($scope);
                        // Finally, refresh the watch expressions in the new element
                        $scope.$apply();
                    }]);
            }

        }

새 요소의 선택자를 전달하여 사용하십시오. 이렇게

compileAngularElement( '.user' ) ; 

감사합니다. $ scope 함수 내에서 HTML을 즉석에서 생성하여 대화 상자에 UIKit을 사용하는 패키지로 제 생명을 구했습니다. 참고로, 필자의 경우 $ [ "data-ng-controller]")에 맞게 $ target의 선택기를 변경하고 $ scope.apply (); 이 기능이 각도 콜백 이미 호출 된 이후 (그래서 이미 복용으로 적용)
— zontar

@zontar target는 인수에서 가져 와서 동적으로 만들 수도 있습니다 .
— shyammakwana.me
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.