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

Hi nthumma,

 

I have tried to follow the process but getting below error, Please help me to fix the issue.

 

 

 [$compile:multidir] Multiple directives [spReferenceField (module: sn.$sp), spReferenceField (module: sn.$sp)] asking for template on: <span class="ref-picker-container" ng-switch-when="reference" ng-class="{'field-has-reference': field.value != '', 'field-empty-reference': field.value == ''}">

If anyone else wants to rewrite the template:

you need to override the directive first and then instead of "templateUrl: 'sp_reference_field.xml'" you can write your own template:

"template: '<h1> my template </h1>'

 

or write a new template and attach it to the global angular templates

Really useful!

Got me on the right track to modify the DateTimePicker directive and utilise some of the configuration options that aren't normally available.

Alok Sharma
Tera Contributor

Hi Jon,

 

I have tried to follow the process but getting below error, Please help me to fix the issue.

 

 

 [$compile:multidir] Multiple directives [spReferenceField (module: sn.$sp), spReferenceField (module: sn.$sp)] asking for template on: <span class="ref-picker-container" ng-switch-when="reference" ng-class="{'field-has-reference': field.value != '', 'field-empty-reference': field.value == ''}">

I would guess you made a new directive. But what you need to do is a new UI Script which you will attach to the JS Includes of the Theme of your Portal.