Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Manipulating the view state via JavaScript can be quite overwhelming. The following table illustrates the differences between various scenarios.
The table below assumes that some view state has been set via JavaScript after a page load to a view state field.
Persisted on browser refresh (F5)
No
Yes
Yes
Persisted on WEM application event
Yes
Yes
Yes
Removed when the widget is unloaded
Yes
Depends
Depends
Removed when the browser tab is closed
Yes
Yes
No
Removed when the browser is closed
Yes
Yes
No
Removed when your computer is hit by a meteor
Yes
Yes
Yes
In the case of a widget being unloaded, there are two scenarios where the outcome depends on specific conditions. As discussed in the previous chapter, we have the option to manually clear the state of localStorage
and sessionStorage
in the unloadscript
block.
The teaching of Less and CSS is outside the scope of this academy. However, there are a few important points to keep in mind. Most of the concepts I explain here apply not only to WEM widgets but also to web development in general.
When you publish or preview a WEM application, the Less styles from all the widgets are combined into a single CSS file. This CSS file is then included in the design template. This presents a significant issue: all the CSS exists in a global space. I briefly discussed this in previous chapters. As we learned, if you are not careful, you could inadvertently overwrite the styles of other widgets or any HTML element, for that matter! For example:
In this case, both Bob and Jane have created a card widget using the class name "card." Even if Jane's widget is not used on a page, if Bob's widget is included, it may appear to have a strange yellow background. This can lead to confusion and blame for issues that are not actually related to Bob's widget. It is advisable to make class names more unique. You can add prefixes to the class names, such as your initials, your company name, or both, like this:
When WEM supported widgets, it included Less by default. Less is powerful because it supports variables, which makes styling more organized and easier to maintain. Nowadays, CSS variables are supported in all major browsers and offer even greater capabilities. You can alter the value of a CSS variable in real time, creating new opportunities for styling your widgets. You can still use Less variables as a base. For example, consider the following Less code:
However, if you save this code, you will encounter an error message indicating a syntax error on the line setting the border
property.
What is happening here? This is because Less has its own syntax and attempts to parse the CSS value as a Less expression. We can resolve this issue by using the escape syntax ~"value"
. If we modify the line as follows:
This change makes the code valid. While it may not be ideal, it is better than nothing.
You may be wondering how to embed a resource in Less. The short answer is that you cannot do it directly. The following code, which uses a made-up WEM style syntax, will not work:
To achieve this, you need to revert to using the <style>
tag or apply it via JavaScript.
In the previous module of the view state chapter, we declared a field and created an event to toggle that field, allowing the message box to expand and collapse. Another way to change the view state is through JavaScript. Let's update our previous implementation of the message box to utilize JavaScript instead.
First, we need to add the Text
text property and the Style
dropdown property, which should include the values "info," "success," and "danger." You can refer to the previous view state chapter for guidance on how we created these properties. Next, we will create a boolean view state field named Collapsed
.
Use the following script:
What has changed is that there is no register event
because we don't have an event in this widget, nor do we need @Collapsed := @Collapsed ? false
to initialize that field to false
when it is unknown
. This works in this case because when we check with if @Collapsed then
, it does not matter whether the value is unknown
or false
.
We introduce a new function, OutputId()
. Every widget has its own Output ID, which serves as a unique identifier on the page. This is perfect for use in conjunction with the id
attribute, which should also be unique! We will discuss this function in more detail in later chapters.
We changed the onclick
attribute to execute the toggleMessageBox()
function instead of triggering an event, as we did in the previous chapter. A new feature is that this function is declared inside a scriptmodule
, which is another way to add JavaScript functionality to the widget, aside from including it via a file. We will cover this topic in more detail in later chapters.
The toggleMessageBox(element: HTMLElement)
function is straightforward. Depending on the state, we toggle between the two classes. We retrieve the Output ID from element.id
and check if it is collapsed by verifying if the element's class list contains the "collapsed" class. The Runtime.viewState(outputId: string)
function returns the view state of the widget with that Output ID. We use the set(key: string, value: any)
function, where the key
is the name of the view state field, to set a value for that field. There are two additional functions besides set()
: get(key: string)
and clear(key?: string)
. These functions are self-explanatory, but you can find more information about them in the WEM widget reference.
The styles remain unchanged and are the same as before:
Now, place this widget on a template and add a refresh button to the page. Preview the widget. Notice that when you click the widget, there is no refresh, unlike in the previous implementation. This creates a better user experience. However, there is one downside: the view state is only persisted when we perform a postback to the WEM Runtime, such as when clicking the refresh button.
Try toggling the state of the widget, and then press F5 to refresh the page in your browser. You will notice that the widget retains its previous state. Now, toggle the state of the widget again and click the refresh button we added to the page. This time, the state is saved.
In the next chapter, we will explore a more modern approach to storing view state using localStorage
and sessionStorage
. This method addresses the refresh issue but comes with its own set of challenges.
You can also utilize sessionStorage
and localStorage
, which are available in the JavaScript standard library. These solutions are purely JavaScript-based and do not rely on WEM view state internals. Let's update our previous widget slightly.
Update the script with the following:
In this update, we introduce startupscript
, which is a JavaScript code block that runs after the page has been initialized and all static HTML elements are rendered. We also have unloadscript
, which executes when a WEM event is triggered, just before the new page is rendered. We will discuss these script blocks in more detail in later chapters.
Comparing the previous code with the new version, you will notice that the initializeMessageBox()
function is used to initialize the message box, as the name suggests. Here, we set the class names and retrieve the view state using sessionStorage
through JavaScript. Additionally, we updated the code to set the click
handler here instead of using an onclick
attribute. While functionally there is no difference, this approach promotes better organization, a principle known in computer science as "separation of concerns."
Looking at the function getKeyMessageBox(outputId, nodeId)
and the line const key =
${element.id}:${nodeId}:collapsed;
, we see that the key
is created by combining the Output ID, a node ID, and an arbitrary identifier, separated by a colon. Since sessionStorage
keys are stored globally, we need to ensure that the keys for this widget are globally unique. If we had simply used "collapsed" as the key and had two identical widgets on the same page, they would overwrite each other's state. The node ID ensures that the view state of this widget is unique per interaction node. While we use a colon here, any character that is not alphanumeric can be used, as those characters are reserved for the Output ID and node ID.
Depending on the widget you are creating, you may want to clear the view state—demonstrated using clearStateMessageBox()
here—when unloading the widget.
Let’s open the overlay again to create a property. All property types have the following attributes:
The name of the property is identified as @MyPropertyName
in WEMscript.
The input type determines how we set the value of the property. There are three methods to do this. Note that there is only one way to write to a property, which is via the Data Model.
This property indicates which group the property should be rendered in within the template editor. It does not affect the functionality of the property.
The file property has an additional attribute for validation. You can leave it blank to accept any file type.
The dropdown has an extra property called Dropdown Options. The options consist of a tuple of a label and a value. The labels are used to display the options in the template editor, while the values are used in WEMscript and are of the text type. In technical terms, a dropdown is a static set of text enums.
Let’s assume a dropdown property called @StyleContext
with the following set of options for UI context styles:
The value of the dropdown is simply a text value. Here’s an example of how to use it:
The navigation types include Button Exit, Flowchart, Hyperlink, and Navigation Item. These are always set statically.
This is the initial value of the property. If it is not set, the initial value will be unknown
.
This property is only available when the input type is Data Model. If you want to write values back to the data model, this should be set to true. The property becomes stricter when it is writable; you cannot use calculated fields.
This property determines when the property should be visible in the template editor. It works in conjunction with literal boolean and dropdown properties. You will notice that if you have any of those as properties for a widget, the "Visible When" dropdown is populated with those properties. The "Visible When" feature is useful for hiding properties that are not required in certain contexts.
Literal
A value that is set statically.
No
Data Model
A value that is set by binding to a data model item, which can be either a list or a field, depending on the property type that has been set. The field must also be writable.
Depends
Expression
A value that is set by a WEM expression.
No
Success
success
Info
info
Warning
warning
Danger
danger
In previous chapters, we used events to refresh the page without writing any code for it, and to toggle between the collapsed and expanded states of our message box widget. In this chapter, we will create our own button and add different types of actions to it.
First, create a new widget and name it "Button." Use the following script:
Next, add a dropdown property called "Action" with the following options:
Refresh screen
refresh
Execute flowchart
execute
Navigate to
navigate
Follow button exit
follow
Then, add three additional properties called "Flowchart," "NavigationItem," and "ButtonExit," using the same property type as their names. Do you remember the "Visible when" property explained previously? Click on the "ButtonExit" property and change the "Visible when" setting from "Always visible" to "Action." Note that "Action" refers to the dropdown property we created with selectable options. For "ButtonExit," check the "follow" checkbox. Repeat this process for the other two properties. You will see this functionality in action once we display this widget in the template editor.
Now, create an event called "OnClick" and use the following example code:
Three new statements are introduced here: execute
, navigate
, and follow
. By now, you should be familiar with WEM terminology. If you read the code, you will find that these statements do exactly what you expect, and they should be self-explanatory.
Events also allow for the manipulation of the row position within a list. This functionality is similar to using the List node in the flowchart editor; however, not all features available in the List node are supported.
The basic syntax is as follows:
The syntax is straightforward, so we won't go into detail about what each command does. However, as mentioned earlier, not every feature is available out of the box. For instance, if we want to create an event that navigates to a specific row, we can program it as follows: we create a numeric view state called "RowIndex" to store the current row index. Note that in this example, the indices start at 1, with the first row being index 1. Fortunately, the code is quite simple:
In the previous chapters, you learned how to create basic widgets. In this chapter, we will delve deeper into the topics we previously covered. However, we will not go in-depth into certain aspects of WEMscript, as that requires a separate module of its own. By the end of this chapter, you will have a better understanding of Properties, View State, Styling, and Events. Once you have a detailed knowledge of these concepts, we will be ready to start writing advanced widgets in the following module.