Org Chart Widget with Modal
Options
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎05-20-2025 09:33 AM
Hello I am trying to build a portal org chart widget with a popup modal. the idea is that when you click the menu next to the persons name.
this widget will popup with the persons info
I've been working on this for a while and just cant seem to find the problem. when I click the menu it just pops up like this
Here is my code for the org chart widget
<div class="org-chart">
<!-- Manager -->
<div class="user-card manager-card">
<div class="kebab-menu" ng-click="openMenu($event, data.user)">⋮</div>
<div class="card-content">
<div class="avatar-wrapper">
<div ng-if="!data.user.photo" class="initials">{{getInitials(data.user.name)}}</div>
</div>
<div class="info">
<div class="name">{{data.user.name}}</div>
<div class="title">{{data.user.title}}</div>
</div>
</div>
</div>
<div class="line"></div>
<!-- Reports -->
<div class="reports-container">
<div class="user-card report-card" ng-repeat="rep in data.reports">
<div class="kebab-menu" ng-click="openMenu($event, rep)">⋮</div>
<div class="card-content">
<div class="avatar-wrapper">
<div ng-if="!rep.photo" class="initials">{{getInitials(rep.name)}}</div>
</div>
<div class="info">
<div class="name">{{rep.name}}</div>
<div class="title">{{rep.title}}</div>
</div>
</div>
</div>
</div>
</div>
<!-- Optional hidden instance -->
<div style="display: none;">
<sp-widget widget="data.employeeDetailsWidget"></sp-widget>
</div>
//Client script
function($scope, $uibModal) {
$scope.getInitials = function(fullName) {
if (!fullName) return '';
let names = fullName.trim().split(' ');
let initials = names[0].charAt(0);
if (names.length > 1) {
initials += names[names.length - 1].charAt(0);
}
return initials.toUpperCase();
};
$scope.openMenu = function(event, user) {
event.stopPropagation();
console.log("Opening modal for user sys_id:", user.sys_id);
$scope.openMenu = function(event, user) {
event.stopPropagation();
$uibModal.open({
size: 'lg',
windowClass: 'employee-details-modal',
template: `
<div class="modal-header">
<h4 class="modal-title">Employee Details</h4>
<button type="button" class="close" ng-click="close()">×</button>
</div>
<div class="modal-body">
<sp-widget widget="data.modalWidget"></sp-widget>
</div>
`,
controller: function($scope, $uibModalInstance) {
$scope.data = {
modalWidget: {
sys_id: 'a73327b683e56a104e1bc296feaad3e6', // Your widget sys_id
options: {
user_sys_id: user.sys_id
}
}
};
$scope.close = function() {
$uibModalInstance.dismiss();
};
}
});
};
};
}
//Server Script
(function() {
var currentUser = gs.getUserID();
var userGR = new GlideRecord('sys_user');
if (userGR.get(currentUser)) {
data.user = {
name: userGR.name.toString(),
title: userGR.title.toString(),
photo: userGR.photo ? userGR.photo.toString() : '',
sys_id: userGR.getUniqueValue()
};
}
data.reports = [];
var repGR = new GlideRecord('sys_user');
repGR.addQuery('manager', currentUser);
repGR.query();
while (repGR.next()) {
data.reports.push({
name: repGR.name.toString(),
title: repGR.title.toString(),
photo: repGR.photo ? repGR.photo.toString() : '',
sys_id: repGR.getUniqueValue()
});
}
// Optional: define hidden widget instance (unused, safe fallback)
data.employeeDetailsWidget = {
sys_id: 'e08f190a83a166104e1bc296feaad334',
options: {
user_sys_id: currentUser
}
};
})();
And the script for the modal widget
<div class="modal-header">
<h4 class="modal-title">{{data.name}}</h4>
<button type="button" class="close" ng-click="close()">×</button>
</div>
<div class="modal-body">
<div class="employee-details">
<div class="header-container">
<div class="user-avatar">
<img ng-if="data.profileImage" ng-src="{{data.profileImage}}" alt="User photo" />
<div ng-if="!data.profileImage" class="avatar-initials">{{data.initials}}</div>
</div>
<div class="user-info">
<h2 class="user-name">{{data.name}}</h2>
<p class="user-title">{{data.title}}</p>
</div>
</div>
<div class="contact-info">
<div class="contact-item">
<div class="contact-label"><span class="location-icon"></span> Location:</div>
<div class="contact-value">{{data.location}}</div>
</div>
<div class="contact-item">
<div class="contact-label">📧 Email:</div>
<div class="contact-value">
<a href="mailto:{{data.email}}">{{data.email}}</a>
</div>
</div>
<div class="contact-item">
<div class="contact-label">📞 Work phone:</div>
<div class="contact-value">{{data.phone}}</div>
</div>
</div>
</div>
</div>
//Server script
(function() {
var userId;
if (typeof input !== 'undefined' && input.options && input.options.user_sys_id) {
userId = input.options.user_sys_id;
} else if (typeof options !== 'undefined' && options.user_sys_id) {
userId = options.user_sys_id;
} else {
userId = gs.getUserID(); // fallback to logged-in user
}
var userGR = new GlideRecord('sys_user');
if (!userGR.get(userId)) {
data.name = "Invalid user";
return;
}
data.name = userGR.getDisplayValue();
data.title = userGR.title + '';
data.email = userGR.email + '';
data.phone = userGR.phone + '';
data.location = userGR.location ? userGR.location.getDisplayValue() : 'Not specified';
var names = data.name.trim().split(' ');
data.initials = names.length >= 2
? names[0].charAt(0) + names[names.length - 1].charAt(0)
: data.name.substring(0, 2);
data.initials = data.initials.toUpperCase();
var photo = new GlideUser(userGR.sys_id.toString()).getPhoto();
data.profileImage = (photo && photo.indexOf("photo.do") !== -1) ? photo : null;
})();
Any Assistance would be appreciated.
0 REPLIES 0