AngularJS + JQuery: Cách tải nội dung động hoạt động trong anglejs


84

Tôi đang làm việc trên một ứng dụng Ajax sử dụng cả jQuery và AngularJS.

Khi tôi cập nhật nội dung (chứa liên kết AngularJS) của một div bằng cách sử dụng htmlhàm của jQuery , liên kết AngularJS không hoạt động.

Sau đây là mã những gì tôi đang cố gắng thực hiện:

$(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>

Tôi có nội dung động bên trong một div có ID #dynamicContentvà tôi có một nút làm mới sẽ cập nhật nội dung của div này khi nhấp vào làm mới. Phần tăng dần hoạt động như mong đợi nếu tôi không làm mới nội dung, nhưng sau khi tôi làm mới, liên kết AngularJS ngừng hoạt động.

Điều này có thể không hợp lệ trong AngularJS, nhưng ban đầu tôi đã xây dựng ứng dụng với jQuery và bắt đầu sử dụng AngularJS sau đó nên tôi không thể di chuyển mọi thứ sang AngularJS. Bất kỳ sự trợ giúp nào để làm việc này trong AngularJS đều được đánh giá rất cao.


1
Có lý do cụ thể nào để sử dụng JQuery cho chức năng này không? Vì đây là độc đáo và dễ dàng bao phủ bởi góc: < jsfiddle.net/pkozlowski_opensource/YCrFD/2 >
pkozlowski.opensource

3
Đây chỉ là một phiên bản đơn giản của trường hợp sử dụng thực của tôi để hiển thị vấn đề. Trong ứng dụng thực tế, nội dung động được tạo ra bởi grails taglib được chuyển sang jquery dưới dạng html. Vì vậy, tôi không thể chuyển tất cả logic trong grails taglib sang anglejs để biến nó thành anglejs thuần túy.
Raja

1
@ pkozlowski.opensource, liên kết đó đã chết? Ngoài ra, bạn nên tham gia ngoài trời.stackexchange.com :)
Liam

Câu trả lời:


115

Bạn cần gọi $compilechuỗi HTML trước khi chèn nó vào DOM để góc có cơ hội thực hiện liên kết.

Trong trò chơi của bạn, nó sẽ giống như thế này.

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

Rõ ràng, $compilephải được tiêm vào bộ điều khiển của bạn để điều này hoạt động.

Đọc thêm trong $compile tài liệu .


2
Cảm ơn Noah, biên dịch đang hoạt động khi tôi thực hiện nó trong một phương thức controller và liên kết trực tiếp phương thức controller đó với sự kiện nhấp vào nút. Đây là ví dụ làm việc . Nhưng tôi trong ứng dụng thực tế của mình, tôi phải gọi phương thức controller từ một hàm jquery khác. vì vậy tôi lấy tham chiếu đến đối tượng phạm vi và gọi phương thức làm mới để biên dịch lại mà không hoạt động. Đây là ví dụ . Bạn có thể giúp làm việc với ví dụ này.
Raja

1
@Raja Khi bạn gọi các phương thức / biểu thức góc bên ngoài khuôn khổ góc, bạn nên gọi $ scope. $ Apply () để thực hiện vòng đời phạm vi thích hợp của xử lý ngoại lệ, thực thi đồng hồ, v.v. jsfiddle.net/fABdD/14
Artem Andreev

1
@ArtemAndreev chính xác đúng. @Raja bạn cũng có thể di chuyển lệnh gọi đến $scope.$apply()vào refresh()chính hàm nếu nó phù hợp với kiến ​​trúc của bạn: jsfiddle.net/nfreitas/8xkeh/1
Noah Freitas

3
Liên kết đến angular-1.0.1.min.jstrong các ví dụ ban đầu là 404. Đây là các phiên bản làm việc cập nhật của ví dụ @ ArtemAndreev-s: jsfiddle.net/pmorch/fABdD/186 và ví dụ @NoahFreitas
Peter V. Mørch

1
Sử dụng $ biên dịch và thao tác DOM trong bộ điều khiển sẽ dẫn bạn đến con đường có mã không thể kiểm chứng được. Các hướng dẫn nên được sử dụng để thay đổi DOM không bao giờ là bộ điều khiển.
Enzey

57

Một giải pháp khác trong trường hợp bạn không có quyền kiểm soát nội dung động

Điều này hoạt động nếu bạn không tải phần tử của mình thông qua một chỉ thị (ví dụ như trong ví dụ trong jsfiddles đã nhận xét).

Kết thúc nội dung của bạn

Gói nội dung của bạn trong một div để bạn có thể chọn nó nếu bạn đang sử dụng JQuery . Bạn cũng có thể chọn sử dụng javascript gốc để lấy phần tử của mình.

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

Sử dụng Angular Injector

Bạn có thể sử dụng mã sau để nhận tham chiếu đến $ compile nếu bạn không có.

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

Tóm lược

Bài đăng ban đầu dường như giả sử bạn có một tài liệu tham khảo $ compile hữu ích. Rõ ràng là dễ dàng khi bạn có tài liệu tham khảo, nhưng tôi đã không nên đây là câu trả lời cho tôi.

Một thông báo trước của mã trước

Nếu bạn đang sử dụng gói asp.net/mvc với kịch bản minify, bạn sẽ gặp rắc rối khi triển khai ở chế độ phát hành. Rắc rối xảy ra dưới dạng Lỗi chưa suy nghĩ: [$ injectionor: unr] gây ra bởi trình thu nhỏ gây nhầm lẫn với mã javascript góc cạnh.

Đây là cách để khắc phục nó :

Thay thế đoạn mã trước bằng đoạn mã quá tải sau.

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

Điều này gây ra rất nhiều đau buồn cho tôi trước khi tôi ghép nó lại.


1
Cảm ơn vì mã trên đã làm việc cho tôi phạm vi và giải thích về biên dịch có sẵn. đôi khi bạn bỏ lỡ những phần dễ dàng :)
Abs

Tôi đã phải tiêu hóa $ sau khi biên dịch.
Knu

2
Absolute phao cứu sinh, tôi đã thêm một tấm séc có điều kiện cho góc trong mã của tôi cho phép nó sử dụng tất cả sự tốt lành góc khi cắm vào một ứng dụng góc
LiamRyan

18

Bổ sung cho câu trả lời của @ jwize

angular.element(document).injector()đã đưa ra lỗi injector is not defined Vì vậy, tôi đã tạo một hàm mà bạn có thể chạy sau khi gọi AJAX hoặc khi DOM được thay đổi bằng jQuery.

  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();
                    }]);
            }

        }

sử dụng nó bằng cách chỉ chuyển bộ chọn của phần tử mới. như thế này

compileAngularElement( '.user' ) ; 

Cảm ơn, điều này đã cứu mạng tôi với một gói sử dụng UIKit cho các hộp thoại của nó, với HTML được tạo nhanh chóng bên trong hàm $ scope. Lưu ý thêm, tôi đã phải thay đổi bộ chọn của $ target cho phù hợp với nhu cầu của mình, trong trường hợp của tôi là $ ["data-ng-controller]") và nhận xét $ scope.apply (); vì hàm này đã được gọi trong một lệnh gọi lại góc (vì vậy việc áp dụng đã diễn ra)
zontar

@zontar bạn cũng có thể tạo targetđộng bằng cách lấy nó từ đối số.
shyammakwana.me
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.