AngularJS: จะสร้างสคริปต์โหลดเชิงมุมภายใน ng-include ได้อย่างไร


85

สวัสดีฉันกำลังสร้างหน้าเว็บที่มีมุม ปัญหาคือมีบางสิ่งที่สร้างขึ้นแล้วโดยไม่มีมุมและฉันต้องรวมไว้ด้วย

ปัญหาคือเรื่องนี้

ฉันมีสิ่งนี้ใน main.html ของฉัน:

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

partial.html ของฉันมีบางอย่างเช่นนี้

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

และ partial.js ของฉันไม่มีส่วนเกี่ยวข้องกับ angularjs nginclude ใช้งานได้และฉันสามารถเห็น html แต่ฉันไม่เห็นไฟล์จาวาสคริปต์ที่กำลังโหลดเลย ฉันรู้วิธีใช้ firebug / chrome-dev-tool แต่ฉันไม่เห็นแม้แต่การร้องขอเครือข่าย ผมทำอะไรผิดหรือเปล่า?

ฉันรู้เชิงมุมมีความหมายพิเศษกับแท็กสคริปต์ ฉันสามารถลบล้างได้หรือไม่?

คำตอบ:


101

คำตอบที่ยอมรับจะใช้ไม่ได้จาก 1.2.0-rc1 + ( ปัญหา Github )

นี่คือการแก้ไขด่วนที่สร้างโดย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));

เพียงแค่เพิ่มไฟล์นี้โหลดngLoadScriptโมดูลเป็นการพึ่งพาแอปพลิเคชันและใช้type="text/javascript-lazy"เป็นประเภทสำหรับสคริปต์ที่คุณจะโหลดอย่างเฉื่อยชา

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

5
ฉันไม่คิดว่าจะได้ผลถ้าแท็กสคริปต์ของคุณมีแอตทริบิวต์ src แทนที่จะเป็น js แบบอินไลน์
Blaskovicz


1
วิธีนี้ใช้งานได้อย่างสมบูรณ์ แต่ยังมีอีกสิ่งหนึ่งที่ฉันต้องการ ฉันจะลบสิ่งนี้ได้อย่างไรเมื่อคำสั่งถูกทำลาย
SLearner

เมื่อฉันประกาศตัวควบคุมในสคริปต์ขี้เกียจฉันได้รับข้อผิดพลาดเมื่ออ้างถึงคอนโทรลเลอร์ในมุมมอง คุณรู้ไหมว่าทำไม?
Changwang Zhang

นั่นเป็นเคล็ดลับ ฉันเคยใช้มันเพื่อเรียกใช้รหัสเริ่มต้นแท็บสำหรับชุดแท็บที่โหลดในบางส่วน
LKallipo

39

คำตอบสั้น ๆ : AngularJS ("jqlite") ไม่รองรับสิ่งนี้ รวม jQuery ไว้ในเพจของคุณ (ก่อนรวม Angular) ก็น่าจะใช้ได้ ดูhttps://groups.google.com/d/topic/angular/H4haaMePJU0/discussion


2
วิธีนี้จะทำงานอย่างไรหาก partial.js ของคุณมีคอนโทรลเลอร์ เทมเพลตจะแสดงผลก่อนที่คอนโทรลเลอร์จะโหลดและแสดงข้อผิดพลาด: Argument 'MyController' ไม่ใช่ฟังก์ชันไม่ได้กำหนด
sthomps

2
@sthomps ดูว่าสิ่งนี้ช่วยได้หรือไม่: การโหลดคอนโทรลเลอร์แบบไดนามิก
Mark Rajcok

16
ฉันไม่เข้าใจว่าทำไมถึงได้ผล - เบราว์เซอร์จะไม่โหลดแท็กสคริปต์ที่แทรกโดยอัตโนมัติหรือไม่ เหตุใดจึงเป็นข้อกังวลเกี่ยวกับ jQuery หรือ jqLite
Scott Coates

ได้ผลสำหรับฉันเช่นกันเนื้อหาของแท็ก <script> ของฉันนั้น angularjs ไม่เกี่ยวข้อง เมื่อฉันไม่โหลด jQuery ก่อน angularjs ทุกอย่างในบางส่วนของฉันด้านล่างและรวมถึงแท็กสคริปต์ก็ถูกลบออกแปลกมาก
Nick Russler

20

ฉันลองใช้วิธีของ neemzy แล้ว แต่มันไม่ได้ผลสำหรับฉันโดยใช้ 1.2.0-rc.3 แท็กสคริปต์จะถูกแทรกลงใน DOM แต่เส้นทางจาวาสคริปต์จะไม่ถูกโหลด ฉันสงสัยว่าเป็นเพราะจาวาสคริปต์ที่ฉันพยายามโหลดนั้นมาจากโดเมน / โปรโตคอลอื่น ดังนั้นฉันจึงใช้แนวทางที่แตกต่างออกไปและนี่คือสิ่งที่ฉันคิดขึ้นโดยใช้ Google Maps เป็นตัวอย่าง: ( 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');
                    });
                }
            }
        };
    }]);

ฉันหวังว่ามันจะเป็นประโยชน์สำหรับใครบางคน


4
แปลกฉันสร้างเวอร์ชันของตัวเองบน 1.2.0-rc3 ด้วยสคริปต์ภายนอก :) เวอร์ชันของคุณดีกว่าอยู่แล้วขอบคุณที่แบ่งปันสิ่งนี้!
neemzy

