In AngularJS, I currently have a directive and 2 services which permit me to bind the window resize event, and broadcast it to my application.
I would like to know if you could see anything that could be improved in my code, in term of optimization, naming or possible cross browser issues.
I have:
- A directive which binds resize event. It will broadcast the event 300ms after the last resize (to avoid flood).
- A factory to get window's dimensions
- A service to detect browser's name (chrome, safari, etc...). In this case, it is used to target Safari which doesn't calculate window's dimensions the same way.
Here is a plunkr to illustrate the code.
Detect Browser Service
/*
* Detects on which browser the user is navigating
*
* Usage:
* var browser = detectBrowser();
*
*/
commonApp.service('detectBrowser', ['$window',
function( $window ) {
// http://stackoverflow.com/questions/22947535/how-to-detect-browser-using-angular
return function() {
var userAgent = $window.navigator.userAgent,
browsers = {
chrome : /chrome/i,
safari : /safari/i,
firefox : /firefox/i,
ie : /internet explorer/i
};
for ( var key in browsers ) {
if ( browsers[key].test(userAgent) ) {
return key;
}
}
return 'unknown';
}
}]);
Window Dimensions Factory
/*
* Get window height and width
*
* Usage:
* windowDimensions.height();
* windowDimensions.width();
*
*/
commonApp.factory('windowDimensions', ['$window', 'detectBrowser',
function( $window, detectBrowser ) {
var browser = detectBrowser();
return {
height: function() {
return ( browser === 'safari' )
? document.documentElement.clientHeight
: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
},
width : function() {
return ( browser === 'safari' )
? document.documentElement.clientWidth
: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
}
}
}]);
Window Resize Event Directive
/*
* Watch window resizing event to set new window dimensions,
* and broadcast the event to the app
*
* Usage:
* <html watch-window-resize>...</html>
*
* Bind the resize event:
$scope.$on('watchWindowResize::resize', function() {
// Do something
});
*
*/
app.directive('watchWindowResize', ['$window', '$timeout', 'windowDimensions',
function( $window, $timeout, windowDimensions ) {
return {
link: function( $scope ) {
// Get window's dimensions
$scope.getDimensions = function() {
// Namespacing events with name of directive + event to avoid collisions
// http://stackoverflow.com/questions/23272169/what-is-the-best-way-to-bind-to-a-global-event-in-a-angularjs-directive
$scope.$broadcast('watchWindowResize::resize', {
height: windowDimensions.height(),
width : windowDimensions.width()
});
}
// On window resize...
angular.element($window).on('resize', function( e ) {
// Reset timeout
$timeout.cancel($scope.resizing);
// Add a timeout to not call the resizing function every pixel
$scope.resizing = $timeout( function() {
$scope.getDimensions();
}, 300);
});
}
}
}]);