我有一个AngularJS指令,可以呈现为自定义社交共享小部件。在每天大约10,000次页面浏览中,大约有1或2次,在开始编译指令后出现Angular错误。这使原始HTML部分保留在DOM中,对用户可见。
我才知道这个错误,因为有几个用户报告过它。我无法重现它,但我设计了一些信息性的日志记录,表明它正在发生。
每次发生这种情况:
多天内某些相同IP发生此错误。
有没有人有过类似的问题?
修改
这是我的代码......
JavaScript的:
(function () {
angular.module('common', []);
angular.module('common')
.filter('encodeURIComponent', function () {
return window.encodeURIComponent;
});
function configure($provide) {
// Pass all Angular errors to Loggly
$provide.decorator("$exceptionHandler", function ($delegate) {
return function exceptionHandlerDecorator(exception, cause) {
$delegate(exception, cause);
_LTracker.push({
'error': 'angularError',
'app': 'shareCounts',
'err': exception,
'element': cause
});
};
});
}
angular.module('common')
.config(['$provide', configure]);
function configure($provide) {
// Defines available share options as well as behaviors of the share popup windows
function shareLinksConfig() {
return {
'facebook': {
width: 670,
height: 200,
urlBase: 'https://www.facebook.com/sharer/sharer.php?',
shareParamPre: 'u=',
msgParamPre: '',
mediaParamPre: '',
addParams: ''
},
'twitter': {
width: 550,
height: 420,
urlBase: 'https://twitter.com/intent/tweet?',
shareParamPre: 'url=',
msgParamPre: '&text=',
mediaParamPre: ''
},
'googlePlus': {
width: 600,
height: 600,
urlBase: 'https://plus.google.com/share?',
shareParamPre: 'url=',
msgParamPre: '',
mediaParamPre: '',
addParams: ''
},
'linkedIn': {
width: 600,
height: 400,
urlBase: 'http://www.linkedin.com/shareArticle?',
shareParamPre: 'url=',
msgParamPre: '',
mediaParamPre: '',
addParams: '&mini=true'
},
'pinterest': {
width: 750,
height: 320,
urlBase: 'https://www.pinterest.com/pin/create/button/?',
shareParamPre: 'url=',
msgParamPre: '&description=',
mediaParamPre: '&media=',
addParams: ''
},
'email': {
width: 0,
height: 0,
urlBase: '',
shareParamPre: '',
msgParamPre: '',
mediaParamPre: '',
addParams: ''
}
};
}
$provide.factory('shareLinksConfig', shareLinksConfig);
}
angular.module('common')
.config(['$provide', configure]);
function ShareLinksController($scope, shareLinksService) {
sendToLoggly.push("A \"ShareLinksController\" started constructing...");
sendToLoggly.push("...and the $scope is typeof...");
sendToLoggly.push(typeof $scope);
var vm = this;
vm.share = function ($event, shareVia) {
if (shareVia !== 'email') {
$event.preventDefault();
// console.log($scope.mediaUrl);
shareLinksService.openPopUp(shareVia, $scope.shareUrl, $scope.shareMsg, $scope.mediaUrl);
}
// Tell Google Analytics share link was clicked
shareLinksService.pushGAEvent($scope.analyticsLocation, shareVia, $scope.shareUrl);
};
$scope.shareLinksShown = true; // Initialized to true, but then this gets set to false in the directive's link function if slideIn is true
vm.toggle = function ($event) {
$event.preventDefault();
$scope.shareLinksShown = !$scope.shareLinksShown;
};
sendToLoggly.push("...and controller finished constructing.");
}
angular.module('common')
.controller('ShareLinksController', ["$scope", "shareLinksService",
ShareLinksController]);
function fuShareLinks($http, shareLinksConfig, testRenderingService) {
function compile() {
sendToLoggly.push("A \"fuShareLinks\" directive started compiling...");
testRenderingService.testShareCounts();
return function postLink(scope) {
sendToLoggly.push("A \"fuShareLinks\" directive started postLinking...");
function Settings(shareVia, slideInDir, slideToggleLabel, colorized, showCounts) {
var self = this,
prop,
splitArray;
/* --------
ShareVia
--------
Comma separated list of ways to share
Accepted options are: 'facebook, twitter, googlePlus, linkedIn, pinterest, email' */
// Copy the properties from the config and initialize to false
self.shareVia = {};
for (prop in shareLinksConfig) {
if (shareLinksConfig.hasOwnProperty(prop)) {
self.shareVia[prop] = false;
}
}
if (typeof shareVia === 'string') {
splitArray = shareVia.split(',');
} else {
splitArray = [];
}
// Check each value of splitArray, if it is in possible share options,
// set that option to true.
angular.forEach(splitArray, function (value) {
// Clean up 'value' a bit by removing spaces
value = value.trim();
if (value.length > 0) {
if (self.shareVia.hasOwnProperty(value)) {
self.shareVia[value] = true;
}
}
});
/* --------
Slide In
--------
The slide-in functionality is activated by passing a value to 'slideInDir'.
Accepted values are 'left' or 'down' (case insensitive)
The 'slideToggleLabel' can be any string, if empty, it defaults to 'Share'. */
self.slideIn = {
direction: '',
label: 'Share'
};
if (typeof slideInDir === 'string') {
slideInDir = slideInDir.toUpperCase();
}
switch (slideInDir) {
case 'LEFT':
self.slideIn.direction = 'left';
break;
case 'DOWN':
self.slideIn.direction = 'down';
break;
}
if (typeof slideToggleLabel === 'string') {
self.slideIn.label = slideToggleLabel;
}
/* ---------
Colorized
---------
'true', 'yes', or 'colorized' (case insensitive) -- results in true
defaults to false */
self.colorized = false;
if (typeof colorized === 'string') {
colorized = colorized.toUpperCase();
}
switch (colorized) {
case 'TRUE':
self.colorized = true;
break;
case 'YES':
self.colorized = true;
break;
case 'COLORIZED':
self.colorized = true;
break;
}
/* -----------
Show Counts
-----------
'true', 'yes', or 'show' (case insensitive) -- results in true
defaults to false */
self.showCounts = false;
if (typeof showCounts === 'string') {
showCounts = showCounts.toUpperCase();
}
switch (showCounts) {
case 'TRUE':
self.showCounts = true;
break;
case 'YES':
self.showCounts = true;
break;
case 'SHOW':
self.showCounts = true;
break;
}
}
scope.settings = new Settings(
scope.shareVia,
scope.slideInDir,
scope.slideToggleLabel,
scope.colorized,
scope.showCounts
);
// Initally hide the share links, if they are set to toggle
if (scope.settings.slideIn.direction !== '') {
scope.shareLinksShown = false;
}
function ShareCounts(shareVia) {
var self = this;
angular.forEach(shareVia, function (value, name) {
self[name] = 0;
});
$http.get(
'/local/social-share-counts/?url=' +
encodeURIComponent(scope.shareUrl)
).success(function (data) {
/* Check for share counts in the returned data.
Must use consistent naming for the social networks
from shareLinksConfig properties all the way to the
JSON data containting the counts.
Expected JSON format:
{
"twitter": {
"count": 42,
"updated": "2015-03-25T15:13:48.355422"
},
"facebook": {
"count": 120,
"updated": "2015-03-25T15:13:47.470778"
}
}
*/
angular.forEach(shareVia, function (value, name) {
if (data[name] && data[name]["count"]) {
self[name] = data[name]["count"];
}
});
}).error(function (data, status) {
sendToLoggly.push("HTTP Response " + status);
});
}
// If showing share counts, get the counts from the specified networks
if (scope.settings.showCounts) {
scope.shareCounts = new ShareCounts(scope.settings.shareVia);
}
sendToLoggly.push("...and directive finished postLinking.");
};
sendToLoggly.push("...and directive finished compiling.");
}
return {
restrict: 'E',
scope: {
shareVia: '@',
shareUrl: '@',
shareMsg: '@',
mediaUrl: '@',
analyticsLocation: '@',
slideInDir: '@',
slideToggleLabel: '@',
colorized: '@',
showCounts: '@'
},
controller: 'ShareLinksController',
controllerAs: 'shrLnksCtrl',
templateUrl: '/angular-partials/common.share-links.html',
compile: compile
};
}
angular.module('common')
.directive('fuShareLinks', ['$http', 'shareLinksConfig', 'testRenderingService', fuShareLinks])
.factory('testRenderingService', function () {
var timerId = null;
function evalShareRender() {
var renderError = (-1 < $('em.ng-binding')
.text()
.indexOf('{{'));
if (renderError) {
console.error('RENDER ERROR');
_LTracker.push({
'error': 'rendering',
'app': 'shareCounts',
'statusMsgs': sendToLoggly,
'userAgent': navigator.userAgent
});
}
}
return {
testShareCounts: function () {
if (!timerId) {
timerId = window.setTimeout(evalShareRender, 5000);
}
}
};
});
function shareLinksService(shareLinksConfig) {
function openPopUp(shareVia, shareUrl, shareMsg, mediaUrl) {
var width,
height,
urlBase,
shareParamPre,
msgParamPre,
mediaParamPre,
addParams,
popUpUrl;
width = shareLinksConfig[shareVia].width;
height = shareLinksConfig[shareVia].height;
urlBase = shareLinksConfig[shareVia].urlBase;
shareParamPre = shareLinksConfig[shareVia].shareParamPre;
msgParamPre = shareLinksConfig[shareVia].msgParamPre;
mediaParamPre = shareLinksConfig[shareVia].mediaParamPre;
addParams = shareLinksConfig[shareVia].addParams;
popUpUrl = encodeURI(urlBase);
popUpUrl += encodeURI(shareParamPre);
popUpUrl += encodeURIComponent(shareUrl);
if (msgParamPre && shareMsg) {
popUpUrl += encodeURI(msgParamPre);
popUpUrl += encodeURIComponent(shareMsg);
}
if (mediaParamPre && mediaUrl) {
popUpUrl += encodeURI(mediaParamPre);
popUpUrl += encodeURIComponent(mediaUrl);
}
popUpUrl += encodeURI(addParams);
// Open the social share window
window.open(popUpUrl, '_blank', 'width=' + width + ',height=' + height);
}
function pushGAEvent(analyticsLocation, shareVia, shareUrl) {
function capitalize(firstLetter) {
return firstLetter.toUpperCase();
}
var gaEventAction = shareVia;
gaEventAction = gaEventAction.replace(/^[a-z]/, capitalize);
gaEventAction += ' - Clicked';
_gaq.push([
'_trackEvent',
analyticsLocation + ' - SocialShare',
gaEventAction,
shareUrl
]);
}
return {
openPopUp: openPopUp,
pushGAEvent: pushGAEvent
};
}
angular.module('common')
.factory('shareLinksService', ['shareLinksConfig', shareLinksService]);
}());
HTML:
<div class="share-links-wrapper" ng-class="{ 'right': settings.slideIn.direction === 'left', 'center': settings.slideIn.direction === 'down' }" ng-cloak>
<a href="#" class="toggle" ng-show="settings.slideIn.direction != ''" ng-click="shrLnksCtrl.toggle($event)">
<i class="fuicon-share"></i>{{ settings.slideIn.label }}
</a>
<div class="share-links" ng-class="{ 'share-links-colorized': settings.colorized }" ng-show="shareLinksShown">
<ul>
<li ng-show="settings.shareVia.facebook">
<a href="#" ng-click="shrLnksCtrl.share($event, 'facebook')"
class="fuicon-hex-facebook">
</a>
<em ng-show="settings.showCounts && shareCounts.facebook > 0">
{{ shareCounts.facebook }}
</em>
</li>
<li ng-show="settings.shareVia.twitter">
<a href="#" ng-click="shrLnksCtrl.share($event, 'twitter')"
class="fuicon-hex-twitter">
</a>
<em ng-show="settings.showCounts && shareCounts.twitter > 0">
{{ shareCounts.twitter }}
</em>
</li>
<li ng-show="settings.shareVia.googlePlus">
<a href="#" ng-click="shrLnksCtrl.share($event, 'googlePlus')"
class="fuicon-hex-googleplus">
</a>
<em ng-show="settings.showCounts && shareCounts.googlePlus > 0">
{{ shareCounts.googlePlus }}
</em>
</li>
<li ng-show="settings.shareVia.linkedIn">
<a href="#" ng-click="shrLnksCtrl.share($event, 'linkedIn')"
class="fuicon-hex-linkedin">
</a>
<em ng-show="settings.showCounts && shareCounts.linkedIn > 0">
{{ shareCounts.linkedIn }}
</em>
</li>
<li ng-show="settings.shareVia.pinterest && mediaUrl">
<a href="#" ng-click="shrLnksCtrl.share($event, 'pinterest')"
class="fuicon-hex-pinterest">
</a>
<em ng-show="settings.showCounts && shareCounts.pinterest > 0">
{{ shareCounts.pinterest }}
</em>
</li>
<li ng-show="settings.shareVia.email">
<a href="mailto:?subject={{ shareMsg | encodeURIComponent }}
&body={{ shareUrl | encodeURIComponent }}"
ng-click="shrLnksCtrl.share($event, 'email')"
class="fuicon-hex-email">
</a>
</li>
</ul>
</div>
</div>
答案 0 :(得分:0)
没有这样的问题,但是如此罕见,你可以让它重新加载页面吗?
另外,你知道ng-cloak吗?隐藏原始内容可能很有用:)
这可能是竞争条件吗?