12

ฉันใช้วิธีนี้เพื่อโหลดไฟล์สคริปต์แบบไดนามิก (ภายในคอนโทรลเลอร์)

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

@azmeer
Ali

โหวตเพราะเป็นวิธีที่ง่ายและดีที่สุดสำหรับการโหลดสคริปต์แบบไดนามิก
RLD

8

สิ่งนี้จะใช้ไม่ได้อีกต่อไปจาก 1.2.0-rc1 ดูปัญหานี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ซึ่งฉันโพสต์ความคิดเห็นอธิบายวิธีแก้ปัญหาอย่างรวดเร็ว ฉันจะแบ่งปันที่นี่เช่นกัน:

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

ไม่ใช่วิธีแก้ปัญหาที่ดีที่สุด แต่เดี๋ยวก่อนไม่มีการใส่แท็กสคริปต์ในมุมมองที่ตามมา ในกรณีของฉันฉันต้องทำสิ่งนี้คือสั่งให้ใช้ Facebook / Twitter / ฯลฯ วิดเจ็ต


4

ocLazyLoadอนุญาตให้โหลดสคริปต์ในเทมเพลต / มุมมองผ่านเราเตอร์ (เช่น ui-router) นี่คือsniplet

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

ฉันประสบปัญหาเดียวกันเช่นนี้ ในแอปขององค์กรคุณต้องใช้เส้นทางทั้งหมดของคุณดังนั้นจึงควรใช้ ng-include ร่วมกับแท็บได้ดีกว่า แต่ ng-include มีปัญหาซึ่งไม่มีคุณสมบัติการโหลดแบบพึ่งพา ..
Serak Shiferaw

1

ในการโหลด recaptcha แบบไดนามิกจากui-viewฉันใช้วิธีการต่อไปนี้:

ใน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));


            }
        }
    };
});

ในmyPartial.client.view.html:

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

เพิ่มหรือลบล้างคำสั่งสคริปต์เนทีฟเชิงมุมหรือไม่ และนั่นคือการใช้ jquery ด้วยหรือไม่?
jamie

1
มันเพิ่มไปยัง. และไม่ไม่มีการใช้ Jquery ที่นั่น
Michael Draper

ขอบคุณ - 'ไม่มีการใช้ jQuery ที่นี่' - แปลก - $(element)ทำไมคุณถึงต้องการ$()ไวยากรณ์ จากเอกสาร ajs 'การอ้างอิงองค์ประกอบทั้งหมดใน Angular จะถูกรวมไว้ด้วย jQuery หรือ jqLite เสมอ' (เช่นอาร์กิวเมนต์องค์ประกอบในฟังก์ชันคอมไพล์ / ลิงก์ของคำสั่ง) - จากนั้นและประสบการณ์อื่น ๆ ของฉันฉันคาดหวังให้คุณใช้องค์ประกอบ ' ผนวก (... ) `- แม้ว่าฉันจะไม่ได้เป็นสิ่งที่ฉันสามารถใช้ได้ในตอนท้าย - เมื่อทำการทดสอบฉันรู้สึกสับสนเมื่อเห็นส่วนนั้นและไม่ได้ผลสำหรับฉันเมื่อฉันพยายามทำงานกับ 'element.append' เท่านั้น ไวยากรณ์
jamie

ใช่มันเป็น แต่คุณสามารถแทนที่ด้วย angular.element () ถ้าคุณต้องการเป็นไปได้มากที่สุด
Michael Draper

0

น่าเสียดายที่คำตอบทั้งหมดในโพสต์นี้ไม่ได้ผลสำหรับฉัน ฉันได้รับข้อผิดพลาดต่อไปนี้

ไม่สามารถดำเนินการ 'เขียน' บน 'เอกสาร': ไม่สามารถเขียนลงในเอกสารจากสคริปต์ภายนอกที่โหลดแบบอะซิงโครนัสได้เว้นแต่จะเปิดไว้อย่างชัดเจน

ฉันพบว่าสิ่งนี้เกิดขึ้นหากคุณใช้วิดเจ็ตของบุคคลที่สาม (demandforce ในกรณีของฉัน) ที่เรียกไฟล์ JavaScript ภายนอกเพิ่มเติมและพยายามแทรก HTML เมื่อมองไปที่คอนโซลและโค้ด JavaScript ฉันสังเกตเห็นหลายบรรทัดดังนี้:

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

ผมใช้ไฟล์ JavaScript บุคคลที่ 3 (htmlParser.js และ postscribe.js) จาก: https://github.com/krux/postscribe ที่แก้ไขปัญหาในโพสต์นี้และแก้ไขข้อผิดพลาดข้างต้นในเวลาเดียวกัน

(นี่เป็นวิธีที่รวดเร็วและสกปรกภายใต้เส้นตายที่แน่นหนาที่ฉันมีในตอนนี้ฉันไม่สะดวกกับการใช้ไลบรารี JavaScript ของบุคคลที่สามฉันหวังว่าจะมีคนคิดวิธีที่สะอาดและดีกว่านี้


0

ฉันพยายามใช้ Google reCAPTCHA อย่างชัดเจน นี่คือตัวอย่าง:

// 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));
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.