SetInterval in for Loop executing only last time - javascript

I have a little problem with SetInterval in javascript. I have a component which load content from url to div. The problem lies in the undefined number of these components.
Each have individual url and reload time.
and the PROBLEM is that my setinterval will execute only the last of components in the for loop.
I NEED to each component reloading on it self. :
component n1 = reload time 5s
component n2= reload time 60sec.
$(document).ready(function() {
var pocet = $('[id^=komponenta]').length;
var i;
for (i = 0, text = ""; i < pocet; i++) {
var nazev = 'komponenta' + i;
var cil = 'target' + i;
var adresa = document.getElementById(nazev).adresa.value;
var cas = document.getElementById(nazev).reload.value;
setInterval(function() {
$('#' + cil).load(adresa);
}, cas);
}
});
<div id="target0"></div>
<div id="target1"></div>
<div id="target2"></div>
<form class="pure-form pure-form-stacked" method="POST" id="komponenta0">
<fieldset>
<label for="email">Komponenta:</label>
<label for="remember" class="pure-checkbox">
</label>
<input type="hidden" name="adresa" id="adresa" type="text" placeholder="Vložte prosím URL" value="text.html">
<input type="hidden" name="reload" value="10000">
</fieldset>
</form>
<form class="pure-form pure-form-stacked" method="POST" id="komponenta1">
<fieldset>
<label for="email">Komponenta:</label>
<label for="remember" class="pure-checkbox">
</label>
<input type="hidden" name="adresa" id="adresa" type="text" placeholder="Vložte prosím URL" value="text2.html">
<input type="hidden" name="reload" value="2000">
</fieldset>
</form>

try this
(function(CIL, ADRESA, CAS) {
setInterval(function() {
$('#' + CIL).load(ADRESA);
}, CAS);
}(cil, adresa, cas));
i,e, wrap your setInterval as above
this is also valid, but may be a little less obvious
(function(cil, adresa, cas) {
setInterval(function() {
$('#' + cil).load(adresa);
}, cas);
}(cil, adresa, cas));
P.S. as #fuyushimoya stated - it's a scope issue

As others have mentioned, it's a scope issue - your setInterval-ed function is called not when the loop is iterating, but after it's through, and only the latest vars are available.
Try this jsFiddle - I replaced your 'load()' with a logging function.
$(document).ready(function () {
log('loaded');
var pocet = $('[id^=komponenta]').length;
var i;
for (i = 0, text = ""; i < pocet; i++) {
log(i);
(function (j) {
var nazev = 'komponenta' + j;
var cil = 'target' + j;
var adresa = document.getElementById(nazev).adresa.value;
var cas = document.getElementById(nazev).reload.value;
setInterval(function () {
log(nazev);
}, cas);
}(i));
}
});
function log(msg) {
$('.log').append(msg + '<br/>');
}

Related

How to pass form data to GAS

