Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Getting an HTML Input date field to display a date from a record (service portal widget)

Wayne Richmond
Tera Guru

I recently downloaded the 'My Delegates Widget' from https://snhackery.com/ and was having a go at modifying it so I can add the Start and End dates to the widget. I suceeded in getting the date fields to show and even saving the information entered. However, I can't get the fields to display the data once saved. I don't know the code well enough to understand what's acheviable. Hopefully someone can help.

This is me adding a new record:

find_real_file.png The data saved in the back-end:

find_real_file.png

The widget when I revisit the page:

find_real_file.png

If I change the input type to 'text', I can see the data is there, so I reckon I need to do something clever to get the data showing in the date input type:

find_real_file.png

Here's the code from the widget:

HTML:

<snh-panel title="'${My Delegates}'" class="panel panel-primary">
  <div style="width: 100%; padding: 5px 50px;">
    <table class="table table-hover table-condensed">
      <thead>
        <tr>
          <th style="text-align: center;">Delegate</th>
          <th style="text-align: center;">Approvals</th>
          <th style="text-align: center;">Assignments</th>
          <th style="text-align: center;">CC on Notifications</th>
          <th style="text-align: center;">Start Date</th>
          <th style="text-align: center;">End Date</th>
          <th style="text-align: center;">Remove</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="item in c.data.listItems track by item.id | orderBy: 'delegate'" ng-hide="item.removed">
          <td data-th="Delegate">
            <sn-avatar class="avatar-small-medium" primary="item.id" show-presence="true"/>
            &nbsp;
            <!--<a href="?id=user_profile&table=sys_user&sys_id={{item.id}}" title="{{item.delegate}}">{{item.delegate}}</a>-->
          </td>
          <td data-th="Approvals" style="text-align: center;"><input type="checkbox" ng-model="item.approvals"/></td>
          <td data-th="Assignments" style="text-align: center;"><input type="checkbox" ng-model="item.assignments"/></td>
          <td data-th="CC on Notifications" style="text-align: center;"><input type="checkbox" ng-model="item.notifications"/></td>
          <td data-th="Start Date" style="text-align: center;"><input type="date" ng-model="item.starts"/></td>
          <td data-th="End Date" style="text-align: center;"><input type="date" ng-model="item.ends"/></td>
          <td data-th="Remove" style="text-align: center;"><img src="/images/delete_row.gif" ng-click="removePerson($index)" alt="Click here to remove this person as a delegate" title="Click here to remove this person from the list" style="cursor: pointer;"/></td>
        </tr>
      </tbody>
    </table>
    <p>To add a delegate to the list, select a person from below:</p>
    <sn-record-picker id="snrp" field="data.personToAdd" ng-change="addSelected()" table="'sys_user'" display-field="'name'" display-fields="'title,department,location,email'" value-field="'sys_id'" search-fields="'name'" page-size="20"></sn-record-picker>
    <br/>
    <p>To remove a delegate from the list, click on the Remove icon.</p>
  </div>

  <div style="width: 100%; padding: 5px 50px; text-align: center;">
    <button ng-click="saveDelegates()" class="btn btn-primary ng-binding ng-scope" role="button" title="Click here to save your changes">Save</button>
    &nbsp;
    <button ng-click="returnToProfile()" class="btn ng-binding ng-scope" role="button" title="Click here to cancel your changes">Cancel</button>
  </div>

  <div style="width: 100%; padding: 5px 50px;" ng-show="data.list2Items.length>0">
    <b>I am a Delegate for:</b>
    <div ng-repeat="item in c.data.list2Items track by item.id | orderBy: 'user'" style="padding: 5px;">
      <sn-avatar class="avatar-small-medium" primary="item.id" show-presence="true"/>
      &nbsp;
      <!--<a href="?id=user_profile&table=sys_user&sys_id={{item.id}}" title="{{item.user}}">{{item.user}}</a>-->
      for {{item.delegations}}
      <span ng-show="item.ends"> until {{item.ends}}</span>
    </div>
  </div>

