UI programming

Is it possible to select for a given form all the (named) elements of a certain type. If not could it be made possible :wink:

To clarify two examples:

  1. on a form I have say 15 buttons. I want to disable them all but one. So if I could grab an array with all the elements of type button (or label or tabpanel) it would be very easy to do a for loop with the disable command (and ending with an enable command for the one button)

  2. I have maybe five forms all of the with a tabpanel (1) on them. If I could ask a given form (getMethodTriggerForm()) for the name of its tabpanel, I can control all the tabproperties (and the forms on those tabpanels) while having a much cleaner and more generalised code.

To sum it up: I want to be able to interrogate the elements array by TYPE having as the result an array with all the elements of that type

Possible ?

I don’t believe you can query the type of an element. Besides how do you distinct a label from a button or an image.
I guess the only way would be to use a naming convention like:

btn_name
fld_name
lbl_name
tab_name
img_name

You can fetch the elements in an array and check the naming convention for the type.

When debugging you can see that the arguments array -->parent–>elements can make a distinction between the different types of elements.
In my case I can see that on the form there is a SpecialTabpanel, some datalabels and some scriptbuttons.
I’m not sure where the distinction (datalabels & scriptbuttons) comes from but the point is Servoy knows about the distinction, so the only thing we need is acces to this information through something like
var arBtns = getElementsArray(#ofType)

Frustrating when you don’t have a way of accessing the info that is lying in front of you :cry:

Using a naming convention is a workaround, but not a solution.
I think internally Servoy is using this elementtype for instance when switching to find mode (and disabling the buttons on your form)

You have to admit that having this possibility would create a whole new level of abstraction in programming the UI and thus eliminating a bunch of (less abstract) form level methods

You can make some distinctions between elements based on properties that they have, and so can work with that to some degree. For example I have a form with radio buttons and text fields that I put together as one of my first learning excersizes where I loop through all the text input elements and modify their contents, but I ignore all the radio buttons.

I use a naming convention for the radio buttons because each one is for use with a specific text input field. It isn’t needed to determine it’s type though.

// when user presses Find...

var form = application.getMethodTriggerFormName();
var fieldDataProvider = "";
var fieldContents = "";
var vListName = "";
var searchElementName = new Array();
var searchValue = new Array();
var targetfield = "";
var targetfieldContents = "";
var i = -1;
var j = 0;

// loop through all the elements
for ( j = 0 ; j < forms[form].elements.length ; j++ )
{
	if (forms[form].elements[j].getDataProviderID() != null )
	{
		fieldDataProvider = forms[form].elements[j].getDataProviderID();
		fieldContents = forms[form].controller.getDataProviderValue(fieldDataProvider);
		vListName = forms[form].elements[j].getValueListName();
		// If it doesn't have a value list then we're interested in it.
		if ( vListName == null )
		{
			//we only want to deal with it if the field has something in it.
			if ( fieldContents != null && fieldContents != "" )
			{
				// increment the array of found elements
				i++
				elementName = forms[form].elements[j].getName()
				// the selection criteria field are all named with the prefix of "findtype_"
				targetfield = "findtype_" + elementName;			
				targetfieldContents = forms[form].controller.getDataProviderValue(targetfield);
			
				// add in wildcards for the appropriate search type.
				switch(targetfieldContents) 
				{
					case "Exact":
						targetfieldContents = fieldContents;
						break;
					case "Begins":
						targetfieldContents = fieldContents + "%";
						break;
					case "Ends":
						targetfieldContents = "%" + fieldContents;
						break;
					case "Contains":
						targetfieldContents = "%" + fieldContents + "%";
						break;
					default:
						targetfieldContents = "%" + fieldContents + "%";
				}		
				// update the array of search elements
				searchElementName[i] = fieldDataProvider;
				searchValue[i] = targetfieldContents;
			}	
		}
	}
}



//delete the record that was created just for the search.
forms[form].controller.deleteRecord()

forms[form].controller.find();
for ( j = 0 ; j < searchValue.length ; j++ )
{
	forms[form].controller.setDataProviderValue(searchElementName[j], searchValue[j] )
}

forms[form].controller.search();

// go to customer layout.
application.showForm('customers');

Yes possible! And quite simple. Run this code and check out the variables in the debugger:

for (var i in elements)
{
	var y = elements[i]
	var elementType = utils.stringLeft(y, utils.stringPosition(y, "[", 1, 1) - 1)	
}

This will loop through ALL of the objects (named “elements”) on a form – whether they are named or not. This is possible because everything in Servoy is an associative array. For more on this subject:

http://www.servoymagazine.com/home/2005 … ek__2.html

(Note: the function “elements.length” returns the number of named elements – not the number of all the elements on a form. Hence why you need to use the type of loop above to get to all of the elements.)

“DataField[fld_country:country]” would be a sample string returned into var y. The first part is the object type, then the name you give it, the data provider name, and finally the data. Which you can then obviously parse yourself and do all kinds of funky things with depending on the values.

If all you are doing is disabling all the objects on a form, you would never need to name them using this technique. Name the object only if you are referring to it individually.

Not sure how long this “feature” will work (as this is poking at the Servoy structure and it could change) but it has been available for a while now.

Thank you all

Code:
for (var i in elements)
{
var x = elements.name
var y = elements
var elementType = utils.stringLeft(y, utils.stringPosition(y, “[”, 1, 1) - 1)
}
This will loop through ALL of the objects (named “elements”) on a form – whether they are named or not. This is possible because everything in Servoy is an associative array. For more on this subject:[/quote]
This is what I had in mind. However, given the weakness (with all due respect David) of basing code on strings, I would rather hope for a Servoy endorsed solution (assuring me that I won’t have to come back to recode my solution when an upgrade breaks the functionality of the code)
So do we agree on the usefullness of such a function ?
:)

As in: elements[objName].getType()

I agree, could be quite useful.