So you have to assemble a string containing the function call and its parameters, something like this:
var JSFn: string; StrParam: string; IntParam: Integer; FloatParam: Double; begin StrParam := 'Say \"Hello\"'; // double quotes must be escaped IntParam := 42; FloatParam := 1234.56789; JSFn := Format('Foo(%d, "%s", %.8f);', [IntParam, StrParam, FloatParam]); ExecJS(JSFn); end;
The interesting bit is what happens to the floating point parameter. Delphi consults the current locale when formatting floats, so the decimal separator used in the resulting string depends of the locale. For example, on my UK English system JSFn has value:
Foo(42, "Say \"Hello\"", 1234.56789000);
whereas when I switch to a German locale the value changes to:
Foo(42, "Say \"Hello\"", 1234,56789000);
'.' as the decimal separator, which means that any
',' separator is not valid. In fact
',' is the parameter separator so a parameter of
'123,4567' is interpreted as two integer parameters:
You also have a Delphi program that loads the HTML document into a TWebBrowser control and has the following code attached to a button click:
ExecJS( Format('showNum(%.8f, %.8f)', [123.456, -42.56]) );
which is what you expect. Switch to a German locale and run again and you'll get:
n1 = 123.456
n2 = -42.56
n1 = 123
n2 = 45600000
Luckily the fix is simple. We simply get information about the current decimal separator and change it to a
Here's my first attempt:
function JSFloat(const F: Double): string; begin Result := FloatToStr(F); if DecimalSeparator <> '.' then Result := StringReplace(Result, DecimalSeparator, '.', [rfReplaceAll]); end;
This uses the DecimalSeparator global variable that Delphi sets correctly for the current locale when the program starts.
ExecJS( Format('showNum(%s, %s)', [JSFloat(123.456), JSFloat(-42.56)]) );
Using DecimalSeparator is not thread safe, and I think the code is rather clunky, so here's another, thread safe, version of JSFloat that I prefer:
function JSFloat(const F: Double): string; var FS: TFormatSettings; begin GetLocaleFormatSettings(GetThreadLocale, FS); FS.DecimalSeparator := '.'; Result := FloatToStr(F, FS); end;
This gets the format settings for the current thread's locale and then replaces the decimal separator with the required
'.'. It uses the extended version of FloatToStr to convert the float according the provided locale.
Note that this code doesn't change the locale's decimal separator because we're operating on a copy of the locale information. Therefore we won't trample on any other parts of the program that may need the the correct decimal separator for the locale.
One further tweak suggests itself that takes advantage of the fact that the Format routine can take an optional TFormatSettings parameter:
var FS: TFormatSettings; begin GetLocaleFormatSettings(GetThreadLocale, FS); FS.DecimalSeparator := '.'; ExecJS( Format('showNum(%.8f, %.8f);', [123.456, -42.56], FS) ); end;
And finally, the promised implementation of the ExecJS method. Note that this is a method of the form that contains the browser control, which we assume is named WebBrowser1.