Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I am trying to bind the src attribute of an HTML <script> element to a variable in my angular controller, so that I can update it from controller without dealing with any UI.

So far I've tried all these options:

<script type="text/javascript" ng-src="{{sourceUrl}}"></script>
<script type="text/javascript" src="{{sourceUrl}}"></script>
<script type="text/javascript" ng-src="sourceUrl"></script>

In my controller I have:

$scope.sourceUrl = "https://<some url goes here>";

When running the page in the browser after the $scope.sourceUrl gets set there is no outgoing request to sourceUrl, so I am sure I am doing something wrong. Any ideas?

I found several posts about src attribute of <img> element, and ng-src should work as they say, but I guess <script> is somehow different.

share|improve this question
    
<script> tags are interpreted only once, during the page loading, by the browser. – Blackhole Dec 5 '14 at 0:21
    
I accomplished this by having multiple <script> tags but enabling them using ng-if: e.g. <script ng-if="condition1" src="script1"/> <script ng-if="condition2" src="script2"/>. Also you should be aware of the scope you are using. To be safe add the scope variables to $rootScope – Aidin Dec 5 '14 at 0: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 5 '14 at 0:41
up vote 9 down vote accepted

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.

share|improve this answer
    
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 <script> element and render a new one with new value in src instead. – Arsen Y.M. Dec 5 '14 at 0: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.... requirejs.org – Kolban Dec 5 '14 at 0:31
2  
I have solved my issue adding a directive to append a generated <script> element (with a generated url as a value for 'src' attribute) to a containing element. And it worked perfectly. – Arsen Y.M. Dec 8 '14 at 22:53
    
@ArsenY.M. please post the code as the answer. – Jonathan Jan 26 at 6:21

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 />
share|improve this answer

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

share|improve this answer
    
It does not work. – erkpwejropi Mar 17 at 22:20

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

        $("<script>").attr({src: $scope.sourceUrl}).appendTo("body");
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.