Почему мой твиттер-виджет не рендерится, если я изменю представление в angularjs?

Привет и спасибо за чтение.

У меня есть угловое приложение, которое я делаю, и я наткнулся на проблему. настроить так

index.html-

<html ng-app="myApp">
...
<div ng-view></div>
<div ng-include="'footer.html'"></div>
...
</html>

Я не буду ставить мои маршруты довольно просто / home показывает /home/index.html и так далее...

/home/index.html (вид по умолчанию, когда вы заходите на сайт)

<div class="responsive-block1">
<div class="tweet-me">
    <h1> tweet me </h1>
</div>

<div class="twitter-box">
    <twitter-timeline></twitter-timeline>
</div>

директива временной шкалы Twitter

directives.directive("twitterTimeline", function() {
return { 
     restrict: 'E',
     template: '<a class="twitter-timeline" href="https://twitter.com/NAME" data-widget-id="XXXXXXXXXXXXXX">Tweets by @NAME</a>',
     link: function(scope, element, attrs) {

    function run(){
        (!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs"));
        console.log('run script');
    };

    run();


     }
   };
});

Итак, я только что создал базовую директиву twitter, используя тег из twitter. Но когда я изменяю пример представления на / blog, затем возвращаюсь в / home, виджет твиттера больше не рендерится вообще.

Я также использую $anchorScroll, и если я перехожу в любом случае на странице с этим, виджет также исчезает. Любая информация будет здорово, спасибо.

6 ответов

Решение

Смотрите этот пост: https://dev.twitter.com/discussions/890

Я думаю, что вы можете получить виджет для повторного рендеринга, вызвав twttr.widgets.load().

Если вы обнаружите, что это не работает, вам нужно обернуть этот код в $timeout в вашем контроллере:

    controller('MyCtrl1', ['$scope', '$timeout', function ($scope, $timeout) {
            $timeout = twttr.widgets.load();
    }])

Чтобы построить ответ сэра l33tname:

В декларации услуг:

    angular.module('app.services', []).
      service('tweetWidgets', function() {

        this.loadAllWidgets = function() {

            /* widgets loader code you get when 
             * declaring you widget with Twitter 
             * this code is the same for all widgets 
             * so calling it once will reference whatever
             * widgets are active in the current ng-view */

            !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
         };

         this.destroyAllWidgets = function() {
            var $ = function (id) { return document.getElementById(id); };
            var twitter = $('twitter-wjs');
            if (twitter != null)
                twitter.remove();
         };  
      });

Тогда в декларации контроллера:

    angular.module('app.controllers', []).
      controller('view_1_Controller', tweetWidgets) {

         // load them all
         tweetWidgets.loadAllWidgets();

     }).

       controller('view_2_Controller', tweetWidgets) {

          // now destroy them :>
          tweetWidgets.destroyAllWidgets();

     });

Теперь каждый раз, когда вы покидаете представление № 1 для перехода к представлению № 2, ваш контроллер для представления № 2 будет удалять виджеты, связанные с представлением № 1, и когда вы вернетесь к представлению № 1, виджеты будут восстановлены.

Проблема заключается в том, что когда Angular переключает просмотр, скрипт-тег, который был изначально вставлен, не удаляется из документа. Я исправил это на своем собственном веб-сайте, удалив элемент скрипта Twitter, когда моя директива шкалы времени Twitter не отображается. Смотрите код ниже с комментариями.

 function (scope, el, attrs) {
     el.bind('$destroy', function() {
         var twitterScriptEl = angular.element('#twitter-wjs');
         twitterScriptEl.remove();
     });

     // function provided by Twitter that's been formatted for easier reading
     function (d, s, id) {
         var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https';

         // If the Twitter script element is already on the document this will not get called. On a regular webpage that gets reloaded this isn't a problem. Angular views are loaded dynamically.
         if (!d.getElementById(id)) {
             js = d.createElement(s);
             js.id = id;
             js.src = p + "://platform.twitter.com/widgets.js";
             js.parentNode.insertBefore(js, fjs);
         }
     }(document, "script", "twitter-wjs");        
 }

В основном это то, что говорит Loc Nguyen.

Поэтому каждый раз, когда вы воссоздаете его, вы должны сначала удалить его.

var $ = function (id) { return document.getElementById(id); };
function loadTwitter() {!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");}

var twitter = $('twitter-wjs');
twitter.remove();
loadTwitter(); 

Ответ @b1r3k работает без проблем:

поместите это в свой контроллер:

$timeout(function () { twttr.widgets.load(); }, 500); 

Для тех, кто пытается загрузить twttr.widgets.load() внутри их контроллера вы, скорее всего, получите ошибку, twttr не определен В НЕКОТОРЫХ ТОЧКАХ в вашем UX, потому что асинхронный вызов для загрузки скрипта twitter может быть не завершен к тому времени, когда вы создадите контроллер и создадите ссылки twttr,

Итак, я создал это TwitterService

.factory('TwitterService', ['$timeout', function ($timeout) {
    return {
        load: function () {
        if (typeof twttr === 'undefined') {
            (function() {
                !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
            })();
        } else {
            $timeout = twttr.widgets.load();
        };
        }
    }
}])

а затем позвоните TwitterService.load() внутри контроллеров, которые требуют ваших виджетов. Это сработало довольно хорошо. Это в основном просто проверяет, если twttw объект существует, и если он существует, просто перезагрузите скрипт... в противном случае просто перезагрузите скрипт.

Не уверен, что это лучшая реализация, но кажется, что у всех других решений есть крайние случаи, когда он выдаст ошибку. Я еще не нашел один с этой альтернативой.

Другие вопросы по тегам