I am trying to pass data from a form into a Google Apps Script but when I press submit I am greeted by I blank screen.
Form:
<div id="nameDiv">
<form action="https://script.google.com/a/umbc.edu/macros/s/AKfycbztum1ImJZeXXYt0fFhwOAMUsB5zCsJQohrum4W7qiH/dev">
<label for="fname">First Name</label>
<input type="text" id="fname" name="firstname">
<label for="lname">Last Name</label>
<input type="text" id="lname" name="lastname" >
<input type="submit" value="Submit" onclick="google.script.run.nameSearch()">
</form>
</div>
Script:
function nameSearch(){
try {
var firstName = document.getElementById("fname").value
var lastName = document.getElementById("lname").value
var inputSheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1z3j7wxMLsXilyKDIH7XnE7VNQqF66fIH4B-mmuWwCJ8/edit#gid=1235654559");
var inputData = inputSheet.getDataRange().getValues();
for (var i = 1; i < inputData.length; i++) {
if (inputData[i][10] == firstName && inputData[i][11] == lastName) {
var result = inputData[i][14] + ": " + inputData[i][15]
}
}
document.getElementById('nameDiv').innerHTML =
"<center>Last Name:" + lastName + "</center>" +
"</br><center>First Name:" + firstName + "</center>"
} catch(e) {
alert(e)
}
}
I am trying to pass this data to the script so that it can use it to search a google sheet so I cannot just place the script in the html as a client side script. Any thought?
All the HTML-related methods (getElementById, innerHTML, etc.) should be in client-side script, and Apps Script methods should be in the server-side.
If I understand you correctly, you want to do the following:
When this form gets submitted, look for the row whose columns K and L match the inputted fields (indexes 10 and 11 from inputData array).
For this row, return data from columns O and P (indexes 14 and 15 from inputData array).
Write this returned data to the HTML.
If all this is correct, then you could do this:
Add an onclick event in the submit input that will fire a client-side function (a function that is declared inside the tags in the HTML). There is no need to use a for this. The HTML body could be something like this:
<div id="nameDiv">
<label for="fname">First Name</label>
<input type="text" id="fname" name="firstname">
<label for="lname">Last Name</label>
<input type="text" id="lname" name="lastname" >
<input type="submit" value="Submit" onclick="clientNameSearch()">
</div>
From this client-side function called clientNameSearch(), retrieve the values from fname and lname, and use these as parameters when you call a server-side function called nameSearch):
function clientNameSearch() {
var firstName = document.getElementById("fname").value;
var lastName = document.getElementById("lname").value;
google.script.run.withSuccessHandler(onSuccess).nameSearch(firstName, lastName);
}
This server-side function iterates through all rows with content in the spreadsheet, and returns the result for the first row whose columns K and L match the inputted data:
function nameSearch(firstName, lastName){
try {
var inputSheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1z3j7wxMLsXilyKDIH7XnE7VNQqF66fIH4B-mmuWwCJ8/edit#gid=1235654559");
var inputData = inputSheet.getDataRange().getValues();
for (var i = 1; i < inputData.length; i++) {
if (inputData[i][10] == firstName && inputData[i][11] == lastName) {
var result = inputData[i][14] + ": " + inputData[i][15];
return result;
}
}
} catch(e) {
alert(e)
}
}
This result is then passed as a parameter to a client-side function called onSuccess via a success handler. This is necessary since server-side functions called by google.script.run don't return anything directly, as specified here. Then onSuccess writes the result to the HTML:
function onSuccess(result) {
document.getElementById('nameDiv').innerHTML = "<div>" + result + "</div>";
}
Full code:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div id="nameDiv">
<label for="fname">First Name</label>
<input type="text" id="fname" name="firstname">
<label for="lname">Last Name</label>
<input type="text" id="lname" name="lastname" >
<input type="submit" value="Submit" onclick="clientNameSearch()">
</div>
</body>
<script>
function clientNameSearch() {
var firstName = document.getElementById("fname").value;
var lastName = document.getElementById("lname").value;
google.script.run.withSuccessHandler(onSuccess).nameSearch(firstName, lastName);
}
function onSuccess(result) {
document.getElementById('nameDiv').innerHTML = "<div>" + result + "</div>";
}
</script>
</html>
And the Code.gs would be like:
function nameSearch(firstName, lastName){
try {
var inputSheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1z3j7wxMLsXilyKDIH7XnE7VNQqF66fIH4B-mmuWwCJ8/edit#gid=1235654559");
var inputData = inputSheet.getDataRange().getValues();
for (var i = 1; i < inputData.length; i++) {
if (inputData[i][10] == firstName && inputData[i][11] == lastName) {
var result = inputData[i][14] + ": " + inputData[i][15];
return result;
}
}
} catch(e) {
alert(e)
}
}
function doGet(e) {
return HtmlService.createHtmlOutputFromFile("your-html-name");
}
I'm not sure you want to write the result to the HTML, but in any case, at this point it shouldn't be difficult to modify this so that it writes exactly what you want and where you want.
Reference:
google.script.run.myFunction(...) (any server-side function)
withSuccessHandler(function)
I hope this is of any help.
Try this:
Launch the dialog fill the text boxes and click submit. The view logs and see the next dialog.
function launchADialog() {
var html='<form><br /><input type="text" name="Name" /> Name: <br /><input type="text" name="Age" /> Age: <br />';
html+='<select name="Children" ><option value="0">None</option><option value="1">One</option><option value="2">Two</option></select> Children:<br />';
html+='<input type="button" value="Submit" onClick="google.script.run.processForm(this.parentNode);" /></form>';
var userInterface=HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModelessDialog(userInterface, "The Form");
}
function processForm(form) {
Logger.log(JSON.stringify(form));
var s=Utilities.formatString('<br />Name: %s <br />Age:%s <br />Number Of Children: %s', form.Name, form.Age, form.Children);
s+='<br /><input type="button" value="Close" onClick="google.script.host.close();" />';
var userInterface=HtmlService.createHtmlOutput(s);
SpreadsheetApp.getUi().showModelessDialog(userInterface, "Form Data")
}

