【问题标题】:How to bind <script> element's src attribute in AngularJS如何在 AngularJS 中绑定 <script> 元素的 src 属性
【发布时间】:2015-02-03 01:56:48
【问题描述】:

我正在尝试将 HTML &lt;script&gt; 元素的 src 属性绑定到我的角度控制器中的一个变量,以便我可以从控制器更新它而无需处理任何 UI。

到目前为止,我已经尝试了所有这些选项:

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

在我的控制器中,我有:

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

在 $scope.sourceUrl 设置后在浏览器中运行页面时,没有对 sourceUrl 的传出请求,所以我确定我做错了什么。有什么想法吗?

我发现了几篇关于&lt;img&gt; 元素的src 属性的帖子,ng-src 应该像他们说的那样工作,但我猜&lt;script&gt; 有点不同。

【问题讨论】:

  • &lt;script&gt; 标签仅在页面加载期间由浏览器解释一次。
  • 我通过有多个
  • @Aidin,我在代码中使用了很多绑定,所以我的控制器范围很好。多个选项的问题是我的 sourceUrl 是根据一些输入和一些随机数据生成的,因此我可以预先定义的 URL 没有限制。

标签: javascript html angularjs


【解决方案1】:

使用 AngularJS 指令的解决方案。

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

用法:

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

【讨论】:

    【解决方案2】:

    @Kolban 是对的,无论如何你可以尝试创建脚本元素,添加 src 属性,然后将其附加到模板中。 例如:

     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;
    }
    

    【讨论】:

      【解决方案3】:

      我知道答案来晚了,但这里有一个优雅而简单的解决方案:

      您必须通过 $sce.trustAsResourceUrl(value) 使用脚本上下文转义。

      Documentation

      它可能看起来像:

      在 app.js 中:

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

      在 index.html 中:

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

      脚本标签的src 属性将绑定到它在Angular 中的值。 这是我运行我的 web 应用程序并启动调试器以检查呈现的 HTML 时的结果:

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

      请注意,如果在第一次加载标签后完成绑定,脚本将不会被执行!

      【讨论】:

      • 在我使用 ng-src 而不是 src 之前,您的解决方案对我不起作用。之后在 ApplicationController 中设置受信任的 url 就可以了。
      【解决方案4】:

      您可以从控制器内将其动态添加到正文的末尾:

              $("<script>").attr({src: $scope.sourceUrl}).appendTo("body");
      

      【讨论】:

      • 不是 Angular 的方式,虽然
      【解决方案5】:

      根据@Jonathan 的建议添加我的解决方案作为答案。

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

      视图sn-p如下:

      <div id="JSObjectScript" style="display: inline" my-container />
      

      【讨论】:

        【解决方案6】:

        虽然脚本标签只能插入一次,你可以添加更多的脚本标签。

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

        在您的控制器中,只需将更多对象(如 {src: 'foo.js'})推送到脚本数组和延迟加载的脚本。

        这里有一个 Plunker 演示了这一点:http://plnkr.co/edit/6QuwuqsGoyrASk8FKmu2?p=preview

        【讨论】:

          【解决方案7】:

          很遗憾,您不能以这种方式使用 Angular。 Angular 仅在页面加载和构建后处理网页,此时 &lt;script&gt; 标记已被处理一次(脚本标记只运行一次)。其他标签(例如img)会在页面加载后其属性发生变化时改变屏幕的视觉外观......但如前所述,脚本仅处理一次,即使在页面加载期间也是如此在 Angular 获得控制权之前。

          【讨论】:

          • 嘿,非常感谢您的快速回复。但是,我仍然认为应该有办法做到这一点。我不想处理的最后手段只是getElementById("scriptElemId").src = newUrl;。但正如我提到的,我希望在控制器中有纯模型,没有 UI 摩擦。有没有更好的方法来做到这一点?或者也许我需要摆脱旧的
          • 就我个人而言,我不喜欢动态加载的代码......但是,普遍接受的机制是使用“require.js”......好好研究以下内容,看看你是否能看到它可以用来动态加载任意代码......requirejs.org
          • 我已经解决了添加指令以将生成的
          猜你喜欢
          • 2017-05-21
          • 2015-04-02
          • 1970-01-01
          • 1970-01-01
          • 2011-05-11
          • 1970-01-01
          • 2023-03-12
          • 2021-03-29
          • 2023-04-04
          相关资源
          最近更新 更多