How to override a javascript function that is being called from sp-model in serviceportal.

nthumma
Giga Guru

I have cloned an OOB form widget (widget-form), Issue is when user clicks on reference info icon (i) on my cloned widget (my-widget-form) the reference information is opening in widget-form instead of my-widget-form.

below ng-click is calling showForm(data); javascript function

ng-click="openReference(field, formModel.view)

in the below function if you see line 2 , its setting the form widget ID, now my goal is to set the widget ID to my-widget-form instead of widget-form.

function showForm(data) {
var url = spUtil.getWidgetURL("widget-form");
var req = {
method : 'POST',
url : url,
headers : spUtil.getHeaders(),
data : data
}
$http(req).then(qs, qe);
function qs(response) {
var r = response.data.result;
showModal(r);
}
function qe(error) {
console.error("Error " + error.status + " " + error.statusText);
}
}

 

Is there a way I can override the whole opeReference method from my cloned widget?

 

1 ACCEPTED SOLUTION

Jon Barnes
Kilo Sage

I think in order to do what you want, you will likely have to override the spReferenceField directive. I learned a trick from SNOW on how to use angular decorators to do that. You could probably use a decorator to just override the controller (which is where the showForm function is), but the controller makes up the vast majority of the directive, so may as well override the whole thing. I did it by putting this in a UI Script and adding this as a dependency to my portal. This worked for me. Just remember in the showForm method below, to put your form widget in there. And of course the down side of doing this is that during any upgrades, you may have to merge fixes/new functionality provided in updated spReferenceField directives into your custom one.

 

/*! RESOURCE: /scripts/app.$sp/directive.spReferenceField.js */
angular.module('sn.$sp').directive('spReferenceField', function($rootScope, spUtil, $uibModal, $http, spAriaUtil, i18n) {
	'use strict';
	return {
		restrict: 'E',
		replace: true,
		templateUrl: 'sp_reference_field.xml',
		controller: function($scope) {
			var unregister;
			$scope.openReference = function(field, view) {
				var data = {
					table: field.ed.reference,
					sys_id: field.value,
					view: view
				};
				if (angular.isDefined(field.reference_key))
					data[field.reference_key] = field.value;
				else
					data.sys_id = field.value;
				if (unregister)
					unregister();
				unregister = $rootScope.$on('$sp.openReference', function(evt, data) {
					unregister();
					unregister = null;
					if (!evt.defaultPrevented && evt.targetScope === $scope)
						showForm(data);
				});
				$scope.$emit('$sp.openReference', data);
			};
			$scope.$on("$destroy", function() {
				if (unregister)
					unregister();
			});
			function showForm(data) {
				var url = spUtil.getWidgetURL("widget-form");
				var req = {
					method : 'POST',
					url : url,
					headers : spUtil.getHeaders(),
					data : data
				};
				$http(req).then(qs, qe);
				function qs(response) {
					var r = response.data.result;
					showModal(r);
				}
				function qe(error) {
					console.error("Error " + error.status + " " + error.statusText);
				}
			}
			function showModal(form) {
				var opts = {
					size : 'lg',
					templateUrl : 'sp_form_modal',
					controller : ModalInstanceCtrl,
					resolve : {
					}
				};
				opts.resolve.item = function() {
					return angular.copy({
						form : form
					});
				};
				var modalInstance = $uibModal.open(opts);
				modalInstance.result.then(function() {}, function() {
					spAriaUtil.sendLiveMessage($scope.exitMsg);
				});
				$scope.$on("$destroy", function() {
					modalInstance.close();
				});
				var unregister = $scope.$on('sp.form.record.updated', function(evt, fields) {
					unregister();
					unregister = null;
					modalInstance.close();
					if (evt.stopPropagation)
						evt.stopPropagation();
					evt.preventDefault();
				});
			}
			function ModalInstanceCtrl($scope, $uibModalInstance, item) {
				$scope.item = item;
				$scope.ok = function() {
					$uibModalInstance.close();
				};
				$scope.cancel = function() {
					$uibModalInstance.dismiss('cancel');
				};
			}
		},
		link: function(scope) {
			i18n.getMessage("Closing modal page", function(msg){
				scope.exitMsg = msg;
			});
		}
	};
}).decorator("spReferenceFieldDirective", function($delegate) { return( [ $delegate[1] ] );});

