Service Portal Form Widget Clickable Link

Elyse Eckert1
Giga Contributor

Hello,

I am completely baffled on how to make a URL clickable on the Form Widget in the Portal. Our client has a requirement to include multiple clickable URLs on their back-end form, which they also need available on the Portal. This is obviously no problem in the console, but nothing I've tried for Portal has worked.

I've tried read-only HTML fields, which do not work in Portal. It ignores the read-only parameter on the dictionary, client scripts, UI Policies and even outright ACL restrictions. The field is always writable. I've tried HTML Annotations, though I know Annotations do not work in Portal. I've tried URL fields, but those also do not work in Portal. I've tried [code][/code] snippets in Journal fields, etc. Nothing works. I cannot make a URL clickable on the Form Widget.

Am I missing something? Should this functionality be so incredibly difficult to implement? Any help would be greatly appreciated.

28 REPLIES 28

Just for clarification I read this as the fields are appearing when you first navigate to the page and then they disappear when the page is finished loading.
If that is the case then to me it sounds like some sort of client side script (client script, ui policy maybe) setting them to not display.

Or it could be ACL's that need to be set if they are custom fields.

It's hard to say with just the image of the blank form. Is it possible to post a walkthrough of how you set the View up?

Goddammit. 

I missed one of my scripts, I think I found it. 

Thats what happens when you get frustrated and rush. 

Thanks Chris I will let you know how I go getting this up. 

Yeah it was the one script I missed. 

I thought I had it worked out, however I get the good ol' blank widget issue.

find_real_file.png

So I figured I have the script wrong on the server. From what I can understand all I needed to do was create the widget from your code and plug in my variables in the server script. 

(function() {
	
	// get the same parameters the OOB form widget uses from the url
	data.table = $sp.getParameter("x_120100_band_songs");
	data.sys_id = $sp.getParameter("3D3499d3bf4f2ce30030b28ab18110c76c");
	
	// use the .getForm() api to grab the form data 
	data.formFields = $sp.getForm(data.table,data.sys_id,null,"Song Links").u_version_original
	data.formFields = $sp.getForm(data.table,data.sys_id,null,"Song Links").u_version_kylie
	data.formFields = $sp.getForm(data.table,data.sys_id,null,"Song Links").u_version_interpret
	data.formFields = $sp.getForm(data.table,data.sys_id,null,"Song Links").u_version_covering
	
	
	// handle the changes to any of the url fields
	if(input){
		for (var field in data.formFields){
			// continue to the next url field if there is no change for the current
			if(data.formFields[field].value == input.formFields[field].value)
				continue;
			
			// if there is a new url update the record appropriately
			var record = new GlideRecord(data.table);
			record.get(data.sys_id);

			if(record.getUniqueValue){
				record.setValue(input.formFields[field].name, input.formFields[field].value);
				record.update();
			}
		}
	}

})();

so I have a feeling I have screwed this up simply, and it will be a face palm of a solution. 

Here is the Client script too

function($rootScope, $scope) {

  var c = this;
	//setup a variable to hold the url field data
	$scope.links = {}
	
	//bring the url field data to the client side 
	c.urlLinks = c.data.formFields;
	//add a lock/unlock state dependent upon the value
	angular.forEach(c.urlLinks,function setLinks(item){
		if(item.value){
			item.lock = true;
		}
		else{
			item.lock = false;
		}
		$scope.links[item.name] = item.value;
	})
	
	// function to set lock/unlock state and update link values
	$scope.setLink = function(formfield){
		if(!formfield.lock && !$scope.links[formfield.name])
			return;
		
		if(formfield.value == $scope.links[formfield.name])
			formfield.value = $scope.links[formfield.name];
		else{
			formfield.value = $scope.links[formfield.name];
			c.server.update()
			})
		}
		formfield.lock = !formfield.lock;
	}
	
	
}

Which as far as I can tell, should just be the same as yours.

Sorry for the repeat q.  

 

 

 

 

There are a few minor details in your scripts. I should have been more clear about what the script is doing.

1) $sp.getParameter() will grab a parameter that exists in the url. For example if I had this url:
myinstance.service-now.com/sp?id=form&sys_id=1234567890&table=x_120100_band_songs
Three parameters exist on this url: id, sys_id, and table
To get the sys_id from the url the syntax would be
        $sp.getParameter('sys_id') 
Thus if I had
        var sys_id = $sp.getParameter('sys_id'),
the value of sys_id would be 1234567890.
And the same would go for the table or id parameter. The parameter is what goes in between the parentheses of $sp.getParameter()

But, if you wanted to hard code the values for testing or other reasons, then there is no need for $sp.getParameter(). You can simply do
var sys_id = "1234567890".

2) $sp.getForm() doesn't bring back the fields at the top layer of the returned object. They are stuffed in a property named "_fields", yes underscore included. So you only need to do the $sp.getForm(...)._fields once and all of your fields are in your variable as an object with the properties being the names of your fields.
In your case you should be seeing something like this in data.formFields

data.formFields = $sp.getForm(data.table,data.sys_id,null,"Song Links")._fields

//In your case if you had the above statement and logged it out you should see an object //like below 

{
   "u_version_orignal": "link value in this field",
   "u_version_kylie": "link value of this field",
   "u_version_interpret": "link value of this field",
   "u_version_covering": "link value of this field"
}

//for logging you can use $sp.log()
//Example $sp.log(data.formFields) and since this is server side and if you're using //chrome you should see it in yellow

If you fix the above and your setup for the "view" is correct you should see the fields in the rendered widget. 
A side note: You might want to .think about if this widget should display all the time or only when viewing the "x_120100_band_songs" table. This check can be done by using the data.table information and an ng-if statement in the html markup
For example the top level element should have something like this:
<div class="panel panel-body" ng-if="data.table == 'x_120100_band_songs'">
   <!-- all your other html markup in here -->
</div>

Doing the above should prevent the content of the widget from displaying unless the table is x_120100_band_songs. Which means that you don't want to hardcode data.table value.

 

Edit: 

The ._fields object actually looks more like this:

{
   "u_version_orignal": {
        value: "link value in this field",
        //There are more properties but value is the one that will contain the link
    },
   "u_version_kylie": {
        value: "link value in this field",
        //There are more properties but value is the one that will contain the link
    },
   "u_version_interpret": {
        value: "link value in this field",
        //There are more properties but value is the one that will contain the link
    },
   "u_version_covering": {
        value: "link value in this field",
        //There are more properties but value is the one that will contain the link
    }
}