Angular JS 无法在页面/路由更改时呈现社交媒体小部件 [英] Angular JS can't render Social Media widgets on page/route change
问题描述
我正在创建一个 Angular 应用程序,它对 Drupal CMS 系统进行 ajax 调用以获取一些内容.其中一些内容包括来自 Facebook、Twitter、Instagram 和 Youtube 的小部件.
I'm creating a Angular App which makes an ajax call to a Drupal CMS system to get some content. Some of this content includes widgets from Facebook, Twitter, Instagram and Youtube.
ajax 调用是通过 postsController
和 postsService
完成的.
The ajax call is done with a postsController
and postsService
.
我无法正确呈现这些社交媒体小部件.当有人直接进入带有小部件的页面时,我已经让它们正确呈现,但如果他们更改路线(页面视图),则小部件将无法加载.我相信这是因为 API 使用的脚本仅在页面加载事件上运行.
I'm having trouble getting these social media widgets to render correctly. I've got them to render correctly when some one goes directly to the page with the widgets but if they change the route (page view) the widgets won't load. I believe this is because the script the API uses only runs on the page load event.
起初 angular 根本没有渲染小部件,但我做了两件事让它工作.
At first angular didn't render the widgets at all but I did two things to get it working.
- 我将指向 API javascript 的 CDN 链接放在 wach API 的头部,例如
/platform.twitter.com/widgets.js
- 我使用名为
compileAjax
的自定义指令对从 Drupal 获取的数据进行了 angular 重新编译
- I put the CDN link to the API javascript in the head for wach API e.g.
/platform.twitter.com/widgets.js
- I made angular re-compile the data I fetched from Drupal once it changed with a custom directive I named
compileAjax
当用户更改视图/路线时,我该怎么做才能呈现这些内容?
以下是 html
文档中代码的屏幕截图和示例,其中在单个 html
文档中复制了问题.小部件在页面加载时正确呈现,但在您单击 转到页面 链接之一时无法正确呈现.
Below is a screenshot and sample of the code in a html
doc in which the issue is replicated in a single html
doc. The widgets render correctly on page load but not when you click one of the Go to Page links.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.9/angular-sanitize.min.js"></script>
<script src="https://code.angularjs.org/1.5.9/angular-route.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>
<script>
var app = angular.module('app', ['ngSanitize','ngRoute']);
app.config(function($routeProvider) {
$routeProvider.when('/page1', {
controller: 'postsController as postsCtrl',
templateUrl: 'page1.htm'
}).when('/page2', {
controller: 'postsController as postsCtrl',
templateUrl: 'page2.htm'
})
.otherwise({ redirectTo: '/page1' });
});
app.controller('postsController', ['postsService',function(postsService) {
var postsCtrl = this;
postsCtrl.test = 'this is an expression from the controller'
var promise = postsService.getPost(1);
promise.then(function(data) {
postsCtrl.data = data.data;
// I can't access the API on SO so am replicating what I would get from it here.
postsCtrl.twitter = "<div data-oembed-url=\"https:\/\/twitter.com\/NatGeo\/status\/811610711671656448\">\n<div style=\"max-width:320px;margin:auto;\">\n<blockquote align=\"center\" class=\"twitter-tweet\">\n<p dir=\"ltr\" lang=\"en\" xml:lang=\"en\">Polar bears are just one of the animals that will benefit from President Obamas\u00a0recent ban on oil drilling <a href=\"https:\/\/t.co\/MX4ZnX7TNw\">https:\/\/t.co\/MX4ZnX7TNw<\/a><\/p>\n\u2014 National Geographic (@NatGeo) <a href=\"https:\/\/twitter.com\/NatGeo\/status\/811610711671656448\">December 21, 2016<\/a><\/blockquote>\n<script async=\"\" charset=\"utf-8\" src=\"\/\/platform.twitter.com\/widgets.js\"><\/script><\/div>\n<\/div>";
postsCtrl.facebook = "<div data-oembed-url=\"https:\/\/www.facebook.com\/natgeo\/posts\/10154212815083951\">\n<div id=\"fb-root\">\u00a0<\/div>\n<script>\n<!--\/\/--><![CDATA[\/\/ ><!--\n(function(d, s, id) {\n var js, fjs = d.getElementsByTagName(s)[0];\n if (d.getElementById(id)) return;\n js = d.createElement(s); js.id = id;\n js.src = \"\/\/connect.facebook.net\/en_US\/sdk.js#xfbml=1&version=v2.3\";\n fjs.parentNode.insertBefore(js, fjs);\n}(document, 'script', 'facebook-jssdk'));\n\/\/--><!]]>\n<\/script><div class=\"fb-post\" data-href=\"https:\/\/www.facebook.com\/natgeo\/posts\/10154212815083951\" data-width=\"550\">\n<blockquote cite=\"https:\/\/www.facebook.com\/natgeo\/posts\/10154212815083951\" class=\"fb-xfbml-parse-ignore\">\n<p>Inhumane and unsafe, snake wine is often made by drowning a live snake in alcohol. Before you purchase a gift abroad, here are a few things to know.<\/p>\nPosted by <a href=\"https:\/\/www.facebook.com\/natgeo\/\">National Geographic<\/a> on\u00a0<a href=\"https:\/\/www.facebook.com\/natgeo\/posts\/10154212815083951\">Wednesday, December 21, 2016<\/a><\/blockquote>\n<\/div>\n<\/div>"
postsCtrl.instagram = "<div data-oembed-url=\"https:\/\/www.instagram.com\/p\/BOTfVSFDgn-\/?taken-by=natgeo&hl=en\">\n<div style=\"max-width:320px;margin:auto;\"><!-- You're using demo endpoint of Iframely API commercially. Max-width is limited to 320px. Please get your own API key at https:\/\/iframely.com. -->\n<blockquote class=\"instagram-media\" data-instgrm-version=\"7\" style=\" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);\">\n<div style=\"padding:8px;\">\n<div style=\" background:#F8F8F8; line-height:0; margin-top:40px; padding:50.0% 0; text-align:center; width:100%;\">\n<div style=\" background:url(data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAABGdBTUEAALGPC\/xhBQAAAAFzUkdCAK7OHOkAAAAMUExURczMzPf399fX1+bm5mzY9AMAAADiSURBVDjLvZXbEsMgCES5\/P8\/t9FuRVCRmU73JWlzosgSIIZURCjo\/ad+EQJJB4Hv8BFt+IDpQoCx1wjOSBFhh2XssxEIYn3ulI\/6MNReE07UIWJEv8UEOWDS88LY97kqyTliJKKtuYBbruAyVh5wOHiXmpi5we58Ek028czwyuQdLKPG1Bkb4NnM+VeAnfHqn1k4+GPT6uGQcvu2h2OVuIf\/gWUFyy8OWEpdyZSa3aVCqpVoVvzZZ2VTnn2wU8qzVjDDetO90GSy9mVLqtgYSy231MxrY6I2gGqjrTY0L8fxCxfCBbhWrsYYAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-22px; width:44px;\">\u00a0<\/div>\n<\/div>\n\n<p style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;\"><a href=\"https:\/\/www.instagram.com\/p\/BOTfVSFDgn-\/\" style=\" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none;\" target=\"_blank\">A photo posted by National Geographic (@natgeo)<\/a> on <time datetime=\"2016-12-22T03:35:07+00:00\" style=\" font-family:Arial,sans-serif; font-size:14px; line-height:17px;\">Dec 21, 2016 at 7:35pm PST<\/time><\/p>\n<\/div>\n<\/blockquote>\n<script async=\"\" defer=\"defer\" src=\"\/\/platform.instagram.com\/en_US\/embeds.js\"><\/script><\/div>\n<\/div>\n\n<p>\u00a0<\/p>";
postsCtrl.youtube = "<div data-oembed-url=\"https:\/\/youtu.be\/G51LtqmZKto\">\n<div style=\"max-width:320px;margin:auto;\"><!-- You're using demo endpoint of Iframely API commercially. Max-width is limited to 320px. Please get your own API key at https:\/\/iframely.com. -->\n<div>\n<div style=\"left: 0px; width: 100%; height: 0px; position: relative; padding-bottom: 56.2493%;\"><iframe allowfullscreen=\"\" frameborder=\"0\" src=\"https:\/\/www.youtube.com\/embed\/G51LtqmZKto?wmode=transparent&rel=0&autohide=1&showinfo=0&enablejsapi=1\" style=\"top: 0px; left: 0px; width: 100%; height: 100%; position: absolute;\" tabindex=\"-1\"><\/iframe><\/div>\n<\/div>\n<\/div>\n<\/div>\n\n<p>\u00a0<\/p>\n<\/div>\n \n<\/div>"
postsCtrl.slider = "<div class=\"slick-slider\">\n \n <div>Service Slide 1<\/div>\n \n <div>Service Slide 2<\/div>\n \n <div>Service Slide 3<\/div>\n \n <\/div>";
});
}]);
app.service("postsService", function($http, $q) {
function getPost(postsId) {
var deferred = $q.defer()
var url = 'https://jsonplaceholder.typicode.com/albums/' + postsId;
$http({
method: 'GET', // GET OPTIONS
cache: true,
url: url,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
}).then(function(response) {
//your code when success
deferred.resolve(response);
}, function(response) {
//your code when fails
deferred.reject(response);
});
return deferred.promise;
}
this.getPost = getPost;
});
app.directive('compileAjax', function($compile) {
return {
restrict: 'A',
replace: true,
link: function(scope, elem, attrs) {
scope.$watch(attrs.compileAjax, function(html) {
elem[0].innerHTML = html;
$compile(elem.contents())(scope);
});
}
}
});
app.directive('slickSlider', function() {
return {
restrict: 'C',
link: function(scope, elem, attrs) {
$(elem).slick({
// settings
});
}
}
});
</script>
<script src="//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.5"
async></script>
<script async="" defer="defer" src="//platform.instagram.com/en_US/embeds.js"></script>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</head>
<body>
<body ng-app="app" ng-controller="postsController as postsCtrl">
<script type="text/ng-template" id="page1.htm">
<h2>You're on Page 1</h2>
<a href="#page1">Go to page 1</a>
<a href="#page2">Go to page 2</a>
<div compile-ajax="postsCtrl.twitter"></div>
<div compile-ajax="postsCtrl.facebook"></div>
<div compile-ajax="postsCtrl.instagram"></div>
<div compile-ajax="postsCtrl.youtube"></div>
<div compile-ajax="postsCtrl.slider"></div>
</script>
<script type="text/ng-template" id="page2.htm">
<h2>You're on Page 2</h2>
<a href="#page1">Go to page 1</a>
<a href="#page2">Go to page 2</a>
<div compile-ajax="postsCtrl.twitter"></div>
<div compile-ajax="postsCtrl.facebook"></div>
<div compile-ajax="postsCtrl.instagram"></div>
<div compile-ajax="postsCtrl.youtube"></div>
<div compile-ajax="postsCtrl.slider"></div>
</script>
<div ng-view></div>
</body>
</body>
</html>