Dynamically naming forms, elements, fields, etc.?

Marcel set my grey matter churning when he pointed out that I could do this:

forms[currentcontroller.getName()].yourNewMethod();

… effectively naming the current form at run time within a method.

I’ve since used elements the same way, to request focus on an element named in a variable. (A form’s validation routine calls a global error handling method, and passes to that method the message to show, and the element on which to focus upon return, for error correction.)

Is there a way to identify a relationship/dataprovider dynamically, too? Something like “forms[currentcontroller.getName()].relationship [getRelation].dataprovider [getFieldName()] = ‘xxxxx’;” to set the current field to ‘xxxxx’?

Pardon the horrid pseudo-code, but I just don’t know what the syntax would be. I can’t find a clear reference in documents, help, etc. to even the forms and elements naming that I now understand. Am I looking in the wrong place?

I could, for example, use this in a phone mask, where I have three phone numbers showing on a page, each of which is via a different relationship to the phones table. It’d be nice to have my global phone mask method just set the result in the current field. There are other ways to do this, of course, but this method would be a nice addition to my toolbox. :-)

try this:

var x = forms['formname'].foundset['relationname']['dataprovidername'];

Excellent! My methods just keep getting shorter and shorter! 8)

Now how can I capture the name of the relation and dataprovider that the user just edited? I can come up with two ways, but is there a command I’m missing?

  1. give the element the name of the relation and dataprovider, then use getMethodTriggerElementName and parse that out.

  2. (less desirable) create a method for each field and form, which passes the data, the relationship and the dataprovider as arguments to a global method.

My copy of the Advanced Programming for FMP Developers may be out of date, but it says there’s no Servoy equivalent for status (currentfieldname). Still, is there a simpler way that I’m missing?

no there is only current form an element.
So you have to build youre own mapping if you want to get the relation/dataprovider

for example make a array where you add all the possible form/element combinations which are pointing to relation.dataprovider.

That you have to do this once in a solution startup script..

I’m afraid I don’t follow…

Is this a method that would loop through each form and element? How would it get the dataprovider?

I’m sure I’m misunderstanding…

you have to do youre own housekeeping in one method (for example the solution startup method)

where you do this:

var elementToRelationMapping = new Array();
elementToDataproviderMapping['formX.elementY'] = 'relationA_to_B';
// ect.
globals.elementToDataproviderMapping = elementToDataproviderMapping;

then in a script that get’s triggerd by an element:

var dataprovider = forms[application.getMethodTriggerFormName()].elements[application.getMethodTriggerElementName()].getDataProviderId();
var key = application.getMethodTriggerFormName() + "." + application.getMethodTriggerElementName();
var value = forms[application.getMethodTriggerFormName()].foundset[globals.elementToRelationMapping[key]][dataprovider];

One problem that i can think of is that getDataProviderId() can already return a value with the relationname in it (divided by a “.”) that are elements on a form that displays its data of a relation.
The only key is to know what relation is used by a element that shows inside a tabpanel. And that you can do with that global variable that you can make in a global solution startup method.

i hope this makes things a bit more cleared, it is pretty advanced.

I think I’m starting to get the idea…

Do I understand correctly, though, that I would add each element to the first bit of code, to map it to a dataprovider?

Wouldn’t it just be simpler to name the element the same as the dataprovider, so that this mapping wouldn’t be required?

I’ll still have the issue with tabpanels, though.

you can already get the dataprovider from an element!
see the getDataProviderId() method..

you need a map that says what kind of relation it is yes. There is no other way.

Ah. I hadn’t seen the getDataProviderID. Makes a big difference.

In your code, though, are you setting an array variable into a global? I didn’t think you could do that. I get an error when I try.

you shouldn’t make the global through dataprovider dialog or if you make it do make it of a media type! (in a string you can’t set an array)

but todo this:

globals.xxxx = yyy;

you don’t need to have a xxxx in the globals dataprovider dialog. Defining a global is only needed if you use it for a relation or want to display a element.

Wow! I was totally unaware that that was possible. My head is spinning with possibilities now. Thanks so much (again)!

The following method was my (primary) objective on this thread. Thanks to all your help, Johan, I think I’ve got something that might even be useful to others, so I thought I’d share.

This phone formatting method can be triggered on data change for any phone field, on any form. Oddly enough, it does work on a tabpanel, but the tabpanels currently in question are showing a form view rather than a list view, so not sure how that would turn out.

The method uses the current field contents, and matches it against a format using ‘#’ as a wild-card. It could easily be altered to other formats, or even have formats passed to the method based on country.

The method will opt out if the current field doesn’t contain numbers, or starts with ‘+’, as international calls do here.

Anything beyond the format is formatted as an extension, either using the descriptive ‘ext’ or whatever that’s in the number, or supplying ‘x’ if not.

Enjoy, and as always, feedback is appreciated.

// gather information about where the user is and what s/he entered
var eleName = application.getMethodTriggerElementName();
var frmName = application.getMethodTriggerFormName();
var fldName = forms[frmName].elements[eleName].getDataProviderID();
var fldContents = forms[frmName].controller.getDataProviderValue(fldName);
// exit if there's nothing in the field to format

if (!utils.stringToNumber(fldContents) || utils.stringLeft(fldContents,1) == '+')
{
	return;
}
// Set initial variables.
var entry = fldContents;
var phone = '(###) ###-####';
// first fill in the format pattern
while (utils.stringPatternCount(phone, '#')>0 && entry )
{
	if(utils.stringPatternCount('0123456789',utils.stringLeft(entry, 1)))
	{
		nextPosition = utils.stringPosition(phone, '#', 1, 1 );
		phone = utils.stringIndexReplace(phone, nextPosition , 1 , utils.stringLeft(entry, 1));
	}
	entry = utils.stringRight(entry, entry.length - 1);
}
// if there's more, fill in initial letters beyond the format, such as 'ext' or 'x'
if ( entry )
{
	if(utils.stringPatternCount('0123456789',utils.stringLeft(entry, 1)))
	{
		phone += ' x';
	}
	else
	{
		phone += ' ';
	}
}
while (entry && !utils.stringPatternCount('0123456789',utils.stringLeft(entry, 1)))
{
	phone += utils.stringLeft(entry, 1);
	entry = utils.stringRight(entry, entry.length - 1);
}
// if there's still more, enter remaining numbers
if ( entry )
{
	phone += ' ';
}
while (entry)
{
	if(utils.stringPatternCount('0123456789',utils.stringLeft(entry, 1)))
	{
		phone += utils.stringLeft(entry, 1);
	}
	entry = utils.stringRight(entry, entry.length - 1);
}
forms[frmName].foundset[fldName] = phone;

This method has quit working for some reason. :oops:

See this thread: Phone Formatting - Classic Servoy - Servoy Community