使用angularjs中的外部窗口小部件加载动态脚本块

时间:2015-07-29 13:33:43

标签: javascript html angularjs

我有脚本块在局部视图上加载小部件,但如果我直接放在部分html页面上,我会收到以下错误:

  

“无法在'Document'上执行'write':无法写入   从异步加载的外部脚本转换为文档,除非   它被明确地打开了。“

示例脚本块是:

> <script type="text/javascript"  defer="defer"
> src="http://svenskfotboll.se/widget.aspx?scr=table&amp;ftid=57108&amp;b1=%232f3841&amp;f1=%23ffffff&amp;b2=%23acbfda&amp;f2=%23000000&amp;b3=%23ffffff&amp;f3=%23000000&amp;b4=%23ececec&amp;bo=%23dfdfdf&amp;s=1"></script>

我将有多个小部件,所以我想要通过ng-repeat加载。请指教。

注意 我尝试显示静态方式为此我添加一个带有html / body标签的html页面并将其放在上面的脚本块然后通过iframe加载该页面然后它工作。但问题是在加载到iframe之前更新内容非常困难

3 个答案:

答案 0 :(得分:1)

如果没有看到外部窗口小部件的某些内容,则很难准确诊断。我的第一印象是可能需要更改它才能返回一个文档,然后使用外部窗口小部件中的头函数名称在JS脚本块中分配该文档。有点像:

var someDoc = writeDoc();

其中writeDoc()是小部件中的头函数,我假设它返回某种HTML文档。当然,脚本标签必须在您的声明之前。或者,根据您的ng-repeat要求,您可以使用以下内容:

ng-repeat="{{writeDoc()}}"

在列表块或甚至是一个选择块中(虽然我不推荐这样的东西),取决于文档占用多少空间。

希望有所帮助。

-C§

答案 1 :(得分:1)

  1. 使用$ compile服务编译动态加载的html内容,同时将其绑定到作用域。
  2. 建议你做一个指示。您可以使用属性传入partial的url。
  3. 特别是指令的链接属性是这样的:

        link: function (scope, ele, attrs) {
          scope.$watch(attrs.dynamic, function(html) {
            ele.html(html);
            $compile(ele.contents())(scope);
          });
        }
    

    有关详细信息,请参阅answer to this question,它提供了一个plunker演示。

    希望这会有所帮助。

    修改 我想写更多回应@VíťaPlšek - angular.cz的答案。 我曾经做过更动态的事情,就是在部分加载javacsript!

    曾几何时,我根据angularjs做了一页的应用程序。每个菜单功能都是使用ajax动态加载的部分功能。当然,每个菜单功能都是一个单独的角度控制器。为了使代码更易于管理,我没有将所有控制器的代码合并到一个文件中,而是从index.html一次性加载它们。相反,我让每个部分使用自定义指令指定自己的控制器的js代码并执行延迟加载。

    因此,单页应用程序的主页面使用自定义指令来包含动态加载的部分:

    <body>
    ...
        <dynamic-partial src={{selected_partial_url}}>
        </dynamic-partial>
    ...
    </body>
    

    ,而每个部分都存储在一个单独的html文件中。它的内容是这样的:

    <lazy-load-script src="js/controllers/dynamic-controller1.js" >
    </lazy-load-script>
    
    <div ng-controller="DynamicController1">
        ...
    </div>
    

    现在,有一个问题:如果我们一次编译部分文件,则会出现错误,指出DynamicController1未定义。是真的。我们必须首先加载dynamic-controller1.js,然后在js文件加载完成后编译部分<div ng-controller="DynamicController1"></div>

    所以指令DynamicPartial的代码是这样的:

    "use strict";
    angular.module('MyApp')
        .directive('DynamicPartial', [ "$compile", function( $compile ) {
            return {
                restrict: 'E',
                scope: {
                    src: '@'
                },
                link: function (scope, element, attr) {
                    console.log( "Linking web-terminal. src = " + scope.src );
                    scope.onLazyLoadDone = function(){
                    // compile the other html elements in the partial, and put them in <dynamic-partial> element.
                        element.html( $compile( scope.other_elements_html )(scope) );
                    }
                    attr.$observe( 'src', function( value ){ // fetch new partial as soon as 'src' attribute changes:
                        console.log( "'src' attribute changed. Fetching new partial: " + value );
                        if( "" == scope.src ) {
                            element.addClass("ng-hide");
                            return;
                        }
                        else
                            element.removeClass("ng-hide");
                        $.ajax({
                                dataType: 'text',
                                timeout: 5000,
                                url: scope.src
                            })
                            .done(function (data) {
                                console.log( "Successfully fetched terminal file, length = " + data.length);
                                // compile the <lazy-load-script> tag first:
                                var lazy_load_element = $('<div/>').append( $(data)).find( "lazy-load-script, [lazy-load-script]" );
                                if( lazy_load_element.length > 0 ) { // lazy-load-script element found:
                                    // Here we pragmatically set the "on-loaded" attribute for the <lazy-load-script> element found in the loaded partial, so that we can get called when the javascript file specified by <lazy-load-script> element finishes loading.
                                    lazy_load_element.attr("on-loaded", "onLazyLoadDone()");
                                    $compile($('<div/>').append(lazy_load_element).html())(scope);
                                }
                                // Save the remaining DOM elements in the partial, which will be compiled after the lazy-load is done.
                                scope.other_elements_html = $('<div/>').append( $(data).filter(':not([lazy-load],lazy-load)')).html();
                                if( 0 == lazy_load_element.length )
                                    scope.onLazyLoadDone();
                            })
    
                            .fail(function (jqXHR, textStatus, errorThrown) {
                                console.error("Failed fetching menu from server: " + errorThrown.message);
                            });
                    });
                    if( undefined == scope.src  || 'not defined' == scope.src ) {
                        return;
                    }
                }
            };
        }]);
    

    <lazy-load-script>的代码如下。关键是使用onLoaded范围属性来指定对父控制器的回调。

    "use strict";
    angular.module('SyncreonApp')
        .directive('lazyLoad', [ "$ocLazyLoad",  function( $ocLazyLoad ) {
            return {
                restrict: 'EA',
                scope: {
                    src: '@',
                    onLoaded: '&'
                },
                link: function (scope, element, attr) {
                    //console.log( "Linking lazyLoadScript, url to load = " + scope.src );
                    if( undefined != scope.src && '' != scope.src ){
                        $ocLazyLoad.load( scope.$parent.$parent.getBasePath() + scope.src )
                            .then(function () {
                                //Javascript lazy load done, calling back to parent controller, so that parent will continue with compiling other parts of the partial.
                                scope.onLoaded();
                            });
                    }
                    else
                        console.error( "Illegal src attribute in directive lazyLoad");
                }
            };
        }]);
    

答案 2 :(得分:0)

问题的根本原因是浏览器在页面初始化后不会加载javascript。这里描述了它 - Execute write on doc: It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.

但是......

需要在模板中加载javascript听起来很奇怪。 Angular是SPA应用程序的框架。它们应该像服务器的外部应用程序一样工作,并与某种API进行通信。

为什么小部件包含javascript?当我访问你的链接时,我可以看到它是简单的HTML。如果是,那么您可以使用ng-include指令 - https://docs.angularjs.org/api/ng/directive/ngInclude

   ng-include="'path-to-template/tamplate-name.html'" 

如果小部件包含一些非角度的javascript,我建议小部件应该重写为普通指令,也可以与服务器通信。