I need to pass arguments to a Excel VBA code from JavaScript of HTA.
I can successfully call VBA function, but unable to pass string arguments correctly.
JavaScript function can pass different string arguments.
Below is code in simple and demo form.
Excel-VBA code
Sub subTest(strName As String)
MsgBox strName
End Sub
HTA code with Javascript
<!DOCTYPE html>
<html>
<head>
<title>HTA</title>
<hta:application
id="oHta"
applicationname="htaNavi"
border="1"
borderstyle = normal
contextmenu = "yes"
caption="Navigator"
sysmenu="yes"
WINDOWSTATE="maximize"
>
</head>
<body>
<input type="button" value="testing" onclick="funRun('testng string')" />
<input type="button" value="testing second" onclick="funRun('testng')" />
</body>
<script>
var objExl;
var objWb;
var objExl =new ActiveXObject("Excel.Application");
objExl.Visible = true;
var objWb = objExl.Workbooks;
var strpath = '\path\testing_excel_web.xls';
objWb.Open(strpath);
function funRun(strName)
{
alert(strName);
objWb.Application.Run('testing_excel_web.xls!subTest(strName)');
}
</script>
</html>
I can call subTest, but message box populates strName as string but not 'testing string' as text.
I'm thinking you want:
objWb.Application.Run('testing_excel_web.xls!subTest("' + strName + '")');
This way, the value of the variable strName is concatenated to the command you are attempting to run.
I know nothing about this calling of a VBA function, so I'm not sure if you need the " around the strName like I provided or not.
In addition, to be safe, in case your strName value contains ", you should use this:
objWb.Application.Run('testing_excel_web.xls!subTest("' + strName.replace(/"/g, "\"") + '")');
Hopefully with this, the value of strName could be
The word "testing" here
or
"Here's a quote"
and it will still work.
The point is that if the string contains ", the Javascript would/could fail. If it would absolutely never contain ", then forget about it. But I think it's needed since any " in the value of strName will break the passing of it as a parameter.
Related
I'm pretty new to Javascript and playing around with it at the moment. However, I can't actually test my code because I get the following error:
Uncaught TypeError: namecaller is not a function
at HTMLButtonElement.onclick (Tools.html:101)
Here is my code:
div id="content">
<script>
function namecaller(){
var a = "scurvy";
var b = "dog";
document.getElementById("namecaller").innerHTML = "You are a " + a + " " + b;
}
</script>
Namecaller</p>
<button type="button" onclick="namecaller()">
You are a...</button>
I have no clue why it doesn't work, looked at other StackOverflow questions and also at the W3 tutorials.
function namecaller() {
var a = "scurvy";
var b = "dog";
document.getElementById("content").innerHTML = "You are a " + a + " " + b;
}
<div id="content"></div>
<button type="button" onclick="namecaller()">
You are a...</button>
The code seems to have a lot of problems like your tags were not in properly written. The tags need to open closed properly. And your script should be in right place so that it gets compiled. Then you have not given an id to any of the elements and try calling them. So here is the working example of how the code should be properly written for bug-free compilation.
Sometimes, it is because your function name override some other functions, especially the system defined ones. For example, I once made a function named as "translate." Later, it reports the exactly same error like yours. The solution is quite simple: just change the function name. For me, I make it "function tranlateIt()" and hence the problem is gone forever.
This is not the solution to your particular problem (the accepted answer answers it neatly), but the following might be the useful reference to the future readers (it happened very often to me).
The same error you provided happened to me, when I first declared a variable and then the function with the same name. For example:
var example = 5;
function example() {
console.log("The function just got executed!");
}
<button onclick="example()">Click me!</button>
You have not defined the id of paragraph for which you are changing the value. Just define the Id of paragraph as namecaller and it will work.
See the code below:
<div id="content">
<script>
function namecaller(){
var a = "scurvy";
var b = "dog";
document.getElementById("namecaller").innerHTML = "You are a " + a + " " + b;
}
</script>
<p id = "namecaller">Namecaller</p>
<button type="button" onclick="namecaller()">
You are a...</button
// Write this function code in inside <script> tag or in index.js file
function namecaller() {
var a = "scurvy";
var b = "dog";
document.getElementById("content").innerHTML = "You are a " + a + " " + b;
}
.content{
background-color: bisque;
}
.button{
color: white;
background-color: blue;
}
<!-- Write this code in inside the <body> tag in your index.html file -->
<!-- I added little CSS -->
<div class="content" id="content"></div>
<button class="button" type="button" onclick="namecaller()">You are a...</button>
Your div tag is not properly written. all tags need to open and close properly. You have to give the proper id to any HTML element and then call the function. Run the code snippet.
Good day!
I need a help on activating my javascript function via on-load on code behind.
Here is my code:
string script = #"var applyCss = function () {
var css = '#CalendarPanel1-month-day-20170607, #CalendarPanel1-month-day-20170614 {background-color: #D0D3D4;}';
Ext.net.ResourceMgr.registerCssClass('someCssClassId', css);
}; ";
ScriptManager.RegisterClientScriptBlock(this, typeof(Page), "css", script, true);
By the way, my code above works in front-end via button click.
But my desired result is, I want my javascript function to work on page load without needing to click the button. I put my javascript function in code-behind because I will put dynamic dates in the css variables. The code above still has static variables. (CalendarPanel1-month-day-20170607)
Will gladly appreaciate any response / solution. Big thanks!
You could use an immediately invoked function to do the trick. Basically you don't give a name to your javascript function and you invoke it right after it's defined.
For example:
var script = #"(function () {alert('Hello');})(); ";
ScriptManager.RegisterStartupScript(this, typeof(Page), "123", script, true);
You need to wrap the function with its body between parenthesis then another set of parenthesis to invoke the function.
You can also pass parameters to your function (which I'm assuming it's what you want to do):
var myAlertText = "Hello Hello";
var script = #"(function (myText) {alert(myText);})('" + myAlertText + "');" ;
If I were you though I would defined the function in client code and just invoke it from code behind with the right parameters.
An alternative and fancier way to call javascript code from code behind would be using X.Call(). Check out this example:
<%# Page Language="C#" %>
<!DOCTYPE html>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
string script = #"var myJSSideVar = 'my var value';
var applyCss = function (paramOne, paramTwo) {
var css = '#CalendarPanel1-month-day-20170607, #CalendarPanel1-month-day-20170614 {background-color: #D0D3D4;}';
Ext.net.ResourceMgr.registerCssClass('someCssClassId', css);
Ext.Msg.alert('applyCss called.', 'I\'ve been run with parameters: (' + paramOne + ', ' + paramTwo + ').');
};";
var hi = "hello";
X.AddScript(script);
X.Call("applyCss", new object[] { hi, new JRawValue("myJSSideVar") });
}
}
</script>
<html>
<head runat="server">
<title></title>
</head>
<body>
<form runat="server" id="form1">
<div>
<ext:ResourceManager runat="server" />
</div>
</form>
</body>
</html>
Notice the second parameter sent to the script call is sent "raw", i.e., it calls: applyCss("hello", myJSSideVar)
If you need to pass but one single parameter you don't need to pass an array, e.g. X.Call("applyCss", hi);
I have 2 HTML pages, send.html and receive.html
In each page I have a textield. The thing that I'm trying to do is whenever the "value" of the textfield in the send.html changes, automatically parse the data to the textfield value of the receive.html. When I say automatically I mean without the need of a button or reloading the pages.
To sum up.. I have this textfiled in the send.html
<input type="text" id="send" size="25" value="Val1">
And this text field in the receive.html
<input type="text" id="receive" size="25" value="Val2">
I want to "monitor" somehow the Val1, and if it changes I want Val2=Val1
For my purpose I cant use jquery.
Is that possible?
I think you are missing a big picture. Data sending and receiving needs some server side interaction like using PHP, ASP, JSP, Python etc., unless you are ok with cookies.
When you update a field in one age, that data needs to go the server somehow for another page to catch. Either way, the way you want it to go automatic is not possible right now. However, I will provide a solution of how you can do this using jQuery and PHP. But if you want?
Update
So, it seems cookies is the only option. Follow the following steps
Create a new file cookie.js and place the following code inside
function getCookie(c_name)
{
var i,x,y,ARRcookies=document.cookie.split(";");
for (i=0;i<ARRcookies.length;i++)
{
x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
x=x.replace(/^\s+|\s+$/g,"");
if (x==c_name)
{
return unescape(y);
}
}
}
function setCookie(c_name,value,exdays)
{
var exdate=new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
document.cookie=c_name + "=" + c_value;
}
Next, create two html file "test1.html" and "test2.html" with this markup
<html>
<head>
<script src="cookie.js"></script>
</head>
<body>
<input type="text" id="text1" name="text1" />
</body>
</html>
Now, on test1.html add the following script on the head
<script>
window.onload = function() {
document.getElementById("text1").onchange = function() {
// ^ use onkeyup if you want this to occur as you type
setCookie("shared", this.value, 1);
alert('oK, val changed so lets check it');
};
};
</script>
On Test2.html add the following Script on the head
<script>
var checkandupdate = function() {
var shared = getCookie("shared");
if(shared) {
document.getElementById("text1").value = shared;
}
};
window.onload = function() {
int = setInterval("checkandupdate()",1000);
};
</script>
Now
Open both pages
Go to test1.html and type something then press tab to get the alert message.
Open the test2.html, it should be update within 1 second
After the demo works, Update the field names as you need
Enjoy ;)
In your second HTML page , let's say we call it like page-2.html?send=xyz when the value is being changed , you add the following JS Code :
function getQueryString() {
var result = {}, queryString = location.search.substring(1),
re = /([^&=]+)=([^&]*)/g, m;
while (m = re.exec(queryString)) {
result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
return result;
}
var sendValue= getQueryString()["send"];
document.getElementById("receive").value=sendValue;
if you want to use without cookie for improving the performance.. you can use this library it uses window.name to carry the values.. however it will not work if the user opens in new tab.. still it is good.. only thing is you should handle new tab situation..
Hope this helps.. especially it will help if it is a html based front end..
This should be simple - don't get what I'm doing wrong! This is a very basic test (I'm new to PERL and Javascript) - this is the CGI file:
#! /usr/local/bin/perl
print "Content-type: text/html\n\n";
print "<html>\n" ;
print "<head>Hello\n";
print '<script type="text/javascript" language="javascript" src="wibble.js">\n';
print "</script>\n";
print "</head>\n";
print "<body>\n";
$fred = "Fred";
$numb = 7;
print <<TEST;
<p>Starting...</p>
<p><script type="text/javascript" language="javascript">
theText = "$fred";
theNum = "$numb";
document.writeln("Direct write...");
document.writeln("Number is: " + theNum);
document.writeln("Text is: " + theText);
testWrite(theNum, theText);
</script></p>
<p>...ending JS</p>
TEST
and in wibble.js:
function testWrite(num1, txt1)
{
document.writeln("In testWrite...");
document.writeln("Number is: " + num1);
document.writeln("Text is: " + txt1);
}
In my browser, I get the first set of writeln's but my function is never called. The error on the webpage says 'Object expected' at line 15 (the 'print <<TEST' line).
I mostly suspect I haven't got the right path in my src element but I've tried every combination I can think of ('.', './', full path etc) - nothing works. The js file is in the same dir as the CGI file.
(I actually originally had the function call with no parameters, hoping that theNum and theText are global and will still work (that was the original point of this test program)).
Please put me out of my misery...
As requested, here is source code from browser:
<html>
<head><script type="text/javascript" language="javascript" src="wibble.js"></script>
</head>
<body>
<p>Starting...</p>
<p><script type="text/javascript" language="javascript">
theText = "Fred";
theNum = "7";
document.writeln("Direct write...");
document.writeln("Number is: " + theNum);
document.writeln("Text is: " + theText);
testWrite(theNum, theText);
</script></p>
<p>...ending JS</p>
</body>
</html>
and this is the actual output on the web page:
Starting...
Direct write... Number is: 7 Text is: Fred
...ending JS
Did you check your server's log to see if wibble.js is ever requested? If it's not, then there's your problem. As well, while not really the problem, this line:
print "<head>Hello\n";
is generating bad html. You can't have "bare" text in the <head> block.
For global JS variables, you use the var keyword.
x = 7; // local
var y = 7; // global
The following loop works:
<html>
<body>
<script type="text/javascript">
var i=0;
for (i=0;i<=5;i++)
{
document.write("The number is " + i);
document.write("<br />");
}
</script>
</body>
</html>
But the following doesn't:
<html>
<body>
<script type="text/javascript">
var i=0;
var x="i=0;i<=5;i++"
for (x)
{
document.write("The number is " + i);
document.write("<br />");
}
</script>
</body>
</html>
I'd just like to create a simple variable.
Please bear with me as I'm a newbie in JavaScript and let me know what I'm missing.
Let me provide my sample Google gadget:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Sample Gadget" />
<UserPref name="order"
display_name="Results Order"
default_value="i = 0; i <= 5; i++" datatype="enum">
<EnumValue value="i = 0; i <= 5; i++" display_value="Ascending"/>
<EnumValue value="i = 5; i >= 0; i--" display_value="Descending"/>
</UserPref>
<Content type="html"><![CDATA[
<script type="text/javascript">
var i=0;
for (__UP_order__)
{
document.write("The number is " + i);
document.write("<br />");
}
</script>
]]></Content>
</Module>
It doesn't work because of the tags <> (they're not supported), and that's why I tried to define a variable for the EnumValue value.
When you say var x="i=0;i<=5;i++" you are creating a text string. This is not interpreted by JavaScript as you are expecting.
There is a definite difference between statements and text strings. Even though it looks to the eye like the same thing, it looks to the interpreter like a text string, like "hello" or "sdflkjsdflkjsdflj". JavaScript is not expecting a text string as loop parameters, it is expecting the three loop control parameters/statements. If you want to have a loop which starts and ends at different points, do something like this...
var i=0;
var start=0; //you can change the start position by changing this
var end=5; //and you can change the end also
for (i=start;i<=end;i++)
{
document.write("The number is " + i);
document.write("<br />");
}
In short: You're confusing code with data. "i=0;i<=5;i++" is data (a piece of text, a string). But when writing a for-loop you have to write initialization, condition and step as code - you cannot pass text that happens to look like the code you'd write there. (In fact, you don't want to - what should happen when the data isn't like valid code? Not to mention it's not needed - see El Ronnoco's)
Because x is a string and you cannot use for statement with a string inside.
If you need to change the upper bound of a for statement you can use a variable instead the fix number 5.