Подтвердить что ты не робот

Загружать динамический блок script с внешним виджетами в angularjs

У меня есть блок script для загрузки виджета на частичном представлении, но я становлюсь ниже ошибки, если я поместил прямо на частичную страницу html:

"Не удалось выполнить 'write' в 'Document': невозможно написать в документ из асинхронно загруженного внешнего script, если только он явно открыт."

Пример script:

> <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-страницу с тегом html/body и помещаю ее выше script, а затем загружаю эту страницу через iframe, тогда она работает. Но проблема очень сложная для обновления содержимого перед загрузкой в ​​iframe

4b9b3361

Ответ 1

Не видя некоторого содержимого внешнего виджета, это трудно точно диагностировать. Мое первое впечатление состоит в том, что его, возможно, придется изменить, чтобы вернуть документ, который вы затем назначили бы в блоке JS script, используя имя функции заголовка во внешнем виджете. Что-то вроде:

var someDoc = writeDoc();

Где writeDoc() - это функция заголовка в виджетах, которая возвращает, я полагаю, какой-то HTML-документ. Тег script должен появиться перед вашей декларацией, конечно. Кроме того, с вашим требованием ng-repeat вы можете использовать что-то вроде:

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

В блоке списка или даже блоке выбора (хотя я бы не рекомендовал что-то подобное), в зависимости от того, сколько места занимает документ.

Надеюсь, что это поможет.

-C§

Ответ 2

  • Используйте компилирующую службу $, чтобы скомпилировать содержимое html, которое вы динамически загрузили, и в то же время привязать его к области.
  • Предлагаю вам сделать директиву. Вы можете передать URL-адрес частичного, используя атрибут.

В частности, свойство директивной ссылки выглядит следующим образом:

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

Подробнее см. ответ на этот вопрос, он предоставил демоверсию plunker.

Надеюсь, это поможет.

ИЗМЕНИТЬ Я хотел бы написать больше в ответ на @Víťa Plšek - angular.cz ответ. Я однажды сделал что-то еще более динамичное, чтобы загрузить javacsript в частичный!

Когда-то я делал одностраничное приложение, основанное на angularjs. Каждая функция меню является частичной динамической загрузкой с использованием ajax. Естественно, каждая функция меню представляет собой отдельный контроллер angular. Чтобы упростить управление кодами, я не объединил все коды контроллеров в один файл и не загружал их сразу из 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, а затем скомпилировать часть <div ng-controller="DynamicController1"></div> после того, как файл js завершил загрузку.

Итак, коды директивы 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");
            }
        };
    }]);

Ответ 3

Коренной причиной вашей проблемы является то, что браузер не будет загружать javascript после инициализации страницы. Здесь описано Выполнение записи в документе: невозможно записать в документ из асинхронно загруженного внешнего script, если он явно не открыт.

Но...

Необходимость загрузки javascript в шаблоне звучит странно. Angular является основой для применения SPA. Они должны работать как внешнее приложение для вашего сервера и общаться с каким-то API.

Почему виджет содержит javascript? Когда я получаю доступ к вашей ссылке, я вижу, что это простой html. Если это так, то вы можете использовать директиву ng-include - https://docs.angularjs.org/api/ng/directive/ngInclude

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

Если виджет содержит некоторый не-w501 > javascript, я бы предположил, что виджеты должны быть переписаны в обычные директивы, которые также могут связываться с сервером.