How to get the selected radio buttons value?

i am trying to get the value of selected radio buttons so i can submit my form using Ajax i searched here for some help but i couldn't find any useful solution
<input type="radio" id="answer" name="answer<?php echo $function::escape_string($question_row->question_id); ?>"
value="<?php echo $function::escape_string($answer_row>answer_id); ?>"/>
-HTML Output
<input type="radio" id="answer" name="answer16" value="107"/>
<input type="radio" id="answer" name="answer17" value="109"/>
<input type="radio" id="answer" name="answer15" value="104"/>
i found this function here
function findSelection(field) {
var test = document.getElementsByName(field);
var sizes = test.length;
alert("Size is " + sizes);
for (i=0; i < sizes; i++) {
if (test[i].checked==true) {
alert(test[i].value + ' you got a value');
return test[i].value;
}
}
}
var radioinputs = findSelection("answer");
But I do not know what to change so I can make it work with me properly
You can structure like this:
function findSelection(field) {
var test = document.getElementsByClassName(field);
var sizes = test.length;
//alert("Size is " + sizes);
result = [];
// result[16]=107;
// result[17]=109;
// result[15]=104;
for (i=0; i < sizes; i++) {
var index = test[i].dataset.index;
if(test[i].checked == true){
result[index] = test[i].value;
}else{
result[index] = undefined; // for a answer doesn't have a value
}
}
return result;
}
function checkfunction(){
var radioinputs = findSelection("radioanswer");
console.log(radioinputs);
console.log(radioinputs[15]);
};
<form id="form1">
<input type="radio" class="radioanswer" name="answer16" data-index="16" value="107"/>
<input type="radio" class="radioanswer" name="answer17" data-index="17" value="109"/>
<input type="radio" class="radioanswer" name="answer15" data-index="15" value="104"/>
<button type="button" onclick="checkfunction();"> Check </button>
</form>
A class can has multiple instances, but id has only one! And you can see document about data attributes here: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
From the looks of it you have a dynamic name field, i.e. name="answer2", name="answer3", etc. Because of that your query document.getElementByName(field) will not find a field matching "answer".
To remedy this either get rid of the dynamic name or if you really need it then I would say add a class to all those radio buttons and use document.getElemenetsByClassName.

Dynamic assigning of event listener for multiple classes is not working

