cannot run JavaScript function from XSL - javascript

I have a form element in an XSL file. I want to have a JavaScript function in the same XSL file to enable the Submit button on checking a check box.
Here is the form -
<form action="NewUserNavigation" method="post" name="NewUserNavigationForm">
<input name="eventName" type="hidden" value="NewUserNavigationEvent"/>
<div class="sansIcon">
<input type="checkbox" name="chk" onClick="EnableSubmit()"><xsl:apply-templates select="content[#name='chkbox']" mode="impl_expandContent"/></input>
</div>
<div class="buttonBarPage">
<input name="Submit" class="primary" type="submit" value="Continue" disabled="true"/>
</div>
</form>
Here is the XML conetent that it is reading -
<content name = "chkbox">
Yes, I understand and agree to the T&C.
</content>
I am facing problem with the javascript, it gives error. I have put an alert to check if the function is being called on click of the checkbox.
here is the code I am using -
<script type="text/javascript">
function EnableSubmit()
{
alert("test");
if(document.NewUserNavigationForm.chk.checked==true)
{
document.NewUserNavigationForm.Submit.disabled=false;
}
if(document.NewUserNavigationForm.chk.checked==false)
{
document.NewUserNavigationForm.Submit.enabled=false;
}
}
</script>
I get this error....
org.xml.sax.SAXParseException: illegal top-level element

The end tag should be </script> rather than <script>.
By the way, did you know that with Saxon-CE you can do this without any Javascript? You can then write template rules in the stylesheet that respond to user input (such as button clicks) and modify the HTML DOM in arbitrary ways, without having to use the Javascript DOM API.

The javascript function needs to wrapped in a CDATA tag, as it is not valid XML. Anything that you wrap in CDATA will be output exactly as is to the file you are writing (ie, the html). So:
<script type="text/javascript"><![CDATA[
function EnableSubmit()
{
alert("test");
if(document.NewUserNavigationForm.chk.checked==true)
{
document.NewUserNavigationForm.Submit.disabled=false;
}
if(document.NewUserNavigationForm.chk.checked==false)
{
document.NewUserNavigationForm.Submit.enabled=false;
}
}
]]><script>

Related

How to count button clicks for a form in Google Apps Script with JavaScript?