View solution in original post

9 REPLIES 9

Jon Barnes
Kilo Sage

I think in order to do what you want, you will likely have to override the spReferenceField directive. I learned a trick from SNOW on how to use angular decorators to do that. You could probably use a decorator to just override the controller (which is where the showForm function is), but the controller makes up the vast majority of the directive, so may as well override the whole thing. I did it by putting this in a UI Script and adding this as a dependency to my portal. This worked for me. Just remember in the showForm method below, to put your form widget in there. And of course the down side of doing this is that during any upgrades, you may have to merge fixes/new functionality provided in updated spReferenceField directives into your custom one.

 

/*! RESOURCE: /scripts/app.$sp/directive.spReferenceField.js */
angular.module('sn.$sp').directive('spReferenceField', function($rootScope, spUtil, $uibModal, $http, spAriaUtil, i18n) {
	'use strict';
	return {
		restrict: 'E',
		replace: true,
		templateUrl: 'sp_reference_field.xml',
		controller: function($scope) {
			var unregister;
			$scope.openReference = function(field, view) {
				var data = {
					table: field.ed.reference,
					sys_id: field.value,
					view: view
				};
				if (angular.isDefined(field.reference_key))
					data[field.reference_key] = field.value;
				else
					data.sys_id = field.value;
				if (unregister)
					unregister();
				unregister = $rootScope.$on('$sp.openReference', function(evt, data) {
					unregister();
					unregister = null;
					if (!evt.defaultPrevented && evt.targetScope === $scope)
						showForm(data);
				});
				$scope.$emit('$sp.openReference', data);
			};
			$scope.$on("$destroy", function() {
				if (unregister)
					unregister();
			});
			function showForm(data) {
				var url = spUtil.getWidgetURL("widget-form");
				var req = {
					method : 'POST',
					url : url,
					headers : spUtil.getHeaders(),
					data : data
				};
				$http(req).then(qs, qe);
				function qs(response) {
					var r = response.data.result;
					showModal(r);
				}
				function qe(error) {
					console.error("Error " + error.status + " " + error.statusText);
				}
			}
			function showModal(form) {
				var opts = {
					size : 'lg',
					templateUrl : 'sp_form_modal',
					controller : ModalInstanceCtrl,
					resolve : {
					}
				};
				opts.resolve.item = function() {
					return angular.copy({
						form : form
					});
				};
				var modalInstance = $uibModal.open(opts);
				modalInstance.result.then(function() {}, function() {
					spAriaUtil.sendLiveMessage($scope.exitMsg);
				});
				$scope.$on("$destroy", function() {
					modalInstance.close();
				});
				var unregister = $scope.$on('sp.form.record.updated', function(evt, fields) {
					unregister();
					unregister = null;
					modalInstance.close();
					if (evt.stopPropagation)
						evt.stopPropagation();
					evt.preventDefault();
				});
			}
			function ModalInstanceCtrl($scope, $uibModalInstance, item) {
				$scope.item = item;
				$scope.ok = function() {
					$uibModalInstance.close();
				};
				$scope.cancel = function() {
					$uibModalInstance.dismiss('cancel');
				};
			}
		},
		link: function(scope) {
			i18n.getMessage("Closing modal page", function(msg){
				scope.exitMsg = msg;
			});
		}
	};
}).decorator("spReferenceFieldDirective", function($delegate) { return( [ $delegate[1] ] );});

Thank you for your response, I am still new to the angular and service portal world.

I have one final request, Do you mind posting the screenshot of your UI script and how to add the UI script as the dependency to the widget.

 

 

UI Script:

find_real_file.png

 

Here is some documentation on creating widget dependencies:

https://developer.servicenow.com/app.do#!/document/content/app_store_doc_sp_widgets_jakarta_widget-dependencies?v=jakarta

Thank you so much for your help, I was able to override the spReferenceField directive and its all good now.

now i have learn more about decorator.