Global Navigation Bar - via a script tag

Our organisation has a common Global Navigation Bar that must go at the very top of every application on our intranet.

This is centrally maintained and is rendered using a <script></script> and <noscript></noscript> pair.

I've looked at the various options and not finding a way to make this happen.

Ideally it would be added to our Layout templates in a common theme we'll create. But to start with I'm just trying to get it working in a standalone app.

I'm pretty certain I can't add a Server Action to a Web Block or Layout so can't use the HTTPRequestHandler API.

I've tried using an expression but I just get the script tags added as text to the layout.

The HTML Element will rightly not accept a <script> tag.

Can anyone nudge my in the right direction?

Cheers,

Roy

Hi,

You need to change the escape content property in expression to No so that it doesn't display it as text.

Regards.

I looked for that - it didn't exist. Is that because I created a Reactive app?

Hi Roy,

In Reactive Web App, you can use the Javascript widget to add custom JavaScript to your application.

For more information on how to extend a Reactive- or Mobile OutSystems application with JavaScript you can read:

https://success.outsystems.com/Documentation/11/Extensibility_and_Integration/JavaScript/Extend_Your_Mobile_and_Reactive_Apps_Using_JavaScript

Regards,

Daniel

Daniël Kuhlmann wrote:

Hi Roy,

In Reactive Web App, you can use the Javascript widget to add custom JavaScript to your application.

For more information on how to extend a Reactive- or Mobile OutSystems application with JavaScript you can read:

https://success.outsystems.com/Documentation/11/Extensibility_and_Integration/JavaScript/Extend_Your_Mobile_and_Reactive_Apps_Using_JavaScript

Regards,

Daniel

I did look at that as an option too. 

But I don't want to embed any JavaScript. I want to pull in a JavaScript file. Remember I don't own this. It's something I just pull in via a script. 

In previous projects I have used JavaScript to dynamically load external scripts, but that's not exactly the most secure way to do it... 

Cheers, 

Roy

Hi Roy,

In traditional web we did that through expression with escape content in reactive you need to follow the steps of this post. If this don't solve your problem can you explain better what you want to achieve.

Regards,

Marcelo

Marcelo Ferreira wrote:

Hi Roy,

In traditional web we did that through expression with escape content in reactive you need to follow the steps of this post. If this don't solve your problem can you explain better what you want to achieve.

Regards,

Marcelo

OK,

I've been through all of these options (I believe) and everything refers to locally owned and managed JavaScript.

This Global Nav Bar has been designed to be used be developers - whatever the client framework: WebLogic, aspx, Angular, SharePoint and more.

OutSystems needs to follow suit...

I don't own this code - I am a consumer. I access as follows:

<script src="https://<intranetDomain>/Style%20Library/CDN/GNB.js" type="text/javascript"></script>
<noscript><a href="http://<intranetDomain>/gnblinks.htm">Access global navigation links</a></noscript>

I need to create a common Widget/Block that I can inject in to every layout template.

It manages itself.

Is that clearer?

Cheers,

Roy

Hi Roy,

The option I gave you accomplishes that. Just add that code you posted on the innerHTML. You will see the code on the page if you inspect it. Did you find it on the page? Any error on the browser console? Or service center?

Regards,
Marcelo

Hi,

I solved this before by creating a client action to add a script to the head of a HTML Page.

Then I called it in the OnInitialize event handler of the layout webblock used by the screens.

Regards,

Daniel

Daniël Kuhlmann wrote:

Hi,

I solved this before by creating a client action to add a script to the head of a HTML Page.

Then I called it in the OnInitialize event handler of the layout webblock used by the screens.

Regards,

Daniel

This is the method (JavaScript) that I used in Backbone.js

Was never overly confident of how secure it was, but this should do the trick. 

Will try in the morning. 


Marcelo Ferreira wrote:

Hi Roy,

The option I gave you accomplishes that. Just add that code you posted on the innerHTML. You will see the code on the page if you inspect it. Did you find it on the page? Any error on the browser console? Or service center?

Regards,
Marcelo

OK I see it now. Just hard code the innerHtml rather than use parameters. 

I'll give this a go to. 


Hi,

innerhtml did not work properly. I tried adding a script file with just one alert and tried adding the script tag with src pointing to the js file in onInitialize and onReady but never got the alert.

Regards.

Roy Corneloues wrote:

Our organisation has a common Global Navigation Bar that must go at the very top of every application on our intranet.

This is centrally maintained and is rendered using a <script></script> and <noscript></noscript> pair.

I've looked at the various options and not finding a way to make this happen.

Ideally it would be added to our Layout templates in a common theme we'll create. But to start with I'm just trying to get it working in a standalone app.

I'm pretty certain I can't add a Server Action to a Web Block or Layout so can't use the HTTPRequestHandler API.

I've tried using an expression but I just get the script tags added as text to the layout.

The HTML Element will rightly not accept a <script> tag.

Can anyone nudge my in the right direction?

Cheers,

Roy

Hi Roy,

So what I understand from your question is you basically want to add a script tag in your page head section of reactive web application.

If yes, then simplest way is to use RequireScript client action from systems espace. You can pass your js url in this action and it will take care of your js reference. If this script is already added it will even avoid duplicate.

Keep in mind that it uses local storage/ server action internally so you may see some warning depedending upon where you are adding it in your flow.

Hi,

Nikhil solution is better than the one I proposed, especially as it takes care of avoiding adding the same url multiple times.

Regards,

Daniel

Nikhil Gaur wrote:

Roy Corneloues wrote:

Our organisation has a common Global Navigation Bar that must go at the very top of every application on our intranet.

This is centrally maintained and is rendered using a <script></script> and <noscript></noscript> pair.

I've looked at the various options and not finding a way to make this happen.

Ideally it would be added to our Layout templates in a common theme we'll create. But to start with I'm just trying to get it working in a standalone app.

I'm pretty certain I can't add a Server Action to a Web Block or Layout so can't use the HTTPRequestHandler API.

I've tried using an expression but I just get the script tags added as text to the layout.

The HTML Element will rightly not accept a <script> tag.

Can anyone nudge my in the right direction?

Cheers,

Roy

Hi Roy,

So what I understand from your question is you basically want to add a script tag in your page head section of reactive web application.

If yes, then simplest way is to use RequireScript client action from systems espace. You can pass your js url in this action and it will take care of your js reference. If this script is already added it will even avoid duplicate.

Keep in mind that it uses local storage/ server action internally so you may see some warning depedending upon where you are adding it in your flow.

So I cannot ad the script to the head. It has to be placed in the body and expects to be the first element.

I'm wondering if I can place an empty <div> placeholder and then target the Client Action to load the script in to that tag.

However to do that I need to be able set/know the <div> ID.

Yes, If that is the case you can add a container and it its name and on onReady event you can write your JS code to add your script reference inside the container you have created.

Note: You can pass the container id to JS block using <YourContainerName>.Id

But I want to know why it is that you want script tag only in body that too as first element.

Thanks all for your help so far. Right now I've just created a simple test app to get things working. No Client Actions etc.

It worked the first time I ran it and it displayed the nav bar and it was fully functional. But as I put the Block in the main content area it appeared under the OutSystems standard navigation bar.

Here's the code I used:

var body = document.getElementsByTagName("BODY")[0];
var script = document.createElement('script');
var noscript = document.createElement('noscript');
var href = document.createElement('a');

script.type = 'text/javascript';
script.src = 'https://<domain>/<path>/<script>.js';

href.setAttribute("href", "https://<domain>/<page>.htm");
href.innerHTML = "Access global navigation links";
noscript.appendChild(href);

body.appendChild(script);
body.appendChild(noscript);

Next step is to replace the OutSystems nav...

Hi Roy,

Instead of appendChild you need to use insertBefore. Check it here how to use it.

Regards,

Marcelo

So, It's finally working...

The last issue i was facing was that I was trying to use one of the standard layouts. There appears to be some code in there that will always float the built in global nav to the top.

I copied the LayoutBlank Layout added my new block inside a container and then moved it to the top.

So all sorted. Thanks for all your help (Still very green around the gills here) and have posted the JavaScript below to help others if ever needed.

var body = document.getElementsByTagName("BODY")[0];
var script = document.createElement('script');
var noscript = document.createElement('noscript');
var href = document.createElement('a');

script.type = 'text/javascript';
script.src = 'https://<domain>/<path>/<script>.js';

href.setAttribute("href", "https://<domain>/<page>.htm");
href.innerHTML = "Access global navigation links";
noscript.appendChild(href);

body.insertBefore(noscript, body.childNodes[0]);
body.insertBefore(script, body.childNodes[0]);