</snh-panel>

Server Script:

(function() {
	data.userID = gs.getUser().getID();
	data.listItems = data.listItems || fetchList();
	data.list2Items = data.list2Items || fetchList2();
	if (input) {
		data.listItems = input.listItems || fetchList();
		if (input.personToAdd && input.personToAdd.value > '') {
			addPersonToList(input.personToAdd.value);
		}
		if (input.button == 'save') {
			saveList();
		}
	}

	function fetchList() {
		var gdt = new GlideDateTime();
		var list = [];
		var delegateGR = new GlideRecord('sys_user_delegate');
		delegateGR.addQuery('user', data.userID);
		delegateGR.orderBy('delegate.name');
		delegateGR.query();
		while (delegateGR.next()) {
			var thisDelegate = {};
			thisDelegate.sys_id = delegateGR.getValue('sys_id');
			thisDelegate.id = delegateGR.getValue('delegate');
			thisDelegate.delegate = delegateGR.getDisplayValue('delegate');
			thisDelegate.approvals = (delegateGR.getValue('approvals') == 1);
			thisDelegate.assignments = (delegateGR.getValue('assignments') == 1);
			thisDelegate.notifications = (delegateGR.getValue('notifications') == 1);
			thisDelegate.starts = delegateGR.getDisplayValue('starts');
			thisDelegate.ends = delegateGR.getDisplayValue('ends');
			list.push(thisDelegate);
		}
		return list;
	}

	function fetchList2() {
		var list = [];
		var today = new Date();
		var delegationGR = new GlideRecord('sys_user_delegate');
		delegationGR.addQuery('delegate', data.userID);
		delegationGR.orderBy('user.name');
		delegationGR.query();
		while (delegationGR.next()) {
			var stillActive = true;
			var endDate = '';
			if (delegationGR.getValue('ends')) {
				endDate = new GlideDate();
				endDate.setValue(delegationGR.getValue('ends'));
				endDate = endDate.getByFormat('dd/MM/yyyy');
				if (today.after(new Date(endDate))) {
					stillActive = false;
				} else {
					if (new Date(endDate).getFullYear() == 2100) {
						endDate = '';
					}
				}
			}
			if (stillActive) {
				var thisDelegation = {};
				var delegations = [];
				if (delegationGR.getValue('approvals') == 1) {
					delegations.push('Approvals');
				}
				if (delegationGR.getValue('assignments') == 1) {
					delegations.push('Assignments');
				}
				if (delegationGR.getValue('notifications') == 1) {
					delegations.push('CC on Notifications');
				}
				if (delegations.length > 0) {
					thisDelegation.sys_id = delegationGR.getValue('sys_id');
					thisDelegation.id = delegationGR.getValue('user');
					thisDelegation.user = delegationGR.getDisplayValue('user');
					thisDelegation.ends = endDate;
					thisDelegation.delegations = '';
					var separator = '';
					for (var i=0; i<delegations.length; i++) {
						thisDelegation.delegations += separator;
						thisDelegation.delegations += delegations[i];
						if (delegations.length > 2) {
							separator = ', ';
							if (i == (delegations.length - 2)) {
								separator = ', and ';
							}
						} else {
							separator = ' and ';
						}
					}
					list.push(thisDelegation);
				}
			}
		}
		return list;
	}

	function saveList() {
		for (var i=0; i<data.listItems.length; i++) {
			var thisDelegate = data.listItems[i];
			if (thisDelegate.removed) {
				if (thisDelegate.sys_id != 'new') {
					var gr = new GlideRecord('sys_user_delegate');
					gr.get(thisDelegate.sys_id);
					gr.deleteRecord();
				}
			} else {
				var delegateGR = new GlideRecord('sys_user_delegate');
				if (thisDelegate.sys_id != 'new') {
					delegateGR.get(thisDelegate.sys_id);
				} else {
					delegateGR.initialize();
					delegateGR.user = data.userID;
					delegateGR.delegate = thisDelegate.id;
					delegateGR.starts = thisDelegate.starts;
					delegateGR.ends = thisDelegate.ends;
				}
				delegateGR.approvals = thisDelegate.approvals;
				delegateGR.assignments = thisDelegate.assignments;
				delegateGR.notifications = thisDelegate.notifications;
				delegateGR.update();
			}
		}
		gs.addInfoMessage('Your Delegate information has been updated.');
	}

    function addPersonToList(selected) {
		var existing = -1;
		for (var i=0; i<data.listItems.length && existing == -1; i++) {
			if (data.listItems[i].id == selected) {
				existing = i;
			}
		}
		if (existing == -1) {
			var thisDelegate = {};
			thisDelegate.sys_id = 'new';
			thisDelegate.id = selected;
			var userGR = new GlideRecord('sys_user');
			userGR.get(selected);
			thisDelegate.delegate = userGR.getDisplayValue('name');
			thisDelegate.approvals = true;
			thisDelegate.assignments = true;
			thisDelegate.notifications = true;
			thisDelegate.starts = true;
			thisDelegate.ends = true;
			data.listItems.push(thisDelegate);
		} else {
			data.listItems[existing].removed = false;
		}
		input.personToAdd = {};
	}
})();

