Jump to content
Claris Engage 2025 - March 25-26 Austin Texas ×

This topic is 6627 days old. Please don't post here. Open a new topic instead.

Recommended Posts

Posted

Hi,

I want to allow a user to enter data (e.g. weight in lbs. and ozs.) in an easy shorthand ("5 3") and have a triggered script reformat that into a rigid form ("5#03"). I have been trying to use EventScript with an auto-enter calculation, without complete success. I have not been able to get the normalized data back into the input field.

Here's how I've tried organizing it, normalizing a zipcode as a simple example. Using the debugger tools, everything seems to work properly until the auto-enter calculation attempts to return y, the normalized zipcode. Nothing is plugged into the field. Can anyone see where I'm going wrong?

ZIP is defined as

  • text
  • auto-enter
  • calculated value
  • replace existing value
  • evaluate even if referenced fields are empty

Auto-enter Calc:

:D

"" & Let ( [ x = NormalizeZIP ( ZIP ) ; y = Get ( ScriptResult ) ] ; y )




function NormalizeZIP ( zip ) 
S4HU_EventScript( Get(FileName) ; "NormalizeZIP" ; zip )




script NormalizeZIP ( zip ) :




Set Var [$inputZIP ; Get ( ScriptParameter ) ]

Set Var [$outputZIP ; Filter ( $inputZIP ; "0123456789" ) ]

If [ Length ( $outputZIP ) != 5 ]  // "not-equal"

   Set Field [g_foo ; $inputZIP ]

   Show Custom Dialog [ "Zipcode error" ; "Zipcode must be 5 digits" ; g_foo ]

   Perform Script ["NormalizeZIP" ; Parameter: g_foo ] // recursive call

   Set Var [ $outputZIP ; Get ( ScriptResult ) ]

End If

Exit Script [ Result: $outputZIP ] // script returns normalized zip as result

Posted

I don't see what zip codes have to do with pounds and ounces. A simple auto-enter calc with the "Do not Replace" option unchecked should suffice to reformat your pounds and ounces.

As for your script, you don't seem to be setting the result to the field.

Posted

I don't see what zip codes have to do with pounds and ounces. A simple auto-enter calc with the "Do not Replace" option unchecked should suffice to reformat your pounds and ounces.

What I'm really trying to learn is how to grab and modify an input field where the modification algorithm is sufficiently complex to require a script. I shouldn't have mentioned pounds and ounces; the zipcode example was meant to serve as a trivial concrete example for discussion of the general technique.

As for your script, you don't seem to be setting the result to the field.

By declaring (for example) the field FirstName to be auto-enter by calculation, and writing a calculation that, let's say, evaluates to "Mr. " & FirstName, I can modify the input. I type "Chap", hit the tab key, and it changes to "Mr. Chap". There isn't any need to explicitly set FirstName from the calculation. It seems to me that triggering a script via EventScript, and returning a value computed by the script as the result of the auto-enter calculation, should behave in the same way. Am I missing something?

Posted (edited)

The EventScript doesn't by itself set a field. You'll need to use Set Field[] or have the auto-enter calc evaluate the script result.

EDIT:

Oh, I see you have that in your auto-enter calc above. Must have missed it in between the pounds and ounces.

In that case, I don't have an explanation. But you should be able to troubleshoot it. Figure out if the script is working correctly. Do you have the auto-enter calc's "Do not replace..." option unchecked?

Edited by Guest
Posted

I've been following this thread in total perplexion.

What I'm really trying to learn is how to grab and modify an input field where the modification algorithm is sufficiently complex to require a script.

There are no 'modification algorithms' sufficiently complex that can't be handled within a calculation except for recursion (and you even have Advanced) so you don't need a script - an Auto-Enter (with Replace) would handle it all. The purpose of script triggers on fields is to fire a script which PERFORMS AN ACTION when the value in the triggered field changes - not something that again affects the field the event trigger is within.

