Components and Directives¶
The Stratpoint Timesheet Application uses custom AngularJS directives defined directly on the main StratpointTSApp module. All directives are implemented in /public/app/js/mine/directives.js. This section details the actual custom directives and their implementation.
Actual Directive Implementation¶
All Directives are Defined On Main Module¶
// All directives are defined directly on StratpointTSApp in /public/app/js/mine/directives.js
StratpointTSApp
.directive('directiveName', function() {
// Implementation
})
Loading Management¶
Loading Container Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('loadingContainer', function () {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attrs) {
var loadingLayer = angular.element('<div class="loading"></div>');
element.append(loadingLayer);
element.addClass('loading-container');
scope.$watch(attrs.loadingContainer, function(value) {
loadingLayer.toggleClass('ng-hide', !value);
});
}
};
})
Usage:
Permission Management¶
Permission-Based Visibility Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('hasPermission', ["Authenticate", function(Authenticate) {
return {
link: function(scope, element, attrs) {
if(!angular.isString(attrs.hasPermission))
throw "hasPermission value must be a string";
var value = attrs.hasPermission.trim();
var notPermissionFlag = value[0] === '!';
if(notPermissionFlag) {
value = value.slice(1).trim();
}
function toggleVisibilityBasedOnPermission() {
var hasPermission = Authenticate.hasPermission(value);
if( !(hasPermission && !notPermissionFlag || !hasPermission && notPermissionFlag ) ){
element.remove();
}
}
toggleVisibilityBasedOnPermission();
scope.$on('permissionsChanged', toggleVisibilityBasedOnPermission);
}
};
}])
Usage:
<!-- Hide element if user doesn't have permission -->
<button has-permission="72">Approve Timelogs</button>
<!-- Hide element if user HAS permission (negation) -->
<div has-permission="!57">You don't have basic access</div>
<!-- Permission IDs are numeric strings -->
<div has-permission="94">Project Management</div>
Form Validation¶
Field Matching Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('match', function () {
return {
require: 'ngModel',
restrict: 'A',
scope: {
match: '='
},
link: function(scope, elem, attrs, ctrl) {
scope.$watch(function() {
var modelValue = ctrl.$modelValue || ctrl.$$invalidModelValue;
return (ctrl.$pristine && angular.isUndefined(modelValue)) || scope.match === modelValue;
}, function(currentValue) {
ctrl.$setValidity('match', currentValue);
});
}
};
})
Usage:
<input type="password" ng-model="password" name="password">
<input type="password" ng-model="confirmPassword" match="password" name="confirmPassword">
Number Conversion Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('convertToNumber', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(val) {
return val != null ? parseInt(val, 10) : null;
});
ngModel.$formatters.push(function(val) {
return val != null ? '' + val : null;
});
}
};
})
Usage:
Data Export¶
CSV Export Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('exportCsv', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var fn = $parse(attrs.exportCsv);
element.on('click', function (event) {
scope.$apply(function () {
fn(scope, {$event: event});
});
});
}
};
}])
Usage:
Template Management¶
Static Include Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('staticInclude', ["$http", "$templateCache", "$compile", function($http, $templateCache, $compile) {
return {
restrict: 'A',
transclude: true,
link: function(scope, element, attrs) {
var templatePath = attrs.staticInclude;
$http.get(templatePath, {cache: $templateCache}).success(function(response) {
element.html(response);
$compile(element.contents())(scope);
});
}
};
}])
Usage:
UI Enhancement¶
Table Enhancement Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('table', ["$compile", "$timeout", function($compile, $timeout) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
// Add responsive table wrapper
if (!element.parent().hasClass('table-responsive')) {
element.wrap('<div class="table-responsive"></div>');
}
// Add Bootstrap table classes
element.addClass('table table-striped table-hover');
// Add sorting indicators to headers
$timeout(function() {
element.find('th[data-sortable]').each(function() {
var header = angular.element(this);
if (!header.find('.sort-indicator').length) {
header.append('<span class="sort-indicator"><i class="fa fa-sort"></i></span>');
}
});
});
}
};
}])
Permission Panel Height Adjustment Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('adjustPermissionPanelHeight', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
$timeout(function() {
var windowHeight = $(window).height();
var panelOffset = element.offset().top;
var availableHeight = windowHeight - panelOffset - 100; // 100px buffer
element.css('max-height', availableHeight + 'px');
element.css('overflow-y', 'auto');
}, 100);
}
};
}])
Navigation¶
Confirmation Redirect Directive¶
// From /public/app/js/mine/directives.js
StratpointTSApp
.directive('confirmRedirect', ["$q", "$uibModal", "$location", "$timeout", function($q, $uibModal, $location, $timeout) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.on('click', function(event) {
event.preventDefault();
var modalInstance = $uibModal.open({
template: '<div class="modal-header"><h3>Confirm Navigation</h3></div>' +
'<div class="modal-body"><p>Are you sure you want to leave this page?</p></div>' +
'<div class="modal-footer">' +
'<button class="btn btn-primary" ng-click="ok()">Yes</button>' +
'<button class="btn btn-default" ng-click="cancel()">Cancel</button>' +
'</div>',
controller: function($scope, $uibModalInstance) {
$scope.ok = function() {
$uibModalInstance.close();
};
$scope.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
}
});
modalInstance.result.then(function() {
$location.path(attrs.confirmRedirect);
});
});
}
};
}])
Usage:
Summary¶
All directives in the Stratpoint Timesheet Application are:
- Defined directly on StratpointTSApp module (no separate directive modules)
- Located in single file:
/public/app/js/mine/directives.js - Focused on specific functionality: permissions, forms, UI enhancement, data export
- Tightly integrated with the application's authentication and UI patterns
The directives provide essential functionality for: - Permission-based UI control - Form validation and enhancement - Loading state management - Data export capabilities - Template inclusion - UI improvements and responsive behavior