AngularJS: Làm thế nào để tạo tập lệnh tải góc bên trong ng-include?


85

Này, tôi đang xây dựng một trang web với góc cạnh. Vấn đề là có những thứ đã được xây dựng mà không có góc cạnh và tôi cũng phải đưa chúng vào

Vấn đề là đây.

Tôi có một cái gì đó như thế này trong main.html của tôi:

<ngInclude src="partial.html">
</ngInclude>

Và part.html của tôi có một cái gì đó như thế này

<h2> heading 1 <h2>
<script type="text/javascript" src="static/js/partial.js">
</script>

Và một phần.js của tôi không liên quan gì đến anglejs. nginclude hoạt động và tôi có thể thấy html, nhưng tôi không thể thấy tệp javascript đang được tải. Tôi biết cách sử dụng firebug / chrome-dev-tool, nhưng tôi thậm chí không thể thấy yêu cầu mạng được thực hiện. Tôi đang làm gì sai?

I knwo angle có một số ý nghĩa đặc biệt đối với thẻ script. Tôi có thể ghi đè nó không?

Câu trả lời:


101

Câu trả lời được chấp nhận sẽ không hoạt động từ 1.2.0-rc1 + ( Vấn đề trên Github ).

Đây là một bản sửa lỗi nhanh được tạo bởi endorama :

/*global angular */
(function (ng) {
  'use strict';

  var app = ng.module('ngLoadScript', []);

  app.directive('script', function() {
    return {
      restrict: 'E',
      scope: false,
      link: function(scope, elem, attr) {
        if (attr.type === 'text/javascript-lazy') {
          var code = elem.text();
          var f = new Function(code);
          f();
        }
      }
    };
  });

}(angular));

Chỉ cần thêm tệp này, tải ngLoadScriptmô-đun dưới dạng phụ thuộc ứng dụng và sử dụng type="text/javascript-lazy"làm loại cho tập lệnh mà bạn tải một cách lười biếng theo các phần:

<script type="text/javascript-lazy">
  console.log("It works!");
</script>

5
Tôi không nghĩ rằng điều này hoạt động nếu thẻ script của bạn có thuộc tính src thay vì js nội tuyến.
Blaskovicz


1
Điều này hoạt động hoàn hảo, tuy nhiên có một điều tôi muốn. Làm cách nào để loại bỏ điều này sau khi chỉ thị đã bị hủy?
SLearner

Khi tôi khai báo bộ điều khiển trong tập lệnh lười biếng, tôi đã gặp lỗi khi tham chiếu bộ điều khiển trong dạng xem. Bạn có biết tại sao?
Changwang Zhang

Đó là mẹo. Tôi đã sử dụng nó để chạy mã khởi tạo tab cho một tabset nạp trong một phần
LKallipo

39

Câu trả lời ngắn gọn: AngularJS ("jqlite") không hỗ trợ điều này. Bao gồm jQuery trên trang của bạn (trước khi bao gồm Angular) và nó sẽ hoạt động. Xem https://groups.google.com/d/topic/angular/H4haaMePJU0/discussion


2
Điều này hoạt động như thế nào nếu một phần.js của bạn chứa bộ điều khiển? Mẫu sẽ hiển thị trước khi bộ điều khiển tải và đưa ra lỗi: Đối số 'MyController' không phải là một hàm, không được xác định.
sthomps

2
@sthomps, xem điều này có hữu ích không: Đang tải động một bộ điều khiển
Mark Rajcok,

16
Tôi không hiểu tại sao điều này hoạt động - trình duyệt sẽ không tự động tải thẻ tập lệnh được chèn vào phải không? Tại sao đây là mối quan tâm của jQuery hoặc jqLite?
Scott Coates

cũng làm việc cho tôi, nội dung của thẻ <script> của tôi không liên quan đến góc cạnh. Khi tôi không tải jQuery trước khi anglejs, mọi thứ trong phần của tôi bên dưới và bao gồm cả thẻ script đã bị xóa, rất kỳ lạ.
Nick Russler

20

