There are several ways to do time tracking in ServiceNow. One of the ways used frequently (especially in Incident Management) is the ‘Time Worked’ field. The ServiceNow wiki describes this functionality. I often see the requirement to have some control over the stop/start of this Time Worked field for customers using this functionality. This post describes the approaches I’ve used in the past to meet this need.
Default Start/Stop state for Time Worked field for ALL Tasks
ServiceNow includes a simple property that allows you to specify whether the time worked timer should be started or paused when a task form loads. This property might meet the needs of some customers, but lacks the needed flexibility for most people using the time worked field. The property name is ‘glide.ui.timer.started’ and can be accessed under the ‘UI Properties’ module as shown here…
Toggle Time Worked Client Script
If you need the additional flexibility of starting or stopping the time worked field for particular task types or even for particular states in given task types, you need to use a client script to start and stop the timer. One common requirement I’ve seen for this is to have the timer always be stopped if the form loads for an already-closed or resolved incident ticket. For this scenario, you could use the script I’ve created below. The script I’ve written takes 2 parameters…the first takes the name of the timer field you want to start or stop, and the second parameter (which is optional) allows you to set the timer to a specific time if needed.
if(g_form.getElement('time_worked')){
toggleTimer('time_worked','00:00:00');
}
}
function toggleTimer(fieldName,timerVal){
try{
//Get the necessary timer elements for fieldName given
var timerEl = $('element.' + g_form.tableName + '.' + fieldName);
var timerIcon = $('link.' + g_form.tableName + '.' + fieldName);
if (timerEl != null){
//Make sure script does not break if field not present
var timerPause = timerEl.select('input[id*=paused]')[0];
//Toggle the timer
if(timerPause.value == 'false'){
timerPause.value = 'true';
timerIcon = $('link.' + g_form.tableName + '.' + fieldName);
timerIcon.removeClassName('icon-stop');
timerIcon.addClassName('icon-play');
}
else{
timerPause.value = 'false';
timerIcon.removeClassName('icon-play');
timerIcon.addClassName('icon-stop');
}
//Reset the timer to timerVal given
if(timerVal){
g_form.setValue(fieldName,timerVal);
}
}
}catch(e){}
}
This works well but I see one issue I’m hoping you can help with. The time worked toggle button does not show as play unless you’ve already started/stopped the timer. Is there a way to change the default button that appears?
The only way is to use the script or the property described above. In my testing on the Service-now demo instance the script toggled the timer correctly on load and changed the icon.
Try changing the timerImg variable to call the second IMG in the code. The code has a 1×1 pixel image in addition to the stop/start gifx that defaults to stop.gifx. This works for me on a client today and on sandbox of ours.
Or, another approach that will allow this to always find the img where timer_stop exists from the beginning do this:
var imgs = timerEl.select('img');
for(var i = 0; i < imgs.length; i++) {
if(imgs[i].src.indexOf('images/timer_stop.gifx') >= 0) {
timerImg = imgs[i];
break;
}
}
Thanks for the tip. I’ve never seen one with a spacer image, and I don’t see it on demo currently so it must just exist in certain builds. In any case, it’s worth targeting that element more specifically so that you make sure you get the right one. I think if you change the line I had before…
To this…
It will always get the true timer image. I’ve updated the code in the original article above to reflect this change. If that doesn’t work, please post the ‘src’ value of that spacer image here and I’ll modify the code a bit more if necessary.
Hi Mark,
Thanks for the good script, it works great, but there is a small hazard. If someone puts this script on the task table with inherited checked, the script will blowup on tables/forms that dont have time_worked and stop everything else (all other client scripts and ui policies) from loading. This happened at a client of mine. With a small check, you can stop this from happening:
[code]
function onLoad() {
toggleTimer(‘time_worked’,’00:00:00′);
}
function toggleTimer(fieldName,timerVal){
//Get the necessary timer elements for fieldName given
var timerEl = $(‘element.’ + g_form.tableName + ‘.’ + fieldName);
if (timerEl != null) { // Added in case the field does not exist on the form
var timerPause = timerEl.select(‘input[id*=paused]’)[0];
var timerImg = timerEl.select(‘img[src*=images/timer_]’)[0];
//Toggle the timer
if(timerPause.value == ‘false’){
timerPause.value = ‘true’;
timerImg.src = ‘images/timer_start.gifx’;
}
else{
timerPause.value = ‘false’;
timerImg.src = ‘images/timer_stop.gifx’;
}
}
//Reset the timer to timerVal given
if(timerVal){
g_form.setValue(fieldName,timerVal);
}
}
[/code]
Thanks, that’s a good improvement! I’ve updated the code above to make the same check.
Mark (or anyone),
I have a case where the client does not want the ITIL user to be able to change the hours or minutes. The seconds are already read only.
How can you do this?
Dan
You have to use a client script to disable those. It can be done, but it’s kind of a tricky script. You can place these lines in a client script to disable the minutes and hours.
$('element.incident.time_worked').select('input[title="Hours"]')[0].disable();
//Disable minutes
$('element.incident.time_worked').select('input[title="Minutes"]')[0].disable();
Hello Mark,
Thanks for Such great Script 🙂
I am trying to apply this script in Domain separated environment.
I have created a Client Script in Global Domain and applied it on Task Table.
but unfortunately this script doesn’t work on “Task [task]” table, Time Worked field is not stopped in any of the domain including global domain as well.
.
However if I modify same client script by just changing the Tables then it works perfectly. I use it on individual table Like Incident , Change, Problem, Change_task, Problem_Task etc.. then Time Worked field stops on all domains.
what could be the reason for it?
if it doesn’t worked on task table then I have to create 6 client scripts the different tables 🙁
Thanks in advance,
Regards,
Shashank J
I’ve used this in several domain separated environments in the past and it’s designed to work for all task tables. I’m not sure why it’s not working in your system, but I’d check the browser console for errors if I were you. That should point you to the issue (whether it’s this script or something else that’s breaking and causing this one not to run).
Hi Mark,
thanks for this starting point. Seems in Fuji with UI15 we have change a bit the UI… there is no more IMG attribute and therefor this part of the code does not work anymore.
I have now replace this with the following piece:
$(“link.problem.time_worked”).removeClassName(‘icon-stop’);
$(“link.problem.time_worked”).addClassName(‘icon-play’);
This seems to do the trick 🙂
Daniel
Thanks Daniel, I’ve been meaning to get my Fuji version of this code out here for a while. You’re correct. I’ve added a fully-working Fuji script above.
I am using this on Geneva now. Thank you for sharing this with the community. The flexibility that this provides is really helpful.
Thanks for sharing this Mark. The Fuji version has solved my issue almost completely. I’m on Helsinki and there’s now a message bubble that comes up above the icon when you hover. Do you know how I can change that to show the correct message “Start Timer” instead of “Pause Timer” which is what it defaults to?
Thanks for letting me know Cheryl! I’ve updated the script so that it will handle the Helsinki tooltips. Please give it a try and let me know how it works.
Hi Mark,
I am new to ServiceNow .I have a query. I need to pause time worked timer whenever task is completed.I have used Type = OnChange/ Field Name = State and have used same script.But I need to know how it will determine to pause the timer field when state is Completed for task?
Hi Sheetal. You need to check for the actual value of the ‘State’ field, not just the label. The state field actually has a number based value. I think the number for ‘Closed Complete’ is 7. You can verify this for sure with any choice field by right-clicking the field label and selecting ‘Show choice list’.
Hey Mark,
I’m running into an issue doing this in a scoped app. After Fuji it looks like they started locking down DOM manipulation, the scoped app I’m running get get the element. Do you know if there’s any way to get around this?
The only possibility is to create a system property to override this in your application. Check out the details and explanation here.
https://community.servicenow.com/community/develop/blog/2015/10/01/scoped-applications-and-client-scripts-a-primer
I have created a custom timer field on a custom form and table.
I’m currently running Helsinki and System Properties> UI Properties allows for the toggle of the setting “Task timer field automatically starts when task is displayed: Yes | No” which allows me to keep the timer paused, but still allows manual entry of hours and minutes (as per requirement of department asking for the field), but I’d like to remove the Start/Pause button next to the field, and maybe even remove the display of the Seconds section of the field if at all possible.
Is there a good way with a client script or other wise to hide the button and maybe the seconds on the field since the UI Properties are already taking care of the auto start/pause condition?
Turns out, while loading an existing task, the timer pauses, but not when you create a new task, which is annoying to say the least.
Can’t do a whole lot to hide the seconds…at least not consistently or reliably. The button can be removed using code like this. You might adjust slightly to work in with the existing script if you’re using the one from this post.
$('element.' + g_form.tableName + '.' + fieldName).select('a')[0].hide();
One other quick question, if I created a custom timer field, is it safe to assume that I’ll need to call the table name and the field name in the script in place of ‘time_worked’? I’m not great at scripting (haven’t needed it much in my career up until now) but learning as it relates to SN configurations.
Example I’m thinking would be ‘customtablename.u_time_spent’
The table name should be taken care of for you. Just replace anywhere that references ‘time_worked’ with the name of your field…’u_time_spent’.
I’m having another odd issue that perhaps you can help with. I have the timer set up, it stays paused like it should with the client script, but now they’re reporting that when they enter time into the fields manually that on submit/save instead of incrementing the total time field it gets wiped out to 00:00:00 each time. I don’t recall seeing this issue during my testing but does seem to be the case currently, and no other changes I’m aware of in the instance have occurred.
That’s a bit harder to figure out without having access to your system. I can say that I’ve never seen that happen with this script before…at least in isolation. I’d start by attempting to reproduce in your dev or test instance in the same manner and then working from there. My guess would be some other client script is causing some sort of conflict or there’s some sort of user error involved.
Thanks, I figured it out by removing some code to showing the following:
toggleTimer(‘time_worked’,’00:00:00′); and changed it to toggleTimer(‘time_worked’); and that seems to have worked.
One more, final silly question. The group requesting these changes now wants a color style applied to the timer field to make it stand out on the form. Applying style in the normal manner to a timer field doesn’t seem to do anything. So you know offhand if there is a way to apply a background color to the fields on the timer? I’m guessing that each one would need to be called in a script and a color defined?
The code you changed is designed to zero out the field when the form loads. It doesn’t zero out the time that has already been saved to the field though. It just sets it to zero when the field is paused.
As far as the background color goes, that is possible but it’s a bit of a hack…one that is likely to break during a future upgrade. Here’s the code; use at your own risk and make sure it’s on a list of things to verify (and potentially fix) during an upgrade.
elmt.style.backgroundColor = '#6EDB8F';
});
I had the same issue as Marcel. The part that ‘zeros out the field when the form loads’ also now clears all time that had been saved. I’m on Istanbul.
By commenting that section, forms occasionally load with 1s already in the time worked field before the timer is paused, but the total time now continues to calculate properly
We recently upgraded our sub-production environments to Istanbul and it apparently broke this script. Turns out g_form.tableName is no longer supported, and using g_form.getTableName() fixed the issue.
That being said, there’s still a weird issue where the play/stop images won’t toggle. Still investigating that one. Just wanted to put this out there in case anyone has a similar issue.
Thanks for sharing. Seems like there’s something odd going on with your system. This entire script works flawlessly in my Istanbul instance and I’ve never heard of ‘g_form.tableName’ not being supported in Istanbul (or anywhere else). I’d check to see if you’re getting some other error in your browser console. Even the image toggling should work without issue.
I see what had done wrong. I was using $j instead of $ when looking for link.table.element
Everything’s look good now! We’re in business using g_form.tableName as well.
Awesome! I’m glad you’ve got it working like you need!