All posts by Gerton Leijdekker

Software Architect in the Uniface Lab in Amsterdam. Working at the Uniface Lab as of 1996 in various roles, like QA, Development, Usability (samples), Documentation, DSPs, UARs, Uniface 10, and now as Product Owner of the Uniface product.

DSPs provide access to the DOM layer

DSP JS API function: uniface.field.getBoundElement()

Putting application developers in control of the presentation layer

HTML5 already provides a powerful set of form controls out of the box, and its functionality is continuing to grow and mature. To get access to all that functionality, application developers need to be able to interface directly with the controls. Uniface 10.3 Dynamic Server Pages provides exactly that capability.

Before we go into detail, let’s see how Uniface’s support for web technology has evolved over time to give developers more and more control over their applications.

The beginning: Uniface Server Pages

Uniface 7.2 provided our first functionality for the web: The Static Server Page, also known as the Uniface Server Page (USP). USPs enable binding between the Uniface server-side data structure and an HTML client side. They handle communication between client and server in a very simple way: the server generates an HTML page complete with data substituted into the HTML, and the browser simply displays that HTML page.

Updates are initiated by the browser via a standard HTML submit, after which the server will load the updates and reconnect them with the back end. After that, the server again generates a full-page response with all changes handled, and the whole process starts again from the beginning.

A leap forward: Dynamic Server Pages

Uniface 9.4 introduced the Dynamic Server Page (DSP) allowing Uniface developers to create rich internet applications (RIAs). The biggest difference between a USP and a DSP is the absence of full-page refreshes in the DSP. Obviously, data is still sent to the server and received back by the client, but instead of the whole page being refreshed, only the affected data is returned and merged into the page displayed in the browser. All communication is handled by the Uniface DSP and programming is as easy as writing some ProcScript in a trigger.

In addition, Uniface 9.4 DSPs provide out-of-the-box client-side syntax checking, which, in case of a syntax error, avoids a round trip to the server. A DSP consists of a server part and a client part. The client part has a copy of the component definition, which is what allows the client to perform syntax checking.

Introducing the ability to manipulate client data

Initially, Uniface application developers could write business logic solely for the server, using ProcScript; the client side was closed to them.

Uniface 9.5 changed that by introducing the JavaScript (JS) API. Uniface application developers can use this to access the Uniface data structure on the client, and can manipulate Uniface data there using JS, without the need to go back to the server. The JS API provides access to field values, properties, valreps, creation and deletion of occurrences, etc.

Application developers take charge of the presentation layer

With Uniface 10.3, we have now also opened up the presentation layer of the client: the Document Object Model (DOM) layer. Using a simple function, a Uniface data object can now get a reference to its bound element in the DOM layer, allowing Uniface developers to access DOM elements in the context of that field, its occurrences, and its instance. The function is: uniface.field.getBoundElement(ViewId)

From the bound DOM element, it is possible to navigate to sibling and parent elements. In case of an AttributesOnly field, the same technique can be used to navigate to child elements. This gives Uniface developers full control of the DOM, allowing integration of third-party JS libraries that integrate at DOM level.

An example

In the following code example we will use the new JS function to change the default reporting of client side syntax errors.

The webtrigger onSyntaxError is the trigger that gets fired the moment the client encounters a syntax error. The default way for Uniface to respond in this situation is to set an error class on the element bound to the field that is in error. CSS would then style it appropriately. The code below overwrites the default behavior and sets the error class to the parent element of the element bound to the field:

webtrigger onSyntaxError
javascript
  // Get field in the data structure
  var field = this;
  // Get bound element of field in layout
  var fieldEl = field.getBoundElement();
  // Get parent of element
  var parentEl = fieldEl.parentElement;
  // Set error class on parent element instead of the field element itself
  parentEl.classList.add(“-highlight-error-“);
  // Prevent default error reporting
  return false;
endjavascript
end

Conclusion

The getBouldElement() function is simple to use and provides full access to the DOM layer of the browser. It opens up communication with any JS technology that needs to interface on the presentation layer.

The Struct and its references

 

Hi bloggers,

For the ones that do not know me, I’m Gerton Leijdekker, Usability Consultant and Lead Developer for the Uniface product line in the Uniface Lab in Amsterdam. My intention is to blog about technical subjects, so this first blog will be about the Struct.

With Uniface we always try to keep things simple with the intention to keep it a productive tool; don’t bother with complex stuff, simply plug in the features you need, some ProcScript to glue them together, and done. But simplicity also has a downside, because now and then you just need more…

Some features take the enablement approach, where the functionality can be used to solve a wide range of problems. But where simplicity adds limitations, flexibility adds complexity and complex things are most of the time harder to understand. The Struct is one of them: powerful, flexible, useful … but complex.