Tôi đã thử cách tiếp cận của neemzy, nhưng nó không hoạt động với tôi khi sử dụng 1.2.0-rc.3. Thẻ script sẽ được chèn vào DOM, nhưng đường dẫn javascript sẽ không được tải. Tôi nghi ngờ đó là do javascript tôi đang cố tải từ một miền / giao thức khác. Vì vậy, tôi đã thực hiện một cách tiếp cận khác và đây là những gì tôi đã nghĩ ra, sử dụng bản đồ google làm ví dụ: ( Gist )

angular.module('testApp', []).
    directive('lazyLoad', ['$window', '$q', function ($window, $q) {
        function load_script() {
            var s = document.createElement('script'); // use global document since Angular's $document is weak
            s.src = 'https://maps.googleapis.com/maps/api/js?sensor=false&callback=initialize';
            document.body.appendChild(s);
        }
        function lazyLoadApi(key) {
            var deferred = $q.defer();
            $window.initialize = function () {
                deferred.resolve();
            };
            // thanks to Emil Stenström: http://friendlybit.com/js/lazy-loading-asyncronous-javascript/
            if ($window.attachEvent) {  
                $window.attachEvent('onload', load_script); 
            } else {
                $window.addEventListener('load', load_script, false);
            }
            return deferred.promise;
        }
        return {
            restrict: 'E',
            link: function (scope, element, attrs) { // function content is optional
            // in this example, it shows how and when the promises are resolved
                if ($window.google && $window.google.maps) {
                    console.log('gmaps already loaded');
                } else {
                    lazyLoadApi().then(function () {
                        console.log('promise resolved');
                        if ($window.google && $window.google.maps) {
                            console.log('gmaps loaded');
                        } else {
                            console.log('gmaps not loaded');
                        }
                    }, function () {
                        console.log('promise rejected');
                    });
                }
            }
        };
    }]);

Tôi hy vọng nó hữu ích cho ai đó.


4
Thật kỳ lạ, tôi đã tạo phiên bản của riêng mình trên 1.2.0-rc3 với các tập lệnh bên ngoài :) Dù sao thì phiên bản của bạn vẫn tốt hơn, cảm ơn bạn đã chia sẻ điều này!
neemzy

12

Tôi đã sử dụng phương pháp này để tải động tệp tập lệnh (bên trong bộ điều khiển).

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "https://maps.googleapis.com/maps/api/js";
document.body.appendChild(script);

Nice one @azmeer
Ali

Đã bình chọn vì đây là giải pháp đơn giản và tốt nhất để tải tập lệnh động.
RLD

8

Điều này sẽ không hoạt động nữa từ 1.2.0-rc1. Xem sự cố này để biết thêm về nó, trong đó tôi đã đăng một nhận xét mô tả một giải pháp nhanh chóng. Tôi cũng sẽ chia sẻ nó ở đây:

// Quick fix : replace the script tag you want to load by a <div load-script></div>.
// Then write a loadScript directive that creates your script tag and appends it to your div.
// Took me one minute.

// This means that in your view, instead of :
<script src="/path/to/my/file.js"></script>

// You'll have :
<div ng-load-script></div>

// And then write a directive like :
angular.module('myModule', []).directive('loadScript', [function() {
    return function(scope, element, attrs) {
        angular.element('<script src="/path/to/my/file.js"></script>').appendTo(element);
    }
}]);

Không phải là giải pháp tốt nhất từ ​​trước đến nay, nhưng này, việc đặt các thẻ script trong các lần xem tiếp theo cũng vậy. Trong trường hợp của tôi, tôi phải làm điều này là sử dụng Facebook / Twitter / etc. vật dụng.


4

ocLazyLoad cho phép tải tập lệnh một cách lười biếng trong các mẫu / chế độ xem thông qua bộ định tuyến (ví dụ: ui-router). Đây là một bức ảnh

$stateProvider.state('parent', {
    url: "/",
    resolve: {
        loadMyService: ['$ocLazyLoad', function($ocLazyLoad) {
             return $ocLazyLoad.load('js/ServiceTest.js');
        }]
    }
})
.state('parent.child', {
    resolve: {
        test: ['loadMyService', '$ServiceTest', function(loadMyService, $ServiceTest) {
            // you can use your service
            $ServiceTest.doSomething();
        }]
    }
});  

