ServiceNow: Widgets, Portals, Pages and more
6/7/2025
Recently I was asked a hypothetical question about how I would build an application in ServiceNow. The request was : how would you go about building an application for a clinic, where the patients need to be able to book appointments with the doctors.
Hmm, I thought. Where do I even begin?!
I said that I would start by setting up my tables, and think about the data that I need to put in them. I would need to think about the relationships between these tables and also how to present this application to the end users, the patience. I would also need to think about implementing a flow that would manage the processes after an appointment would have been submitted. And also I would have to think about the customer experience, implement notifications, reminders and surveys. Pff! That would be a lot to think about.
Since that was kind of a short conversation, I felt like I did not really manage to grasp or to really see this application with my mind's eye. Sidenote: I do not always have all my words with myself, I usually think about a conversation and I redo it but this time using the better words.
So I went ahead and built it!
I think that I have a pretty good first version. I’m thinking of keeping tinkering at it, until I have an even better version.
This first version has to do with creating a new portal, adding pages, building widgets and placing them on those pages. Of course, before doing that, I built a new application in a private scope, created a few tables : u_doctors, u_patients, u_appointments, u_timeslots.
Here are the main difficulties I had, as a newbie in ServiceNOw portal widgets building. For this part, I am making use of a very intelligent presence - ChatGPT - who also guided me through the steps and helped solve some issues.
Second sidenote: I am thinking that I am not a real developer, I would rather call myself a problem solver. Someone who is using the tools that are available in order to achieve some results. In my mind, a developer is someone who can solve those problems relying mostly on their own skills and experience. Since I am not that rich in such things, I would prefer to just be a problem solver for now. But this is probably a story for another time.
So here is the technical scheltelon of the Clinic app:
. Data Model & Roles
-
Table Structure: I created 4 custom tables (u_doctor, u_patient, u_timeslot, u_appointment) including field names, types, references, mandatory flags, and system fields.
-
Roles/ACLs: At this stage,I did not dive too deep in security matters. I will probably be creating new specific roles in the near future.
2. Service Portal Setup
-
New Portal: I created a new “Doctor Appointment Portal.
3. Pages & Navigation
-
Homepage Routing: You needed to point the portal’s Homepage to your custom Doctor Home page so your widgets would actually appear.
-
Portal Pages: I created the pages as I was building the widgets and realizing that I need a page to place them 🙂 Probably not the best way but this is how I roll 🙂
4. Widgets & Client-Server Scripts
When it comes to the widgets, I again jumped right in it, and I understood in the process that the client script is getting the data from the server script. The server script is sending this data via the data object. The HTML is receiving the data via the Angular directives.
Server Script → data object
In my All doctors widget, I used :
Client Script → controller (alias c)
Defines an Angular controller that Angular bootstraps for the widget:
HTML uses Angular directives to display the data:
I am not familiar with Angular but this way of displaying data is very similar to what I did with Python and displaying data from the backend in forms using Jinja ( a templating language) , also accepting user input via http requests. I suppose that Angular is doing and functions in the same way.
Widgets details
-
Doctor List Widget
-
GlideRecord query in the Server Script against the scoped doctor table, filtering by u_active, sorting, and populating data.doctors.
-
Angular controller in the Client Script, registered under DoctorListController as c, and wiring up c.selectDoctor(sys_id) to navigate to the profile page.
-
Troubleshooting “ReferenceError: DoctorListController is not defined” by ensuring the Controller As field was set correctly, that the controller wrapper function existed, and busting caches.
-
Doctor Profile Widget
-
Reading $sp.getParameter('sys_id') in the server script to fetch the selected doctor record, exposing data.doctor, and rendering name, photo, bio in the HTML.
-
$sp - I learned that this is a server side API object for portals.
-
In order to get parameters in a client side script, the $location object would need to be used: var sysId = $location.search().sys_id;
-
Doctor Availability Widget
-
Server script fetching available timeslots for that doctor, pushing data.events for FullCalendar.
-
I learned that FullCalendar is a open-source JavaScript library and it’s pretty interesting. https://fullcalendar.io/
-
Exposing data.sys_id so the calendar’s id="calendar-{{c.data.sys_id}}" could be found.
-
Client script instantiating FullCalendar, wiring eventClick to navigate to the booking form.
This was overall an interesting project and I was happy to work on it. As I said, I used AI to solve some issues and find the way out. In my ideal version of myself, I would know how to solve all the issues just by using my brian, but that is unfortunately not the case.
I am looking forward to the next version, when I will be using Flow Designer, sending emails, notifications and reminders to the doctors and patients .
I’ll let you know about it 🙂