Client controller:

function MyDelegates($scope, $window) {
	var c = this;

	$scope.addSelected = function() {
		$scope.server.update().then(function(response) {
			$('#snrp').select2("val","");
		});
	};

	$scope.removePerson = function(i) {
		c.data.listItems[i].removed = true;
	};

	$scope.saveDelegates = function() {
		c.data.button = 'save';
		$scope.server.update().then(function(response) {
			reloadPage();
		});
	};

	$scope.returnToProfile = function() {
		reloadPage();
	};

	function reloadPage() {
		$window.location.reload();
	}
}

 

1 ACCEPTED SOLUTION

Community Alums
Not applicable

Hi @Wayne Richmond ,

 

You can use <sn-date-picker> for this:

Replace '<input type="date" ng-model="item.starts"/>' with

<sp-date-picker  field="item.starts" ng-model="item.starts" sn-change="" sn-include-time="true"/>

 

and 

Replace '<input type="date" ng-model="item.ends"/>' with

<sp-date-picker  field="item.ends" ng-model="item.ends" sn-change="" sn-include-time="true"/>

 

Taranjeet 

Please mark reply as Helpful/Correct, if applicable. Thanks!

View solution in original post

5 REPLIES 5

Community Alums
Not applicable

Hi @Wayne Richmond ,

 

You can use <sn-date-picker> for this:

Replace '<input type="date" ng-model="item.starts"/>' with

<sp-date-picker  field="item.starts" ng-model="item.starts" sn-change="" sn-include-time="true"/>

 

and 

Replace '<input type="date" ng-model="item.ends"/>' with

<sp-date-picker  field="item.ends" ng-model="item.ends" sn-change="" sn-include-time="true"/>

 

Taranjeet 

Please mark reply as Helpful/Correct, if applicable. Thanks!

Excellent! Thanks @Taranjeet Singh! Is there a list of Service Portal fields that can be used, rather than standard input fields? I'd been keen to review them. I couldn't find anything on the dev portal but I didn't really know what to search for to be honest.

Here's the working widget:

find_real_file.png

Nice enhancement! I like it!!

Thanks! I appreciate you sharing the widget in the first place.

I've parked this for the time being as I get intermittent results where I select a user to delegate to, but it doesn't get added to the form on the portal. However, the record is created on the backend. I can't replicate it now so maybe my tinkering has fixed it. 

Also, I want to hide delegations that have expired. Looking at the code, I thought it did this already, but that isn't the case. I've considered running a daily scheduled job to delete delegation records that have expired anyway, just to keep things tidy.

Thanks again! I love stumbling across little widgets and apps like this. I wish there were a better resource for them.

All the best