tôi phải đối mặt với vấn đề tương tự như thế này. trong ứng dụng doanh nghiệp, bạn phải sử dụng tất cả các tuyến đường của bạn để nó tốt hơn để sử dụng ng-bao gồm với với các tab nhưng ng-bao gồm có các vấn đề của nó mà là nó không có tính năng phụ thuộc loading ..
Serak Shiferaw

1

Để tải động recaptcha từ một, ui-viewtôi sử dụng phương pháp sau:

Trong application.js:

    .directive('script', function($parse, $rootScope, $compile) {
    return {
        restrict: 'E',
        terminal: true,
        link: function(scope, element, attr) {
            if (attr.ngSrc) {
                 var domElem = '<script src="'+attr.ngSrc+'" async defer></script>';
                 $(element).append($compile(domElem)(scope));


            }
        }
    };
});

Trong myPartial.client.view.html:

 <script type="application/javascript" ng-src="http://www.google.com/recaptcha/api.js?render=explicit&onload=vcRecaptchaApiLoaded"></script>

điều đó có thêm vào hoặc ghi đè chỉ thị tập lệnh gốc có góc cạnh không? Và đó là sử dụng jquery với điều đó?
jamie

1
Nó thêm vào. Và không, không được sử dụng Jquery có
Michael Draper

thx - 'không có jQuery được sử dụng ở đây' - kỳ lạ- $(element)tại sao bạn cần $()cú pháp. từ tài liệu ajs 'Tất cả các tham chiếu phần tử trong Angular luôn được bao bọc bằng jQuery hoặc jqLite' (chẳng hạn như đối số phần tử trong hàm biên dịch / liên kết của chỉ thị) - vì vậy từ đó và các kinh nghiệm khác của tôi - tôi mong bạn sử dụng phần tử '. append (...) `- mặc dù cuối cùng tôi không phải là thứ tôi có thể sử dụng - khi kiểm tra, tôi đã bối rối khi thấy phần đó và không hoạt động với tôi khi tôi cố gắng chỉ hoạt động với 'element.append' cú pháp
jamie

doh vâng nó là như vậy, nhưng bạn có thể thay thế nó bằng angle.element () nếu bạn muốn, rất có thể.
Michael Draper

0

Thật không may, tất cả các câu trả lời trong bài đăng này không phù hợp với tôi. Tôi tiếp tục nhận được lỗi sau.

Không thể thực thi 'ghi' trên 'Tài liệu': Không thể ghi vào tài liệu từ một tập lệnh bên ngoài được tải không đồng bộ trừ khi nó được mở rõ ràng.

Tôi phát hiện ra rằng điều này xảy ra nếu bạn sử dụng một số tiện ích con của bên thứ 3 (trong trường hợp của tôi là nhu cầu) cũng gọi các tệp JavaScript bên ngoài bổ sung và cố gắng chèn HTML. Nhìn vào bảng điều khiển và mã JavaScript, tôi nhận thấy nhiều dòng như thế này:

document.write("<script type='text/javascript' "..."'></script>");

Tôi đã sử dụng các tệp JavaScript của bên thứ 3 (htmlParser.js và postscribe.js) từ: https://github.com/krux/postscribe . Điều đó đã giải quyết vấn đề trong bài đăng này và sửa lỗi ở trên cùng một lúc.

(Đây là một cách nhanh chóng và bẩn thỉu trong thời hạn chặt chẽ mà tôi có bây giờ. Tuy nhiên, tôi không cảm thấy thoải mái khi sử dụng thư viện JavaScript của bên thứ ba. Tôi hy vọng ai đó có thể nghĩ ra cách sạch hơn và tốt hơn.)


0

Tôi đã thử sử dụng reCAPTCHA của Google một cách rõ ràng. Đây là ví dụ:

// put somewhere in your index.html
<script type="text/javascript">
var onloadCallback = function() {
  grecaptcha.render('your-recaptcha-element', {
    'sitekey' : '6Ldcfv8SAAAAAB1DwJTM6T7qcJhVqhqtss_HzS3z'
  });
};

//link function of Angularjs directive
link: function (scope, element, attrs) {
  ...
  var domElem = '<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>';
  $('#your-recaptcha-element').append($compile(domElem)(scope));
}
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.