Simplified the code as much as possible. How are the button clicks counted?
html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Example File 3</h1>
<form action="<?= url ?>" method="GET">
<input type="text" name="update" />
<input type="submit" name="Submit" /><br> <!-- count clicks -->
<span><?= update ?></span>
<span><?= count ?></span>
</form>
</body>
</html>
The Code.js file:
var clicks = 0;
function doGet(e) {
Logger.log(JSON.stringify(e));
var htmlOutput = HtmlService.createTemplateFromFile('ExampleFile3');
if (!e.parameter['update']) {
htmlOutput.update = '';
}
else {
htmlOutput.update = 'updated value is: ' + e.parameter['update'];
htmlOutput.count = 'count is: ' + clicks;
clicks++
}
htmlOutput.clicks = clicks;
htmlOutput.count = clicks;
htmlOutput.url = getUrl();
return htmlOutput.evaluate();
}
function getUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
the increment isn't increasing, that I see, and the output is squished together. Looking to count the number of form submissions.
Here is a sample code for creating an oversimplified web app. It shows one way to count button clicks using JavaScript.
The client-side code is added to the HtmlOutput object by using the HtmlService.HtmlOutput.append method.
The global variable is set in the client-side instead of the server-side. Please bear in mind that reloading the web app will reset the global variable.
In <form> uses the attribute onsubmit instead of the attributes action and method. This attribute calls a client-side JavaScript function that updates the client-side global variable and display it in <div>.
Please note the use of event.preventDefault(). This is required when submitting html forms in Google Apps Script web apps because the form is hosted in a special Google service that cannot be modified by the Google Apps Script web app developers.
function doGet(e) {
return HtmlService.createHtmlOutput()
.append(`
<form onsubmit="handleFormSubmit()">
<input type="text" name="something"><br>
<button type="submit">Submit</button>
</form>
<div>0</div>
<script>
var clicks = 0;
function handleFormSubmit(){
event.preventDefault();
document.querySelector('div').innerHTML = ++clicks;
}
</script>
`);
}
Notes:
The web browser console will show several warnings. You can ignore them
The web browser console will show the following error:
Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.
at gas-hub.js:25:10
For the purpose of this oversimplified example, you can ignore it. To avoid this error, the HtmlOutput object should include a "full" HTML5 structure:
function doGet(e) {
return HtmlService.createHtmlOutput()
.append(`
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form onsubmit="handleFormSubmit()">
<input type="text" name="something"><br>
<button type="submit">Submit</button>
</form>
<div>0</div>
<script>
var clicks = 0;
function handleFormSubmit(){
event.preventDefault();
document.querySelector('div').innerHTML = ++clicks;
}
</script>
</body>
</html>
`)
.setTitle('Demo')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
To send <form> values to the server side, as well for other type of values, without reloading the web app, use google.script.run to call a server side function as is explained in https://developers.google.com/apps-script/guides/html/communication.
You also can use google.script.run to call server side functions on client-side event like clicking button. A very simple way is by using a button (<button> or <input type="button"> with an onclick attribute).
<button onclick="google.script.run.myFunction();">Run</button>
Also it's possible to use it with <form>'s onsubmit attribute and buttons of type submit but you have to include event.preventDefault() to avoid the page redirection cause the form submit action.
Please bear in mind that the use of event attributes is discouraged. Instead set the function to be called on the event by using HtmlElement.addEventListener whenever be possible.
To store a value persistently, do not use server-side global variables, instead consider to use the Properties Service among other options (see the related questions).
Here is another example, now using the "full" HTML5 structure, the Properties Service to persistently keep the number of button clicks. Instead of using the attribute onsubmit it uses the <form>attributes action and method but also use <base> to set the elements target to `"_top". This is required to properly reload the web app when the form is submitted.
A hidden <input> is used to pass a value to control when the click counter should be increased, this way we prevent that following the link (without the clicked=yes url parameter) increase the counter. Please note that no JavaScript is included on the client-side (HtmlOutput).
function doGet(e) {
const props = PropertiesService.getScriptProperties();
const name = "clicks";
let clicks = Number(props.getProperty(name));
if (e && e.parameter && e.parameter.clicked === 'yes') {
props.setProperty(name, ++clicks);
}
return HtmlService.createHtmlOutput()
.append(`
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form action="${ScriptApp.getService().getUrl()}" method="GET">
<input type="hidden" name="clicked" value="yes">
<input type="text" name="something" value="default value"><br>
<button type="submit">Submit</button>
</form>
<div>${clicks}</div>
</body>
</html>
`)
.setTitle('Demo')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
If you are on your way to create a production class web application, please be aware that the client-side code is "satinized" and there are some limitations about what can done compared to other platforms. Please study the references to learn the basics about this.
Related
How to define global variable in Google Apps Script
How do I know which button was clicked in the Google Apps script?
References
https://developers.google.com/apps-script/guides/web
https://developers.google.com/apps-script/guides/html

capture submit event with dynamically added content with JavaScript

I am building a sort of page builder where the user can add blocks to the page and then save the layout. I have encountered a problem that I can't seem to figure out. I have a form that is dynamically added to the page with JavaScript containing a file input as so:
<form class="upload " action="" method="post">
<input id="" type="file" class="fill" name="upload">
<img src="/admin/img/default.png" alt="">
</form>
After adding the content I call the following function to add event listeners. $el corresponds to the file input.
function changeListen($el){
$el.addEventListener('change', function(){
$el.parentElement.submit();
});
$el.parentElement.addEventListener('submit', function(e){
e.preventDefault;
// call Ajax request...
});
}
I want to be able to update the database with an Ajax request when an image is selected, therefore I submit the form within the change event, so far so good, but for some reason the submit event is not taken into account and the page reloads. Any solutions or workaround appreciated, preferably not jQuery.
By using onsubmit event in HTML, you can call javascript function this way and do ajax calls.
Javascript sample
<script>
function doSomething() {
alert('Hello, World');
return false;
}
</script>
HTML Sample
<form onsubmit="return doSomething();">
<input type="submit" value="Submit" />
</form>
EDIT: return false in javascript so ? does not appear in URI after clicked

Can external JavaScript access DOM elements from a different file?

Just started working in Dreamweaver recently. I was wondering if when you are working with external javascript files, do you have to pass in html elements or can the js file see their id? For example;
<body>
<script src="client.js"></script>
<input type="submit" name="submit" id="submit" onclick="getValue()" value="Submit"></td>
And then in the client.js file
function getValue() {
"use strict";
document.getElementById(submit).value = document.getElementById(otherelement).value;
}
This isn't working in the first place and I understand that there are other errors, but mainly - can the client.js file see and use getElementById(submit) and getElementById(otherelement)?
I would suggest shying away from using inline JavaScript elements, and doing things differently. I'd suggest using addEventListener() to bind events from JavaScript.
So, remove the onclick attribute, and just do:
<input type="submit" name="submit" id="submit" value="Submit">
We will be adding the event in JavaScript. For this to work, the script needs to be ran after the page (DOM) is loaded. You can use window.onload = function(){} to do this or you can load the script at the end of the page (before </body>).
Anyway, in your JavaScript, you want to use:
document.getElementById("submit").addEventListener('click', function(event){
// NOTE: You are clicking a submit button. After this function runs,
// then the form will be submitted. If you want to *stop* that, you can
// use the following:
// event.preventDefault();
// In here `this` will be the element that was clicked, the submit button
this.value = document.getElementById('otherelement').value;
});
document.getElementById( id ) takes id param as string
Use
document.getElementById("otherelement");
document.getElementById("submit");
also remove the </td> as there is no <tr> in your code
If you don't use quotes to wrap your strings, javascript will try to find variables named submit or otherelement. Try adding quotes like that :
function getValue() {
"use strict";
document.getElementById("submit").value = document.getElementById("otherelement").value;
}
If you have an HTML element with an id attribute, The JS engine automatically converts it to a variable..
e.g.
<input type="submit" name="submit" id="submit" onclick="getValue()" value="Submit"></td>
equals to the var submit in your JS code (considering you load your JS file when the DOM is fully rendered).
In every HTML page an element id is unique and that's why it is converted to a variable and wll not be overwritten until you decide so.
I was wondering if when you are working with external javascript
files, do you have to pass in html elements or can the js file see
their id
Yes you can see the ID:
function whoAmI(e) {
document.getElementById('output').textContent = e.target.id;
}
<button id='Hiii' onclick='whoAmI(event)'>Check ID</button>
<p id='output'></p>

Why is a value not getting copied to the clipboard in javascript?

I'm using Google App Engine Go SDK and I want to put some basic javascript code into my HTML templates that will use parameters passed from the application. The template looks like this:
<script type="text/javascript">
function CopyToClipboard()
{
CopiedTxt = document.selection.createRange();
CopiedTxt.execCommand("Copy");
}
</script>
[...]
<form name="Form1">
<input type="hidden" name="link" value="{{.Link}}">
<input type="button" onClick="CopyToClipboard()" value="Copy to clipboard" />
</form>
What the code is supposed to do is copy the {{.Link}} value into the clipboard. But instead of getting things like http://example.com in the clipboard, I get {{.Link}}, even though the page source of the executed template clearly reads
<input type="hidden" name="link" value="http://example.com">
How can I make the javascript work properly with the GAE Golang template?
This has nothing to do with app engine, templates, or go. The problem is that .execCommand() will not generally work. Clipboard access is not something that can be done successfully through javascript. You must use a flash plugin.

Automatically making a div appear based on status of radio button with JavaScript

I have a form which posts data to the same page. Based on the user's radio button selection I am inserting checked="checked" into the radio button form element to redisplay the correct selection. This works fine, however when the form is redisplayed (in case of bad input etc), I need a div to be revealed (containing the relevant fields from the form).
I have an onclick event that reveals the div in the first place (before the user has posted the form), and this works fine, but when I redisplay the form I don't want the user to have to manually reveal the form again by clicking.
Therefore I've been trying something along the following lines (heavily cut down for the purposes of this post)...
<link href="styles/style1.css" rel="stylesheet" type="text/css" />
<script language="JavaScript">
if (document.getElementById('complete_yes').checked) {
document.getElementById('repair_complete').style.display = 'block';
} else {
document.getElementById('repair_complete').style.display = 'none';
}
</script>
<form action="javascript_test.php" method="POST">
<input id="complete_yes" type="radio" name="complete" checked="checked" value="true"/>Yes
<input id="complete_no" type="radio" name="complete" value="false"/>No
<input type="submit" value="Save">
<div id="repair_complete">
I'm a div!
</div>
... but it returns an Object Required javascript error (as it does in the 'real' page):
Message: Object required
Line: 3
Char: 1
Code: 0
URI: http://localhost/repair_system/javascript_test.php
Why is this? Am I not correctly referencing the form element? Apologies if I'm being a "div" (deliberate bad pun intended!), I'm yet to learn about the fun and games of javascript!
Because your javascript is not wrapped inside a function, the browser is executing it as soon as it "gets to it". In this case, the JS is being executed before the browser has reached the html declaring your form.
The simplest fix therefore is to move the Javascript to after your form. A more robust solution would be to wrap you code in a function, and have that triggered somehow - from what you appear to be trying to do, in this case it'll be the onLoad event of the body tag:
<head>
<script language="JavaScript">
function showHelpDiv() {
if (document.getElementById('complete_yes').checked) {
document.getElementById('repair_complete').style.display = 'block';
} else {
document.getElementById('repair_complete').style.display = 'none';
}
}
</script>
</head>
<body onload="showHelpDiv()">
<form action="javascript_test.php" method="POST">
<input id="complete_yes" type="radio" name="complete" checked="checked" value="true"/>Yes
<input id="complete_no" type="radio" name="complete" value="false"/>No
<input type="submit" value="Save">
<div id="repair_complete">
I'm a div!
</div>
Your code is being executed as the document is being loaded, and the DOM tree isn't ready yet. So it is trying to access an element that doesn't exist yet.
You probably want to instead write an event handler that toggles the div whenever the checkbox is checked.
I prefer jQuery, which abstracts away things like cross-browser event handling, provides lots of nice helpers and generally makes code look cleaner (when written properly). Something like this should work:
$(document).ready(function() {
$('#repair_complete').toggle($('#complete_yes').is(':checked'));
}
The above can be roughly translated as:
When the document loads, perform the following:
Add an event handler for the 'change' event to any elements of type 'input' with a name of 'complete'
When the event handler fires, toggle the visibility of the element with ID 'repair_complete' where it should be visible if the element with ID 'complete_yes' is checked
Update: The JS above now actually does what you want, originally I had it written as an onclick
This is because Javascript is executed just before rest of the objects are created.
Place your javascript code into the function body, and add this function into onclick event for whatever you need.
<link href="styles/style1.css" rel="stylesheet" type="text/css" />
<script language="JavaScript">
function test() {
if (document.getElementById('complete_yes').checked) {
document.getElementById('repair_complete').style.display = 'block';
} else {
document.getElementById('repair_complete').style.display = 'none';
}
}
</script>
<form action="javascript_test.php" method="POST">
<input id="complete_yes" type="radio" name="complete" checked="checked" value="true" onClick="javascript: test();"/>Yes
<input id="complete_no" type="radio" name="complete" value="false" onClick="javascript: test();"/>No
<input type="submit" value="Save">
<div id="repair_complete">
I'm a div!
</div>
</form>
It looks to me as though your script is firing before the form is drawn, you may want to move your script block to after the form element. Basically I think that the document.getElementById('complete_yes').checked is looking at null.checked, which would trigger the object required error.
You should make the action of the radio button be to change the visibility of the div (that is, "push" the status to it), rather than to "pull" the div status via the radio button status at render time (which as Andrejs said, will be unset).
Sounds like the problem is in your initialization code. The javascript is being called before the page is finished rendering. It's one annoying aspect of the "onload" event that in my opinion simply doesn't work as it should in every browser.
There's a cross-browser technique to call initialization code once and only once after the DOM is fully loaded.
Try this code in the HEAD of your HTML:
function showHelpDiv() {
if (document.getElementById('complete_yes').checked) {
document.getElementById('repair_complete').style.display = 'block';
} else {
document.getElementById('repair_complete').style.display = 'none';
}
}
function InitOnce()
{
if (arguments.callee.done) return;
arguments.callee.done = true;
showHelpDiv();
}
/* for Mozilla */
if (document.addEventListener)
{
document.addEventListener("DOMContentLoaded", InitOnce, null);
}
/* for Internet Explorer */
/*#cc_on #*/
/*#if (#_win32)
document.write("<script defer src=ie_onload.js><"+"/script>");
/*#end #*/
/* for other browsers */
window.onload = InitOnce;
And then you need to create an ie_onload.js file that contains this line for IE compatibility:
InitOnce();
I've tried other techniques but none work as perfectly as this. I believe I originally found this solution here:
http://dean.edwards.name/weblog/2005/09/busted/
I use it in an online application that receives 500 unique visits a day or so and this has been reliable for us.

Categories

Resources