Skip to content

WNamingContext

Mark Reeves edited this page Jan 3, 2018 · 9 revisions

WNamingContext is one form of naming context within WComponents. A naming context provides a means to isolate segments of a view to allow reuse of UI components without id duplication. In WComponents a naming context allows reuse of components with custom IDs. If custom IDs are not required then naming contexts are not required.

Why use WNamingContext

WNamingContext provides means to apply a naming context without having a specific UI artefact. WRepeater and WTable naming contexts are automatic as they are known to contain repeated components.

The naming context is given its own idName (ID). This ID is then used as part of the ID of all nested components, including any nested naming contexts. Parts of an ID name added by naming contexts are separated by a DASH (-).

// creating a named context.
WNamingContext nc = new WNamingContext("My_Named_Context");

Using WNamingContext

Duplicate IDs

There is a brief discussion of setting a custom component id in WComponents ID property. WComponent IDs must be unique, therefore if a particular ID was applied to a component, and that ID was genuinely static, it would be vital the component is not used more than once in a particular view; similarly it would be equally important that the same static ID string was not used on different components where more than one of these components appears in any given view.

This may seem make it difficult to use static IDs:

  • in repeated components such as those in a column of a WTable;
  • when components are re-used several times in a view; or
  • when parts of a view are produced at different times by different people working from different (or absent) specifications increasing the risk of the same ID string being used.

Avoiding duplicate IDs

The naming context itself has an ID and this id is prefixed to the ID of each component in the naming context in order to overcome the problem of potentially duplicate IDs.

Let's look at an example. Maybe we are registering entrants in a rally. We have a driver and a navigator in each vehicle and we want to capture the details of both in the same view. We would want to re-use a single UI segment because we need to capture the same details for each member of the team.

// given we have a re-usable container class.
WTextField givenNameField = new WTextField();
// set an ID which makes sense to me.
givenNameField.setIdName("Given_Name_Field");
WTextField familyNameField = new WTextField();
// and again let's use a readable ID.
familyNameField.setIdName("Family_Name_Field");
// etc etc.

If we re-use content such as the above we would try to output the same ID ("Given_Name" for example), more than once. So we use naming contexts to isolate the IDs.

// within a container using other reusable components...
WNamingContext nc = new WNamingContext("Driver_Details");
add(nc);
// let us assume we have a person details form segment which comprises a
// WFieldSet containing the given name field and family name fields from
// the example above.
nc.add(new PersonDetailsFieldSet());

// and we want to capture the details of the navigator
nc = new WNamingContext("Navigator_Details");
add(nc);
nc.add(new PersonDetailsFieldSet());

In the example above We would now have a text input with ID "Driver_Details-Given_Name_Field" and one with ID "Navigator_Details-Given_Name_Field" which are unique. A naming context will retain its fixed ID prefix wherever it is in the WComponents render tree. It will have this prefixed with the ID of any other naming contexts it is in.

WNamingContext ncLevel1 = new WNamingContext("Rally_1");
add(ncLevel1);
// ... do stuff
ncLevel1.add(new RallyRegistrationContainer());

In the example above (assuming the RallyRegistrationContainer contains the code sample in the previous example), we would end up with the "Driver_Details" naming context having ID "Rally_1-Driver_Details" and the given name input fields would have IDs "Rally_1-Driver_Details-Given_Name_Field" and "Rally_1-Navigator_Details-Given_Name_Field".

This can get a bit messy...

Using naming contexts

A single naming context could be used to prefix all components in a view. If, for example, you wanted to use web analytics to track several versions of an application UI for split testing you could use a single naming context to differentiate the controls in each split. For most purposes though it would be unusual to have a single naming context wrapping everything in a view.

It would also be a little unusual to have all reusable sub-form classes contain a named context for that sub-form. That would possibly be an over use of naming contexts and lead to more noise than signal.

Somewhere between these there are uses for naming contexts.

WRepeater, WTable and naming contexts.

WRepeater and WTable are naming contexts and their ID will be prefixed to any component in them. This is insufficient for repeated components though. A table may, for example, have many rows each containing the same components with (ostensibly) the same IDs. To get around this these components have a naming context for each row/repitition. If no other action is taken this will result in the naming context for the row being the letter "r" followed by the index of the row. This is able to be set to any unique value held on the Bean which populates the row. Since the WRepeater/WTable is itself a naming context its ID is prefixed to the row identifier so we could, for example, see rows identified as something like "Results_Table-r0", "Results_Table-r1" etc and these would then be prefixed to the ID of each component in that row.

"Static" IDs

For various more-or-less bad reasons some people really want the IDs in their UIs to be immutable. They really need to get over this. It is, however possible to fix component IDs under most circumstances.

  • A component with a custom ID will output an element with that ID if it is not in any naming context;
  • A component in a known hierarchy of one or more naming context(s) will always have the same ID which will be the IDs of all of the naming contexts separated by DASH characters followed by a DASH then the ID of the component.
  • A component in a repeater will have an ID which contains the row identifier and will have a fixed ID if the row identifier has a unique but fixed value from the Bean which populates the row, such as a record identifier, database key etc.

What to do when IDs can't be static

There are many ways to identify a UI component in a HTML page other than by ID. Some of the WAI-ARIA attributes applied to WComponents HTML are very useful for showing the nature of a component and the relationships between components. There are many attributes and properties of the components reflected in the HTML which may be used to identify particular components. Finally, if one is really stuck then one can use the id of a component as a start to finding it. If there is a HTML element with that ID, great, you have found it. Otherwise get the Node list of all elements with an ID ending with the required string.

Given our previous example we can find each instance of the WTextField givenNameField. In JavaScript we could get this Node list using something like:

// given a var ID set to  "Given_Name_Field"
return document.getElementById(ID) || document.querySelectorAll("[id$="+ID+"]");

Test the return value for null then for nodeType to determine if you have a single element or a node list and Robert is your parent's brother.

Further information

Clone this wiki locally