I haven't used S4HU (I have SecureFM) and they may handle things differently. I can't even figure the logic of your calcs and examples. If the FirstName CHANGES (remember there must be something that happens at the field level which triggers), then your script would be fired at that moment (script may change layouts, re-sort and so on. There is no need to use event trigger if you want to simply change another field's value (within same table) to something else - auto-enter on THAT field would handle it fine. So First Name would be set as Auto-Enter (be sure to UNCHECK 'Do Not Replace Existing Value') and that FirstName field must again be referenced within the calc (at least in SecureFM):

FirstName & External ( "Menu-PerformScript"; "yourSortScript") *

* SecureFM example

Then when FirstName changes, your script will fire. You must be very careful because ANY time FirstName changes that script will fire so it can fire when you create a new record! WHEN it fires must be controlled within the script (such as only fire if on the proper layout). Again, the purpose of field-triggers is to fire when field value changes. You still haven't provided an example of needing one in this instance ... which is usually the case. That is why event triggers should be handled with prudence. If one doesn't know exactly what they are doing, they will be in for BIG surprises when least expected (been there done that). :

LaRetta

Posted (edited)

There are no 'modification algorithms' sufficiently complex that can't be handled within a calculation....

That's hard to believe! Suppose I wanted to take the input field, call a script to call AppleScript to call the BSD shell to run a Perl script to pass the input to a server on the Internet to translate the input field into French, and replace the input with that. Silly, of course, but I'm not sure how you could make that TCP/IP connection using FM's functions.

In a more practical vein, I could imagine putting up a Custom Dialog when the input is invalid, and give them a chance to re-enter it. Again, not sure how to do that with functions.

I'm having two problems, it looks like. One is that my Auto-enter Calc lacks the smarts to identify the conditions when I actually *do* want to run my script, versus conditions when I just want to ignore it. I can build that in.

But the more serious problem is that S4HU_EventScript doesn't appear to run the script synchronously. From what I can see, the S4HU_EventScript function completes before the script ever runs. (I remember some notes about queuing that I need to check.) If this is the case, then this is why it isn't behaving the way I expected it to.

Perhaps this is a limitation of S4HU, and there are other triggering plugins that will "block" until the script finishes.

Edited by Guest
add example of custom dialog
Posted

Suppose I wanted to take the input field, call a script to call AppleScript to call the BSD shell to run a Perl script to pass the input to a server

That is an action and script would write back to field using Set Field [ ]. I explained the difference between auto-enter calculation and performing an action. Again, I see no concrete examples to work with ... you don't effect change on the standard field - the standard field (by changing) fires your script. :wink2:

I know nothing of your second problem, sorry. I DO recall reading a post about it - try searching for S4HU.

Posted

That is an action and script would write back to field using Set Field [ ]. I explained the difference between auto-enter calculation and performing an action.

Right, I saw it. Is there a technical definition of the word "action" in the context of Filemaker, or databases? To me, "action" has no special meaning.

Basically I thought, because the method (or more technically, "hack" ;-) for driving an after-event script with S4HU used Auto-Enter Calculation, that this allowed one to use a script as an "extension", if you will, of the calculation. It appears, though, that the S4HU_EventScript() function is unusual in that it completes *before* the script is ever run. I've not found any discussion about this in the FMForums searching for "S4HU" - but I've written to the developer for clarification.

Again, I see no concrete examples to work with ...

I want to give users a shorthand notation for entering pounds and ounces, or durations of time in hours and optionally minutes. In each case, the user should be able to type one or two numbers with practically anything as a delimiter ("7 11", "4.6"), and when he hits tab, some code will run which will parse the input, neaten it up into a standard form (7#11, 4:06, etc.), and, if there is some problem with the input (ounces greater than 15, minutes greater than 59, etc.), give an error message and allow the user to re-type the input.

And maybe, with sufficient work, I can accomplish all of that using an ordinary auto-enter calculation. But it made me interested in finding a more generalized solution wherein the full capabilities of ScriptMaker, AppleScript, BSD, heck - the Internet :chili: - could be brought to bear.

Posted

I can accomplish all of that using an ordinary auto-enter calculation

By the look of it is it straight forward autoentering!!!!!

--sd

Posted

I think you are not taking into account some things:

- EventScript is a plugin, and therefore it appears to Filemaker as a function. Filemaker evaluates the function. It does not 'know' that a script is triggered in the process.

- I don't know of a way for a script to pass its result to a field - other than by Set Field[].

I believe the way to achieve what you want is to make the auto-enter calc along the lines of:

Case (

and IsEmpty ( Get ( ScriptName ) ) ;

Field & ;

Field

)

and the script is simply:

# do whatever

Set Field [ field ; ]

Posted

- EventScript is a plugin, and therefore it appears to Filemaker as a function. Filemaker evaluates the function. It does not 'know' that a script is triggered in the process.

No; why should it? At some point in the plugin, it *must* call some routine ("DoScript" let's call it) within the Filemaker binary, communicating a request to run MyScript in MyFile with MyParameters. Does DoScript complete immediately once the request has been queued, or does it wait until the script has run to completion? Because until DoScript completes, S4HU_EventScript won't complete, meaning my auto-enter calculation won't complete, meaning Filemaker won't complete the auto-entry.

Apparently, from what I've been seeing, the hypothetical DoScript simply queues the request and then returns. If so, then having the script explicitly Set Field() is the only way to do it.

Case (

and IsEmpty ( Get ( ScriptName ) ) ;

Field & ;

Field

)

Nice summary, thank you.

Posted

until DoScript completes, S4HU_EventScript won't complete, meaning my auto-enter calculation won't complete

I don't think that is an accurate description of the situation. Suppose the auto-entered calc is:

Case (

IsEmpty ( Get ( ScriptName ) ) ;

Field - 100 & ;

Field

)

and that the script is:

Pause/Resume Script [ Duration (seconds): 5 ]

Set Field [ Table::Field; Table::Field * .5 ]

Now if you enter 500 into the field and tab out, the auto-entered calc immediately changes it 400 and runs the script. That, I would say, means the auto-enter calculation is complete as far as Filemaker is concerned. You can move on to the next field and enter data into it. Meanwhile the script is paused, and after 5 seconds the value is changed to 200.

Posted (edited)

I don't think that is an accurate description of the situation.

I found the plugin API that is provided to plugin writers. There's one C function prototype called FMX_StartScript, and though it's not well documented at all, I infer from its name that its job is to put the script in some sort of execution queue, and that's all.

Anyway, substituting "FMX_StartScript" for "DoScript" above, yes, I'm all but certain it is an accurate description of the situation -- whenever one procedure calls another, it waits for the called procedure to complete before continuing. In your example, I've replaced with S4HU_EventScript( file, script, parms ) :

Case (

IsEmpty ( Get ( ScriptName ) ) ;

Field - 100 & S4HU_EventScript( file, script, parms ) ;

Field

)

S4HU_EventScript runs, calls FMX_StartScript which places the request to run a script on a queue in Filemaker, and returns to S4HU_EventScript, which returns to your expression, where Field - 100 & "" is computed and returned to Filemaker as the calculation result, which FM plugs as the auto-enter value and then tabs you into the next field. Meanwhile, as FM gets a few cycles to spare, it gets busy on queued tasks, one of which is to run our script.

In other words, the chain of events I described is basically correct, FMX_StartScript does do its job before completing -- it's just that its job is not what I wanted it to be! It only schedules the script for (eventual) execution.

Edit: add...

I don't see anything useful in the Plugin API that would allow a plugin to suspend execution pending the completion of the queued script. Oh well!

Edited by Guest
Posted

I am not sure what you're saying. It seems that we agree that the auto-enter kicks the script and goes on about its business without caring what happened to the script. To me, the FUNCTION S4HU_EventScript() is completed when it has been evaluated and returned "". That is the point where 500 has turned into 400.

Posted

I am not sure what you're saying. It seems that we agree that the auto-enter kicks the script and goes on about its business without caring what happened to the script. To me, the FUNCTION S4HU_EventScript() is completed when it has been evaluated and returned "". That is the point where 500 has turned into 400.

Exactly! Yes, we're in complete agreement.

I made an incorrect assumption about S4HU_EventScript. I assumed that it kicked the script and then waited until the script ended before going on about its business.

I think that an external function that would actually run a script to completion (the way I expected it would) would be extremely useful, if it were possible. However, from looking at the Software Developer's Kit list of API's for writing FM plugins, there doesn't seem to be any way to do this.

If anyone's actually interested, someone sent me some useful links providing further information about writing plugins and what can be done.

MacTech article

www.murrayc.com site

Posted

I know nothing about writing plugins, but I wonder what would be the use of waiting for the script to finish. It's not like it makes (or can make) any difference to the field.

It would be slightly different if the plugin could get the script result and return it as its value to the auto-enter calc. I am not sure if that is possible, but in any case ending the script with Set Field[] achieves the same thing.

Posted

I wonder what would be the use of waiting for the script to finish. It's not like it makes (or can make) any difference to the field. It would be slightly different if the plugin could get the script result and return it as its value to the auto-enter calc. I am not sure if that is possible...

I don't think the plugin could get the script result, but I think this would work, assuming that MNDU_RunScript waited for the script to finish:

Auto-enter calculation for Weight:


Case (  ;

Let 

( 

[ x = MNDU_RunScript ( Get ( FileName ) ;

"NormalizeWeight" ; Weight 

] ; 

Get ( ScriptResult ) 

) ;   // end of Let

Weight

)     // end of Case





x would just indicate programming error, like S4HU_EventScript.



NormalizeWeight script:




Set Variable ( wt ; Value: Get ( ScriptParameter ) )

// massage / manipulate / transform wt into "normal form"

Exit Script ( Result: wt )

Although it's moot, the advantage would mainly be that the script call was synchronous rather than asynchronous, so you'd be guaranteed that nothing would change while the script did its thing.

Posted

I think waiting for the script to finish is not enough - there's the matter of catching the result, which only exist for a split second - if at all ("The script result gets deleted when you exit the main script", says the help). And for what? What's the advantage of "nothing would change while the script did its thing"?

If the script has "to call AppleScript to call the BSD shell to run a Perl script to pass the input to a server on the Internet to translate the input field into French", I would rather go:

Case (

;

"Evaluating..." & ;

Field

)

then letting the user stare at nothing happening.

It's not to say that a function like GetScriptResult ( fileName ; scriptName ; parameter ) would be entirely useless - but at this point I'm afraid it's merely wishful thinking.

Posted

I think waiting for the script to finish is not enough - there's the matter of catching the result, which only exist for a split second - if at all

Hm - you're right. However, it looks like a global variable will do the trick. $$myResult can be set in the script, and returned in the auto-enter calculation.

And for what? What's the advantage of "nothing would change while the script did its thing"?

That's important. When the script is allowed to run "concurrently" with the user interface (as my original idea using S4HU_EventTrigger would have), you have two "threads of execution" sharing a single resource - the current layout. In the time that it takes for the script to finish, the user might have retyped the field with the trigger, navigated to a different record, or to a different layout. When the script finally issued Set Field to deliver its result, the landscape would have quietly changed and it would either clobber the field the user was attempting to type into, or plug the result into the wrong record. Whatever, it wouldn't be right. Short of trying to add a plugin to manage asynchronous events : I'd rather just suspend the user interface while the script runs.

Actually, unless you need some specific functionality of FMScript, why bother with it? An external function that could pass commands directly to the BSD Unix layer, and get results back, would avoid the asynch issue entirely, and allow us to code in Perl.

It's not to say that a function like GetScriptResult ( fileName ; scriptName ; parameter ) would be entirely useless - but at this point I'm afraid it's merely wishful thinking.

Indeed! :

Posted

unless you need some specific functionality of FMScript, why bother with it?

Because it's there, it's easy to work with and, most importantly, it's cross-platform.

This topic is 6627 days old. Please don't post here. Open a new topic instead.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.