LogoLogo
WEM ModelerWEM ReferenceTutorialsMyWEM
  • WEM Platform Documentation
  • Getting Started
    • Introducing WEM
    • Create WEM Account
    • WEM Login
    • MyWEM Portal
      • MyWEM Features
      • MyWEM Support
      • Allow Support Access
    • Partner Portal
  • WEM Modeler
    • Introducing the WEM Modeler
    • Modeler Start Page
    • Manage Projects & Workspaces
    • User Roles Scheme
    • Create a new Project
    • Modeler Application Overview
    • Project Settings
      • Project Configuration
      • Security Settings
      • Portal Settings
      • SMTP Settings
      • Mobile App Settings
    • Expression Editor
    • Flowcharts
      • User Interaction
      • End Node
      • Sub-flowchart
      • Navigation
      • Clear session
      • Decision
      • Assignment
      • List Action
      • Loop
      • Copy Data
      • Save and Discard
      • Import Data
      • Export Data
      • Invoke Webservice
      • HTTP Request
      • Execute Process
        • Different processes explained
        • Send Email
        • Change settings
        • Changing files
        • Generate File
      • Ping server
      • Authenticate
      • Comet Messages
      • OpenAI
      • Async Tasks
      • Note Node
    • Data Model
      • WEM Session Folder
    • Services and Integration
      • Webservices
      • Remote Data Sources
      • Authentication Providers
        • SAML 2.0
          • SAML App Registration in EntraID
        • OAuth 2.0
      • Comet - Real Time Messages
      • Certificates
    • Concepts and Concept Queries
      • Concepts
      • Concept Queries
      • Concept Relations
    • Navigation
      • HTTP Endpoints
      • Tasks
    • Files and Assets
      • Widget Libraries
      • Template Fragments
      • Files
      • Hyperlinks
    • Multilanguage Dictionary
    • Agentic AI
      • WEM AI Agent
      • AI Flowchart Nodes
      • AI User Interaction
    • WEM Preview
    • WEM Runtime
      • Publishing Process
      • Staging
      • Live
    • Debugging
  • Template Editor
    • Interaction Template Editor
      • Interaction Template Hotkeys
    • General and preview
    • Style
      • Heading Type
      • Paragraph Style
      • Text Styling
      • Alignment
      • Hyperlink
      • Tooltip
    • Layout
      • Adaptive columns
      • Div
      • Panel
      • Alert
      • Table
      • Image
      • Icon
      • Label
    • Interaction
      • Form
      • Validation
      • Required field
      • Button
      • Dropdown
      • Free form item
    • Miscellaneous
      • Tabbar
      • Google maps
      • Nested template
      • Script
      • Reference
      • Conditional
      • Data grid
      • Repeater
      • Rich text
      • Custom
    • WMT Tool
  • WEM Reference
    • WEM Expressions Reference
    • Functions
      • Aggregation
        • Average
        • Count
        • First
        • Last
        • Max
        • Min
        • Sum
      • Concepts
        • ConceptId
        • Description
        • FindConcepts
        • GetAncestors
        • GetChildren
        • GetDescendants
        • GetParent
        • Intersection
        • LocalName
        • Synonyms
        • ToConcept
        • Union
      • Date
        • Date
        • DateDiff
        • DateOnly
        • DatePart
        • DayOfWeek
        • FromUnixTimestamp
        • MoveDate
        • Now
        • TimeOfDay
        • Today
        • ToDuration
        • ToLocal
        • ToUnixTimestamp
        • ToUTC
        • UTCNow
        • UTCToday
      • Environment
        • ApplicationId
        • CountryCode
        • CountryName
        • Hostname
        • IpAddress
        • IsFirstRequest
        • IsHttps
        • IsPreview
        • IsStaging
        • IsLive
        • NodeTrail
        • PortalId
        • PortalName
        • ProjectId
        • ProjectName
        • ProjectVersion
        • Setting
        • UrlPath
      • Files
        • FileName
        • FileSize
        • FileUrl
        • MimeType
      • Lists
        • Distinct
        • IsNewRow
        • IsOnRow
        • List
        • NameOf
        • RowId
      • Math
        • Abs
        • Ceiling
        • Cos
        • Distance
        • Exp
        • Floor
        • Log
        • Log10
        • Pi
        • Pow
        • Random
        • Round
        • Sin
        • Sqrt
        • ToNumber
      • Security
        • AesDecrypt
        • AesEncrypt
        • AesIv
        • AesKey
        • CreateJsonWebTokenH256
        • HmacSha256
        • Md5
        • Password
        • PasswordStrength
        • Pbkdf2
        • Sha1
        • Sha256
        • Totp
      • Text
        • AsText
        • Base32ToText
        • Base64ToText
        • CompareFuzzy
        • Concat
        • Contains
        • FormatDate
        • FormatDuration
        • FormatNumber
        • Guid
        • HexToText
        • HtmlAttributeEncode
        • HtmlEncode
        • IndexOf
        • JavascriptEncode
        • JsonEncode
        • Length
        • Padl
        • Padr
        • RegExIsMatch
        • RegExMatches
        • RegExReplace
        • Replace
        • Split
        • StringPart
        • SubString
        • ToBase32
        • ToBase64
        • ToBase64Url
        • ToHex
        • ToLower
        • ToRichText
        • ToString
        • ToTitleCase
        • ToUpper
        • Trim
        • UrlDecode
        • UrlEncode
        • XmlAttributeEncode
        • XmlEncode
        • XPath
        • XPathList
        • XPathNumber
      • Validation
        • HasValue
        • IsEmpty
        • IsKnown
        • IsUnknown
        • IsValidBankaccount
        • IsValidBSN
        • IsValidBTW
        • IsValidEmailAddress
        • IsValidIBAN
        • IsValidPhonenumber
        • IsValidURL
      • Localization
        • AvailableLanguages
        • CurrentLanguage
        • CurrentTimezone
        • LanguageStrategy
        • Languages in WEM
    • Keywords
      • Contains
      • Concepts
        • Ancestor of
        • Child of
        • Concept
        • Descendant of
        • Overlaps
        • Range of
        • Parent of
        • Contains
      • Environment
        • ApplicationRoot
        • Platform
      • Lists
        • In
        • Of
        • Where
        • Contains
        • All
      • Logic
        • And
        • Not
        • Or
        • Choose
        • If Then Else
      • Mobile
        • BatteryLife
        • BuildVersion
        • ConnectivityTypes
        • DeviceId
        • DeviceName
        • IsDevelopmentBuild
        • IsDistributionBuild
      • Text
        • Contains
        • Ends with
        • NewLine
        • Starts with
    • Operators
      • Addition +
      • Division /
      • Equality =
      • Equality-strong ==
      • Greater-than >
      • Greater-than-or-equal >=
      • If-unknown ?
      • Inversion -
      • Less-than <
      • Less-than-or-equal <=
      • Logical-and &, and
      • Logical-not !, not
      • Logical-or |, or
      • Modulo %
      • Multiplication *
      • Power ^
      • Subtraction -
      • Unequality <>
    • Data Types
      • Text
      • Number
      • Yes / No (Boolean)
      • Date Time
      • Duration
      • File
      • Rich Text
      • Concept
      • Conceptset
      • Reference
    • SQL Compatibility
      • Functions
      • Keywords
      • Operators
    • Content Security Policy
    • WEMScript for Custom HTML
    • WEM Widgets
      • WEM Widget Structure
      • WEMScript for Widgets
      • Widget Editor
      • Content Placeholder
    • WMT
      • File Structure
      • Basic Functional Template
      • Styling
      • Font Icons
      • Reference
        • Breadcrumb
        • Button Bar Buttons
        • Common Scripts
        • Common Styles
        • Conditional
        • Content
        • CSP
        • CSP Nonce
        • Expression
        • Hidden Fields
        • Language Select
        • Navigation
        • Node ID
        • Node Name
        • Placeholder
        • Placeholder Conditional
        • Startup Scripts
        • Template Fragment
        • Uses
    • Regression Test Framework
      • WEM Test Script
  • Tutorials
    • Tutorials
      • Making a Change Log
      • Placeholders for end-users
    • First Application
      • Expand First Application
    • Video Tutorials
      • By Partners
      • Security
    • Building Widgets
      • Basics
        • 1. Introduction
        • 2. Hello, World!
        • 3. General
        • 4. Properties
        • 5. Events
        • 6. Styling
        • 7. View State
        • 8. Resources
        • 9. Placeholders
        • 10. Template Editor Script
        • 11. Global Scope
        • 12. Risks and Responsibilities
        • 13. Conclusion
      • In-depth
        • 1. Introduction
        • 2. Platform Availability
        • 3. Development Workflow
        • 4. Properties
        • 5. View state
          • 1. Runtime.viewState
          • 2. sessionStorage
          • 3. Summary
        • 6. Styling
        • 7. Events
          • 1. Navigation
          • 2. Row position
      • WEMscript
        • 1. Introduction
        • 2. Variables
        • 3. Properties
        • 4. OutputId()
        • 5. Register Input - Required
        • 6. Encoding
        • 7. Script Block - Introduction
        • 8. Types
          • 1. Boolean
          • 2. Concept
          • 3. ConceptSet
          • 4. Datetime
          • 5. Duration
          • 6. File
          • 7. Number
          • 8. Richtext
          • 9. Text
        • 9. Script Block - Global Scope
        • 10. Script Block - ES Modules
        • 11. CSS - attachShadow
      • Examples
  • Tips and Tricks
    • Tips and Tricks
      • Keyboard Shortcuts
      • Video's in WEM
      • Extracting text from File
    • Custom Hostnames
    • FAQ
    • Expressions
      • Order of Operators
    • Processes
      • Email Process
      • Tips for creating PDF's
      • ZIP Archive Process Node
    • Concepts
      • Concepts and Runtime
    • Working with data
      • The Power of the Calculated Field
      • Consuming your OData source with Excel 2016
      • Expose your data via OData
      • Using OData to transfer data between runtimes
      • WEM Storage Options
    • Integration
      • Integrating external systems
      • Json
      • Single Sign-on
      • Office365 Integration
    • Performance
      • Performance Tips
      • Performance Profiler
      • Template Performance Profiler
      • The Split Loop
    • Security
      • 2FA with TOTP
      • Blacklist or whitelist IP addresses
    • Widgets
      • Advanced Charts
        • Boxplot Chart
        • Brush Chart
        • Bubble Chart
        • Candlestick Chart
        • Card with Chart
        • Effect Scatter Chart
        • Heat Map
        • Line, Area and Bar Chart
        • Map-Bar Morph
        • Mix Time Line Chart
        • Nested Pie Chart
        • Polar Area Chart
        • Polar Bar Chart
        • Profit Chart
        • Radial Bar Chart
        • Radial Bar Gauge
        • Range Bar Chart
        • Rosetype Pie Chart
        • Sankey Energy Chart
        • Scatter Chart
        • Scatter-Aggregate-Bar Chart
        • Stacked Columns Chart
        • Stepline Chart
        • Treemap
      • Advanced Input
        • Color Picker
        • Conceptset Image Selector
        • Google maps locator
        • Multi select input button
        • MultiFile Upload
        • On/Off switch
        • Process Arrow Steps
        • Rate
        • Rating view
        • Single select input button
        • Slider
        • Tree
      • Template Actions
        • Follow exit
      • Global widgets
        • Agenda
        • Audio Player
        • Calendar
        • Draw Signature
        • Grid Widget
        • Image capture
        • Kanban Board
        • Path
        • Progress Bar
        • reCAPTCHA
        • Timeline
      • Document widgets
        • Json Viewer
        • PDF Viewer
    • Various
    • Go to MyWEM
