How to bind – Blackhole Dec 05 '14 at 00:21

  • I accomplished this by having multiple – Aidin Dec 05 '14 at 00:32
  • @Aidin, I use a lot of bindings in my code, so my controller scope is fine. The problem with multiple options is my sourceUrl is generated based on some input and some random data, so there is no limited set of URLs that I can pre-define. – Arsen Y.M. Dec 05 '14 at 00:41
  • 7 Answers7

    24

    Unfortunately, you can not use Angular in this way. Angular processes the web page only after the page has been loaded and built by which time the <script> tag has been processed its one time (script tags are only ever run once). Other tags such as img will change the visual appearance of the screen when their properties change after the page has loaded ... but as mentioned, the script is only processed once and even then during page load and before Angular can ever get control.

    Kolban
    • 13,794
    • 3
    • 38
    • 60
    • hey, thanks a lot for a quick response. However, I still think there should be a way to do that. The last resort, which I don't want to deal with is just `getElementById("scriptElemId").src = newUrl;`. But as I mentioned, I want to have pure model in the controller, no UI friction. Is there a better way to do that? Or maybe I will need to get rid of the old – Arsen Y.M. Dec 05 '14 at 00:29
    • 1
      Personally, I frown on dynamically loaded code ... however, the generally accepted mechanism is to use "require.js" ... have a good study of the following and see if you can see how it can be used to dynamically load arbitrary code.... http://requirejs.org/ – Kolban Dec 05 '14 at 00:31
    • 3
      I have solved my issue adding a directive to append a generated – Arsen Y.M. Dec 08 '14 at 22:53
    5

    You could have added it dynamically to the end of the body from within the controller:

            $("<script>").attr({src: $scope.sourceUrl}).appendTo("body");
    
    Houdini Sutherland
    • 1,550
    • 21
    • 20
    4

    Adding my solution as an answer per @Jonathan's suggestion.

    (function (ng) {
    
        // Retrieve main app module
        var appModule = angular.module('appModule');
    
        // This directive appends a child <script> element to an element with 'my-container' attribute.
        // This is needed for 'src' attribute generation and script evaluation of some object after the
        // page has been loaded.
        appModule.directive('myContainer', ['$log', 'MvcModelService', function ($log, MvcModelService) {
            return {
                restrict: 'A',
                scope: false,
                link: function (scope, elem, attrs) {
                    var s = document.createElement("script");
                    s.type = "text/javascript";
    
                    var JSObjectName = "JSObject";
    
                    // Just a random number ...
                    var randomNumber = Math.floor(Math.random() * Number.MAX_VALUE);
    
                    // flowId is a UUID representing current session.
                    var flowId = MvcModelService.FlowId;
    
                    // Construct the url  where the object contents will be loaded from:
                    var Url = MvcModelService.UrlPrefix + "Get" + whatever + "/" + JSObjectName +
                              "someOtherStuffDepending on flowId and randomNumber";
    
                    s.src = Url;
    
                    $log.info("Adding script element to MyContainer with source url: " + Url);
                    elem.append(s);
                }
            };
        }]);
    }(angular));
    

    And the view snippet follows:

    <div id="JSObjectScript" style="display: inline" my-container />
    
    Arsen Y.M.
    • 673
    • 1
    • 7
    • 18
    3

    @Kolban is right, anyway you can try to create the script element, add the src attr and then append it to the template. For example:

     var exampleController = function() {
     controller.exampleController= [ '$sce',function($sce) {
    
         //Remember to set the src as a trusted src
    
         var trustedSrc = $sce.getTrustedUrl("www.example.com");
    
         var scriptElement = document.createElement('script');
    
         //Add attributes 
    
         scriptElement.setAttribute("data-size", '1220x700' );
         scriptElement.setAttribute("src", trustedSrc);
    
    
         //Append the srcipt to some element in the template
    
         var elementContainer = angular.element('#elementToAppend');
         elementContainer.append(scriptElement);
     }]
    
    return controllers;
    }
    
    1

    Although the script tags may only be interpolated once you can just add more script tags.

    <script ng-repeat="script in scripts" ng-src="{{script.src}}"></script>
    

    In your controller just push more objects like {src: 'foo.js'} to the scripts array and presto, lazy loaded scripts.

    Here is a Plunker that demonstrates this: http://plnkr.co/edit/6QuwuqsGoyrASk8FKmu2?p=preview

    Enzey
    • 5,254
    • 1
    • 18
    • 20
    1

    I know the answer comes late but here is an elegant and simple solution:

    You have to use the Script Contextual Escaping with $sce.trustAsResourceUrl(value).

    See Documentation

    It would probably look like :

    In app.js:

    //Dynamic Url for Tagging
        $rootScope.exUrl1 = $sce.trustAsResourceUrl(confserver.example.url);
    

    In index.html:

    <script type="text/javascript" src="{{exUrl1}}"></script>
    

    The src attribute of the script tag will be binded to its value in Angular. Here is the result when I run my webapp and launch the debugger to check the rendered HTML:

    <script type="text/javascript" src="http://exampleUrl.js"></script>
    

    Please note that the script will not be executed if the bind is done after the first loading of the tag !

    • 1
      Your solution didn't work for me until I used `ng-src` instead of `src`. After that setting the trusted url in ApplicationController did the trick. – mareckmareck Feb 14 '17 at 14:10
    0

    Solution using AngularJS directive.

    function dynamicScript () {
        return {
            restrict: 'E',
            scope: {
                dynamicScriptSrc: '='
            },
            link: function(scope, element, attrs, ngModel) {
                setScriptSrc(element, scope.$eval(attrs.dynamicScriptSrc));
    
                scope.$watch('dynamicScriptSrc', src => {
                    setScriptSrc(element, src);
                });
            }
        }
    }
    
    function setScriptSrc(element, src) {
        if(src) {
            var newScript = document.createElement("script");
            newScript.type = 'text/javascript';
            newScript.src = src;
            element.empty();
            element.append(newScript);
        }
    }
    

    Usage:

    <dynamic-script dynamic-script-src="vm.dynamicJsPath"></dynamic-script>
    
    Ivan
    • 1