The Struct is introduced in Uniface 9.5 and can solve a variation of challenges, like data transformations, data communication, and data processing. The Struct has no format limitations and therefore can handle any data format, whether it is Entities, XML, JSON, or your own custom format. But in all cases it helps if you fully understand what a Struct is and how it works.

Currently, I’m working on the new Uniface 10 IDE and we use the Struct for almost everything. It replaces entity, occurrence, list, and xmlstream parameters and is heavily used for data cashing purposes. But although I was involved during the original design of the Struct, now that I need to use it, I still find it a challenging thing to use and it took me some time to fully grasp its concepts. In this first blog, I will focus on its core technical concepts being the Struct itself, the Struct Node, the Struct Variable, and the Struct Node Reference. To me it was very helpful once I fully understood those.

The info in this blog is also being used to update the Uniface Library, but remember, you read it here first. 🙂

The Struct

The Struct is a collection of objects, called Struct Nodes. These Struct Nodes are hierarchically organized, hence the term ‘struct’. Every Struct Node can have i/o refers to 0, 1, or more child Struct Nodes. The Struct always has only one root Struct Node.

The image shows two Structs as the reside somewhere in Uniface memory:

Struct Image 1

The Struct Variable

You can declare a struct variable the way you like any other variables, but unlike to variables of type String, Numeric, or Boolean, the Struct Variable does NOT contain the data itself; the Struct Variable only refers to the struct data that (as said) resides somewhere in Uniface memory. To be more specific, a Struct Variable refers to the root Struct Node of a struct dataset making this dataset the thing we call ‘Struct’.

The image shows two Struct variables referring to the root node of a Struct.

Struct Image 2

 

A Struct Variable can actually refer to multiple Structs or to none at all.  To be specific, a Struct Variable can refer to 0, 1, or more Structs.

The image shows a single Struct Variable containing 2 references to two Structs.

Struct Image 3

The opposite is also possible: multiple references to the same Struct.

The image shows two Struct Variables referring to the same Struct. One has to refer to the root node, the other refers to some node in the same Struct making it a kind of sub-Struct or nested Struct. More about this construction later.

Struct Image 4

 

Struct Variable declaration

The declaration of a Struct Variable, does not create the Struct, it only creates a Struct Variable with zero references. This variable can now be used to either create a Struct from scratch or have it referred to an already existing Struct.

The image shows two Struct Variables that do not refer to any Struct.

Struct Image 5

 

Struct creation

There are two ways to create a Struct.

The first is by making use of the Proc function $newstruct. This Proc function creates a single Struct Node and returns a reference to it. If this reference is then assigned to a Struct Variable, a Struct consisting of a single node, has been created.

The image shows the code used create a Struct with only one node. This Struct is now accessible via the Struct Variable.

Struct Image 6

 

The second is by making use of the conversion Proc statements like componenttostruct, xmltostruct, and jsontostruct. Maybe more conversion statements will follow in the future. A struct conversion function uses the provided data in some external format and generates a (huge) set of hierarchical related Struct nodes that logically represent the data. The Proc instruction returns a reference to the root node of this Struct which is typically assigned to a Struct Variable. This Struct is now accessible via the Struct Variable.

Struct Image 7

 

Struct member creation

To create a sub node, or a Struct member, you also use the Proc function $newstruct, but instead of assigning the newly created node to a Struct Variable, you assign it to a member a specified by its name.

The image shows the code used create the initial Struct and then how members are created.

The image also shows how an existing member is assigned to a Struct Variable, creating a sub-struct or nested Struct.

Struct Image 8

 

Struct deletion

A Struct that is no longer referenced by a Struct Variable, and therefore not accessible, is automatically deleted from Uniface memory.

The image shows that setting “” to the Struct Variable that refers the root node of the Struct will have as a consequence that the Struct will deleted. A Struct Variable running out of scope has the same effect.

Struct Image 9

 

The image shows that deleting a Struct does not affect any sub or nested Structs. The sub Struct, or nested Struct, has its own variable referring to its root node (this is what makes it a Struct) and therefore is still referenced and not deleted.

Struct Image 10

 

Struct parameters

Uniface also supports Struct Parameters. The Struct Parameter is like the Struct Variable, it works with references.

Image a Proc function that takes one struct parameter as input, it checks all members of the referenced Struct and returns references to the members that are leaves as Struct out parameter. The image shows the result after calling this function, where myStructVar1 refers to the root node of the Struct and myStructVar2 refers to all leaves in the same Struct as detected by the function.

But more about Struct Parameters next time.

Struct Image 11

That’s it for now, next time more about passing structs by reference and by value. Gerton's Emoticon

Gerton