Powered by GitBook
On this page

Was this helpful?

Export as PDF
  1. Tutorials
  2. Building Widgets
  3. WEMscript

9. Script Block - Global Scope

In the previous chapter, we were introduced to the specific types of script blocks and when to use them. Within these blocks, we use window[Symbol.for(<?js OutputId() ?>)] to assign it to the instance of the Note widget. But what is the purpose of this? Let's examine what is happening under the hood to understand it better.

Let’s take the following widget as an example and see how the final rendered page output will look:

<h2>Script Block Example Widget</h2>
<script>
	console.log("Regular JavaScript script block");
</script>
<? scriptmodule "script-block-example-widget" ?>
	console.log("Script module");
<? end ?>
<? scriptreference "example-website-script" "https://example.website/script.js" ?>
<? startupscript ?>
	console.log("Startup script");
<? end ?>
<? submitscript ?>
	console.log("Submit script");
<? end ?>
<? unloadscript ?>
	console.log("Unload script");
<? end ?>

When inspecting the code output of the page and observing how this widget has been rendered, it roughly translates to the following stripped-down output:

<html>
	<head>
		...
		<script>
			console.log("Script module");
		</script>
		<script src="https://example.website/script.js"></script>
		...
	</head>
	<body>
		...
		<!-- Page content -->
		...
		<h2>Script Block Example Widget</h2>
		<script>
			console.log("Regular JavaScript script block");
		</script>
		...
		<!-- Other page content -->
		...
		<script> 
			Runtime.scripts.addStartupScript(function() {
				console.log("Startup script");
			});
			
			Runtime.scripts.addSubmitScript(function() {
				console.log("Submit script");
			});
			
			Runtime.scripts.addUnloadScript(function() {
				console.log("Unload script");
			});
		</script>
	</body>