Im struggling to find problem.
Idea behind code:
dynamically assign event listener "oninput" to specific inputs on page determined by classes stored in "classes" array.
Problem:
function PassValue does not handle any element event where class is different from the last index in "classes" array(only the last class in array is handled).
When I change order of "class" array elements it results in different class being handled - again class on last index in array.
Image of how it works (or check Snippet)
When I hover over console element in first part "Datum" should be highlighed just as "Blast KD" is on second part. Its simplified representation of when I Type something in them, same text should appear in input under them, but that works only for one of them.
Question:
Does anyone know why is it happening and how to fix it(so all inputs are handled)?
$(function() {
$('.constant-select-form-numeric').attr('list', 'consoptions-numeric');
$('.constant-select-form-numeric-NT').attr('list', 'consoptions-numeric-NT');
$('.constant-select-form-date').attr('list', 'consoptions-date');
});
$(document).ready(function() {
var classes = ['.constant-select-form-date', '.constant-select-form-numeric', '.constant-select-form-numeric-NT'];
var form = $(document).find('form');
for (var j = 0; j < classes.length; j++) {
var c = classes[j];
//console.log(c);
var e = $(document).find(c);
if (e.length > 0) {
// ... switch(c) differentiating classes from each other(assingning atributes)
switch (c) {
case '.constant-select-form-date':
form[0].innerHTML += "<datalist id='consoptions-date'>\n\
<option data-value='-1'>Unknown</option>\n\
</datalist>";
break;
case '.constant-select-form-numeric-NT':
form[0].innerHTML += "<datalist id='consoptions-numeric-NT'>\n\
<option data-value='-2'>NT</option>\n\
</datalist>";
break;
default:
form[0].innerHTML += "<datalist id='consoptions-numeric'>\n\
<option data-value='-3'>NA</option>\n\
</datalist>";
break;
}
// assign EventListener to each element of c
for (var i = 0; i < e.length; i++) {
var element = $("input[for=" + e[i].attributes.for.value + "]")[0];
var hidden = $("input[name=" + e[i].attributes.for.value + "]")[0];
element.value = hidden.value;
element.addEventListener("input", function(elem) {
PassValue(elem.target);
});
PassValue(element);
//print element DOM
console.log(element);
}
}
}
});
function PassValue(element) {
console.log(element);
var x = element.value;
console.log(x);
// rest of function...
var hiddenInput = $(document).find("input[name=" + element.attributes.for.value + "]")[0];
hiddenInput.value = x;
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html>
<body>
<form>
<fieldset class="form-group">
<label for="datum">Datum: </label>
<input for=datum class="form-control constant-select-form-date">
<input type="text" name="datum" id="frm-newMessageForm-datum">
</fieldset>
<fieldset class="form-group">
<label for="datum1">Datum1: </label>
<input for=datum1 class="form-control constant-select-form-date">
<input type="text" name="datum1" id="frm-newMessageForm-datum1">
</fieldset>
<fieldset class="form-group">
<label for="blast_kd">Text: </label>
<input for=blast_kd class="form-control constant-select-form-numeric">
<input type="text" name="blast_kd" id="frm-newMessageForm-blast_kd">
</fieldset>
<fieldset class="form-group">
<label for="blast_kd1">Text1: </label>
<input for=blast_kd1 class="form-control constant-select-form-numeric">
<input type="text" name="blast_kd1" id="frm-newMessageForm-blast_kd1">
</fieldset>
</form>
</body>
</html>
Nevermind, I solved it with completely different approach on different layer.(adding db constant fields is supposed to be in different layer, not in js)

implementing insertbefore() in loop

I am trying to show error messages below an array of textboxes that I have selected using Javascript. The error messages are being put by creating a new span element and using the insertBefore() method. The span element is created in the function since I don't want to hard code it into the DOM. The span messages do show but each time I submit the form, they are appended over and over again. I'd like to show the span messages only once and each time the form is submitted, they are shown once only. Below is my code.
HTML
<div class="slideshow">
<form id="form">
<input type="text" name="1" class="textbox" />
<input type="text" name="2" class="textbox" />
<input type="text" name="3" class="textbox" />
<input type="submit" name="submit" value="submit" id="submit" />
</form>
</div>
JAVASCRIPT
<script>
var slideshow = document.querySelector('.slideshow');
// var span = document.createElement('span');
var form = document.querySelector('#form');
var inputs = form.querySelectorAll('.textbox');
form.addEventListener('submit', function(e)
{
e.preventDefault();
for( var i=0; i<inputs.length; i++ )
{
var span = document.createElement('span');
(function(index)
{
span.innerHTML = 'error ' + index;
inputs[index].parentNode.insertBefore(span, inputs[index].nextElementSibling);
})(i);
}
}, false);
</script>
Each time I submit, I'd like the error messages to be shown below the textbox and not appended over and over again. They should be shown just once and I'd like to do this without using jQuery or any sort of library.
I rewerite your example to create available 3 span tags instead of crate them in code. If there are some errors, populate them to span rather than creating/deleting the spans in code.
var slideshow = document.querySelector('.slideshow');
var form = document.querySelector('#form');
var inputs = form.querySelectorAll('.textbox');
form.addEventListener('submit', function (e) {
e.preventDefault();
for (var i = 0; i < inputs.length; i++) {
(function (index) {
document.getElementsByTagName('span')[index]
.innerHTML = 'error ' + index;
})(i);
}
}, false);
<div class="slideshow">
<form id="form">
<input type="text" name="1" class="textbox" /><span></span>
<input type="text" name="2" class="textbox" /><span></span>
<input type="text" name="3" class="textbox" /><span></span>
<input type="submit" name="submit" value="submit" id="submit" />
</form>
</div>
Hope this help.
Just do a check before you insert. Here is one way to do it.
form.addEventListener('submit', function (e) {
e.preventDefault();
for (var i = 0; i < inputs.length; i++) {
var span = document.createElement('span');
(function (index) {
span.innerHTML = 'error ' + index;
if (inputs[index].nextElementSibling.tagName !== 'SPAN')
inputs[index].parentNode.insertBefore(span, inputs[index].nextElementSibling);
})(i);
}
}, false);
You have to wait for page to be load, the you should run JavaScript.
PageLoad Event : window.onload=function(){}
Code :
<script type="text/javascript">
window.onload = function () {
var slideshow = document.querySelector('.slideshow');
var form = document.getElementById('form');
var inputs = document.querySelectorAll('.textbox');
form.addEventListener('submit', function (e) {
e.preventDefault();
for (var i = 0; i < inputs.length; i++) {
var span = document.createElement('span');
(function (index) {
span.innerHTML = 'error ' + index;
inputs[index].parentNode.insertBefore(span, inputs[index].nextElementSibling);
})(i);
}
}, false);
}
</script>
Put your code in window.onload event.

What's the best way to update the input names when dynamically adding them to a form?

I'm trynig to come up with a clean and efficient way of handling form input names when dynamically adding more to the POST array.
For example, if I have the following form:
<fieldset>
<input type="text" name="users-0.firstname" />
<input type="text" name="users-0.lastname" />
</fieldset>
I then click an 'addmore' button which duplicates that HTML and adds it back into the document. Resulting in:
<fieldset>
<input type="text" name="users-0.firstname" />
<input type="text" name="users-0.lastname" />
</fieldset>
I'm trying to find the best way to increment that name index so I can use the data on the server. So far, I've been using the following code:
$('.addmore').click(function()
{
var $button = $(this);
var $fieldset = $button.prev('fieldset');
var $newset = $('<div class="new">' + $fieldset[0].innerHTML + '</div>');
$newset.insertBefore($button);
updatenames($newset, $('fieldset').length + 1);
});
function updatenames($set, newIndex)
{
/*
updates input names in the form of
set-index.name
set-index
*/
var findnametype = function(inputname)
{
if (inputname.indexOf('-') != -1 && inputname.indexOf('.') != -1)
{
var data1 = inputname.split('-');
var data2 = data1[1].split('.');
// [type, set, index]
return [1, data1[0], parseInt(data2[0])]
}
if (inputname.indexOf('-') != -1 && inputname.indexOf('.') == -1)
{
var data = inputname.split('-');
return [2, data[0], data[1]];
}
return false;
};
var type = findnametype($set.find('input:eq(0)')[0].name);
$set.find('input, select').each(function()
{
var $input = $(this);
var oldname = $input[0].name;
var newname = false;
switch (type[0])
{
case 1: newname = oldname.replace('-' + type[2], '-' + newIndex);
break;
case 2: newname = oldname.replace('-' + type[2], '-' + newIndex);
break;
}
$input[0].name = newname;
});
return type;
}
That updatenames function is a variation of what I've been using lately. In this case, I check to find the format of the input name. I then increment the index.
The incrementing, as you've probably noticed, happens in the DOM. As a 'part 2' to my question, I'd like to learn how to have that object returned for me to then insert into the DOM.
Something like:
$newset = updatenames($newset, $('fieldset').length +1);
$newset.insertBefore($button);
Your help is appreciated. Cheers.
Have you considered using array-based field names? You wouldn't have to alter those at all:
<input type="text" name="users.firstname[]" />
<input type="text" name="users.lastname[]" />
whether this works for you will of course depend on what you're going to do with the fields.
<script type="text/javascript">
$(document).ready(function () {
$('.addmore').click(function () {
var fieldset = $(this).prev('fieldset');
var newFieldset = fieldset.clone();
incrementFieldset(newFieldset);
newFieldset.insertBefore($(this));
});
});
function incrementFieldset(set) {
$(set).find('input').each(function () {
var oldName = $(this).attr('name');
var regex = /^(.*)-([0-9]+)\.(.*)$/;
var match = regex.exec(oldName);
var newName = match[1] + '-' + (parseInt(match[2]) + 1) + '.' + match[3];
$(this).attr('name', newName);
});
}
</script>
<fieldset>
<input type="text" name="users-0.firstname" />
<input type="text" name="users-0.lastname" />
</fieldset>
<input type="button" class="addmore" value="Add" />
<fieldset>
<input index=1 var=user prop=firstname />
<input index=1 var=user prop=lastname />
</fieldset>
<fieldset>
<input index=2 var=user prop=firstname />
<input index=2 var=user prop=lastname />
</fieldset>
before you submit your form
get the custom attributes and construct your 'name' attribute
[update]
its jsp but shouldn't be hard for u to convert to php
<%
for (int i = 0; i < 1000; i++) {
%>
<fieldset>
<input index=<%=i%> var=user prop=firstname />
<input index=<%=i%> var=user prop=lastname />
</fieldset>
<%
}
%>
for the js code
$('button').click(function(){
$('input').each(function(i, node){
var $node = $(node);
$node.attr('name', $node.attr('var') + $node.attr('index') + "."+ $node.attr('prop'))
});
});

Categories

Resources