</html>

A few interesting things are happening here. The scriptmodule is JavaScript code inside a <script> tag that has been added to the <head> section. The scriptreference behaves similarly. The regular <script> blocks are rendered as part of the page body content. However, you will notice that the code inside the other script blocks is registered at the end of the <body> in anonymous functions.

It is therefore crucial that your function and class names are unique when used in a scriptmodule or scriptreference. To clarify, consider these two widgets created by Bob and Jane:

<? scriptmodule "bobs-button" ?>
	class Button {/* Bob's button */}
<? end ?>
<? scriptmodule "janes-button" ?>
	class Button {/* Jane's button */}
<? end ?>

This will output roughly to:

<head>
	<script>
		class Button {/* Bob's button */}
	</script>
	<script>
		class Button {/* Jane's button */}
	</script>
</head>

In this case, Bob's button is overwritten by Jane's, which is problematic. The scriptreference faces the same issue, as the script is loaded externally instead of being embedded within the page itself.

We resolved this issue in the Note widget by using class WemAcademyNote instead of class Note. While this is not a perfect solution, it helps minimize naming collisions.

There are other ways to address this naming collision, but they come with trade-offs. I will explain those later. First, let’s take a closer look at window[Symbol.for(<?js OutputId() ?>)]. Notice that the startupscript, submitscript, and unloadscript are anonymous functions. But what if we need access to context outside their local scope? This was the problem we encountered in the Note widget. To achieve this, we need a way to share state between those functions, which requires a global context. However, this can be very risky if not handled carefully.

Let's examine a stripped-down version of initializing and disposing of the Note widget from the previous chapter in a potentially dangerous way:

<? startupscript ?>
	const note = new Note();
	document.documentElement.append(note.rootEl);
	window.note = note;
<? end ?>
<? unloadscript ?>
	window.note.dispose();
<? end ?>

This will output roughly to:

<body>
	...
	<script> 
		Runtime.scripts.addStartupScript(function() {
			const note = new Note();
			document.documentElement.append(note.rootEl);
			window.note = note;
		});
		
		Runtime.scripts.addUnloadScript(function() {
			window.note.dispose();
		});
	</script>
</body>

In this example, we declared a global variable note, which can be risky. If another piece of JavaScript code uses a global variable with the same name, we may encounter undefined behavior. In this case, we could inadvertently overwrite someone else's note variable. This is a classic pitfall of using global variables!

However, there is a way to make this global variable "hidden." Let's dissect window[Symbol.for(<?js OutputId() ?>)] using the following code:

<? startupscript ?>
	const note = new Note();
	document.documentElement.append(note.rootEl);
	window[Symbol.for(<?js OutputId() ?>)] = note;
<? end ?>
<? unloadscript ?>
	window[Symbol.for(<?js OutputId() ?>)].dispose();
<? end ?>

This will output to the following:

<body>
	...
	<script> 
		Runtime.scripts.addStartupScript(function() {
			const note = new Note();
			document.documentElement.append(note.rootEl);
			window[Symbol.for("cc1")] = note;
		});
		
		Runtime.scripts.addUnloadScript(function() {
			window[Symbol.for("cc1")].dispose();
		});
	</script>
</body>

Here, we see that <? OutputId() ?> has printed "cc1". As we learned in previous chapters, OutputId() creates a unique identifier for each instance of the widget on the page. This means that if we add multiple instances of this widget, the identifiers will be "cc2", "cc3", and so on. Note that we use "cc1" as an example, and it is bound to the implementation of the WEM Runtime, so it can be anything.

The window object is the global object in JavaScript, and the Symbol class is particularly interesting here. It creates symbols that are guaranteed to be unique. In our case, we use it to create a unique key that we store in window, effectively creating our "hidden" global variable. In other words, this approach provides a form of weak encapsulation or weak information hiding.

You might wonder, "What if we navigate to the next page? Wouldn't we potentially have another instance of a widget called cc1?" Yes, that is true, but it does not matter because we disposed of the instance of the note in the previous unloadscript. Therefore, it is acceptable to overwrite the contents of window[Symbol.for("cc1")].

In our Note widget, we implemented the following:

<? unloadscript ?>
	const noteSymbol = Symbol.for(<?js OutputId() ?>);
	window[noteSymbol].dispose();
	delete window[noteSymbol];
<? end ?>

To ensure that we clean everything up, we also delete our "hidden" global variable, as shown above. This helps the JavaScript garbage collector free up memory space. More importantly, it ensures that we do not have access to the variable after it has been used.

Previous9. TextNext10. Script Block - ES Modules

Last updated 4 months ago

Was this helpful?