I am working on a project using Google Apps Script coupled with HTML and JS. I am fairly new to programming, so bear with me if this is a simple question.
Basically, in my JS file I have a function that calls a function contained in the Google Apps Script (from now on, GAS) file using this method; the GAS function populates an array with values retrieved from a Google Sheets and returns the array. This array is then used by the JS file to populate a drop down list in the HTML file.
The issue is that the dropdown list is not populated at all; if I reload the page with the Google Chrome console on, I see that the array is empty; however, if I click on the empty array, the values are shown, as if it is not populated on page load. See the picture below to have a better understanding of what I mean:
Google Chrome Console screenshot
Below you'll find the relevant snippets of code that handle the differente functions:
JS:
$(function() {
var cities = [];
function onSuccess(elem, array) {
var i = 0;
for (item in elem) {
array.push(elem[i])
i++;
};
return array
};
google.script.run.withSuccessHandler(onSuccess).withUserObject(cities).populate();
//Create the dropdown menu for the cities
for (city in cities) {
var element = $("#city1").append("<option value=" + cities[city].toLowerCase() + ">" + cities[city] + "</option>");
console.log(city);
};
[...]
});
HTML:
<select id="city1" name="city" placeholder="City"><option id="citydummy">City</option></select>
Google Apps Script:
function populate() {
var db = SpreadsheetApp.openById('SHEETID');
var check = true;
var array = [];
for (var i = 2; i < db.getLastRow(); i++) {
db.getActiveSheet().getRange(i, "1").getValue()
array.push(db.getActiveSheet().getRange(i, "1").getValue())
}
return array;
}
Many thanks in advance for anyone who will contribute!
How about the following modification for JS? HTML and GAS are not modified. Data obtained at populate() is directly sent to onSuccess(), and imported the data to the list.
JS :
$(function() {
google.script.run.withSuccessHandler(onSuccess).populate();
});
function onSuccess(cities) {
for (city in cities) {
var element = $("#city1").append("<option value=" + cities[city].toLowerCase() + ">" + cities[city] + "</option>");
console.log(city);
};
};
If I misunderstand your situation, I'm sorry.
Related
I have an Asp.Net Core MVC application that searches youtube videos and returns a list that is displayed on screen. Each video is placed in a custom component that has a checkbox. Every time a checkbox is selected I access a script that searches all the video components that are on the screen and I store the video id's in a list in my .cshtml page.
At some point I need to get this list of video id's to do a processing. For that I created a javascript method in the same .cshtml page to return this list of ids.
I've already done a research on JSRuntime on Blazor (.razor) pages but that wouldn't be my case.
The fact is that with the click of a button I need to call a controller method, and this method calls my javascript method which returns my list of ids.
How best to do this?
This my javascript code.
#section scripts
{
<script>
var listaDeIds = [];
function Mostrar() {
//document.getElementById("btnplaylist").style.display = 'block';
var videos = document.querySelectorAll('#video');
var count = 0;
var lista = [];
for (var i = 0; i < videos.length; i++) {
//console.log("1 - " + videos.item(i).getAttribute("name"));
var videoID = videos.item(i).getAttribute("name");
//console.log("2 - " + videos.item(i).getAttribute("id"));
const shadow = videos.item(i).shadowRoot;
const childNodes = Array.from(shadow.childNodes);
//console.log("3 - " + childNodes.length);
childNodes.forEach(childNode => {
if (childNode.nodeName === "DIV") {
//console.log("4 - " + childNode.nodeName);
const shadowChilds = Array.from(childNode.childNodes);
//console.log("5 - " + shadowChilds.length);
shadowChilds.forEach(shadowShild => {
if (shadowShild.nodeName === "DIV") {
//console.log("6 - " + shadowShild.nodeName);
const shadowChildsInternas = Array.from(shadowShild.childNodes);
//console.log("7 - " + shadowChildsInternas.length);
shadowChildsInternas.forEach(interna => {
if (interna.nodeName === "INPUT") {
//console.log("8 - Name " + interna.nodeName);
if (interna.checked === true) {
//console.log("9 - Checked: " + interna.checked);
lista[count] = videoID;
count = count + 1;
}
}
});
}
});
}
});
}
if (lista.length > 0) {
document.getElementById("btnplaylist").style.display = 'block';
} else {
document.getElementById("btnplaylist").style.display = 'none';
}
listaDeIds = lista;
}
function RetornaListaDeIds() {
return listaDeIds;
}
</script>
This is my html component code
<custom-iframe id="video" name="#item.Id.VideoId" urlvideo='#Url.Content(item.Url)' onclick="Mostrar()"></custom-iframe>
This is the button that calls my controller.
<div id="btnplaylist" class="right_side hidden">
<button value="Playlist" asp-controller="VideoSearch" asp-action="GravarSelecionados" class="btn green-button button-tamanho-padrao">Playlist</button>
</div>
Code of my control.
I think you might be missing something at a high level here so bear with me.
Your use case is you want users to 'check' videos that you serve to them via a web app, visually altering the page elements around the videos and ultimately sending them off for processing, which I assume means some kind of storage or at least some back-end work.
If I understand your attempted solution to this problem correctly, it is impossible. Even if you did get your backend to run javascript, it wouldn't be aware of the client's state and could not read that list of videos off of it. There's no reason for javascript to run on your server as I see it.
Instead, you need your client-side Javascript to send that list of ids to your server via an API in a JSON format. The flow goes (user checks box -> JS on the browser collects the id of that video and formats a POST request with some json describing what was checked -> that JSON is sent to your server which then reads it an processes it)
The frontend javascript and the server should always communicate with eachother in this way. Again, there's no need for javascript to be run on the server itself.
Moving on to thank everyone who gave suggestions for solving my problem for their support. I followed and tested all the suggestions and the one that fit best to my problem was the use of ajax, suggested by #Andre.Santarosa.
I followed the following article as a reference:http://www.macoratti.net/15/05/mvc_ajax.htm
I installed the package: Microsoft.jQuery.Unobtrusive.Ajax
I added the script reference in my _Layout.cshtml:
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
On the page that lists the videos, the code looks like this:
Button code:
<div id="btnplaylist" class="right_side hidden">
<input type="button" value="Playlist" id="Playlist" class="btn green-button button-tamanho-padrao" />
</div>
Ajax Code:
$('#Playlist').click(function () {
var url = "/VideoSearch/PegarListaDeIds";
var lista = listaDeIds;
$.post(url, { pListaDeIds: lista }, function (data) {
$("#msg").html(data);
});
});
I want to pass a checked value (upon hitting the submit button) to the .js function. The .js function should then take that checked value and query data from a sqlite db and AWS to populate the current webpage.
Here is what I think is happening in the posted code below. After checking a single box and hitting submit, the checked value is being passed to function getQuestionData(). Within getQuestionData(), an endpoint is created using the passed value then function appendInnerHTML is called to populate the page with queried data.
The error I get is
unreachable code after return statement[Learn More]
applied to the 4th line from the bottom ---- q.append('img').
I also noticed that whichever box is checked, my local URL changes. For example, if the box with Coordinate Geometry is checked, the url changes to
http://127.0.0.1:5000/?topic=Coordinate+Geometry
I had some help setting this up so I'm not 100% clear on the fundamentals, if that wasn't already obvious..
CODE
HTML
<form id="checkboxes">
<input type="submit" id="submitTopic" onsubmit="getQuestionData(this.value)">
</form>
.js
function getQuestionData() {
sampleValue = $('input[id=submitTopic]:checked').val()
//document.getElementById("submitTopic").value;
document.getElementById("question").innerHTML = ""
document.getElementById("solve").innerHTML = ""
var endPointQuestionData = '/api/v1/questions/' + sampleValue
Plotly.d3.json(endPointQuestionData, function(error, response) {
if (error) return console.warn(error);
appendInnerHMTL(response)
});
};
//populates webpage with data from sqlite db
function appendInnerHMTL(response) {
d3.select("#solve")
.append('h2')
.text("Solve.")
for (var i = 0; i < response.length; i++){
q = d3.select("#question")
d = q.append('div')
.append('strong')
.text(response[i]['id'])
d.append('div')
button = d.append('input')
.attr('class','button')
.attr('type','button')
.attr('value','Show Answer')
.attr('onclick','showAnswer('+ i + ')')
shownAnswer = d.append('div')
.attr('class','shownAnswer')
.text(response[i]['ans'])
document.getElementsByClassName('shownAnswer')[i].style.display='none';
//appends image from Amazon AWS to each id
q.append('img')
.attr('src', 'https://s3-us-west-1.amazonaws.com/actmath/' + response[i]['date'] + '/' + response[i]['id'] + '.JPG')
//retrieve .jpg file if .JPG file not found
.attr('onerror', 'this.oneerror=null;this.src=\"https://s3-us-west-1.amazonaws.com/actmath/' + response[i]['date'] + '/' + response[i]['id'] + '.jpg\";')
}
};
I have a list in HTML which I need to access in the java script to perform certain validation.
Below is the list skills that populates the drop down :
HTML
<select class="skill-select form-control" name="name" required="true" id="skill-name">
<option></option> <!-- Needed for select2 -->
<c:forEach items="${skills}" var="skill">
<option value="${skill.id}">${skill.name}</option>
</c:forEach>
</select>
I have tried using the below Javascript but nothing seems to happen:
$(".skill-select").change(function(){
var list = ${skills};
$.each(list, function( index, value ) {
alert( index + ": " + value );
});
});
Here, I am using Spring MVC to set the object skills is a list and hence it is not in json format to access it easily in the java script.
Could you please let me know how to access the skills list in the java script without converting it into json format?
Currently I am using the below java script :
$(".skill-select").change(function(){
var opts = $('#skill-name')[0].options;
var array = $.map(opts, function(elem) {
return (elem.text);
});
for (i = 1; i < array.length-1; i++) {
if ($('#skill-name :selected').text() == array[i]) {
$('#failure-msg').html('Could not add existing skill name. Please enter a new skill name and try again.');
$('#failure-msg').removeClass('hidden');
}
}
});
Is there any other efficient way of achieving the same by accessing the list in the javascript?
I want to implement a search box same as this, at first, just first dropdown list is active once user selects an option from the first dropbox, the second dropdown box will be activated and its list will be populated.
<s:select id="country" name="country" label="Country" list="%{country} onchange="findCities(this.value)"/>
<s:select id="city" name="city" label="Location" list=""/>
Jquery chained plugin will serve your purpose,
https://plugins.jquery.com/chained/
usage link - http://www.appelsiini.net/projects/chained
this plugin will chain your textboxes.
Try this code where based on your needs you have to populate it with your options:
var x;
$('#pu-country').on('change', function () {
if (this.value != '0') {
$('#pu-city').prop('disabled', false);
$('#pu-city').find("option").not(":first").remove();
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
switch (this.value) {
case 'A':
x = '<option value="A.1">A.1</option><option value="A.2">A.2</option><option value="A.3">A.3</option>'
}
$('#pu-city').append(x)
} else {
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
$('#pu-city').prop('disabled', true);
$('#pu-city').val("Choose");
}
});
$('#pu-city').on('change', function () {
if (this.value != '0') {
$('#pu-location').prop('disabled', false);
$('#pu-location').find("option").not(":first").remove();
switch (this.value) {
case 'A.1':
x = '<option value="A.1.1">A.1.1</option><option value="A.1.2">A.1.2</option><option value="A.1.3">A.1.3</option>'
break;
case 'A.2':
x = '<option value="A.2.1">A.2.1</option><option value="A.2.2">A.2.2</option><option value="A.2.3">A.2.3</option>'
break;
case 'A.3':
x = '<option value="A.3.1">A.3.1</option><option value="A.3.2">A.3.2</option><option value="A.3.3">A.3.3</option>'
break;
}
$('#pu-location').append(x)
} else {
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
}
});
I have also set up and a demo to see the functionallity with more options.
FIDDLE
Your code should be something like this:
$(country).change(function(){
var l=Document.getElementByID("country");
for(i=0;i<=l.length;i++)
{
if(l.options[i].selected?)
{
text_array=[HERE YOU NEED TO ADD THE CITIES OF l.options[i].text];
val_array=[HERE YOU NEED TO ADD THE VALUES OF THECITIES OF l.options[i].text];
}
}
var c=Document.getElementByID("city");
c.options.text=[];
c.options.value=[];
//You now should have an empty select.
c.options.text=text_array ;
c.options.value=val_array ;
});
As I don't know, what kind of DB you use, to have the cities connected to their countrys, I can't tell you, what to put into the uppercase text...
Ciao j888, in this fiddle i tried to reconstruct the same system as the site you provided the link
the number of states cityes and locality is less but the concept remains the same
If you want to add a new state you must enter a new html options in select#paese with an id.
Then you have add in obj.citta a property with this id name and an array of cityes for a value.
The same thing for obj.localita where you will create an array of arrays.
The jQuery code you need is
<script type="text/javascript">
$(document).ready(function(){
var obj={
citta:{ //value is the same of option id
albania:['Durres','Tirana'],
austria:['Vienna','innsbruck','Graz'],
},
localita:{//for every city create a sub array of places
albania:[['località Durres1','località Durres 2'],['località Tirana','località Tirana 2']],
austria:[['località Vienna','località Vienna 2'],['località innsbruck','località innsbruck 2'],['località Graz','località Graz 2','località Graz 3']],
}
}
$('#paese').on('change',function(){
$('#località').attr('disabled','disabled').find('option').remove()
var quale=$(this).find('option:selected').attr('id')
var arr=obj.citta[quale]
if(arr){
$('#citta').removeAttr('disabled')
$('#citta option.added').remove()
for(i=0;i<arr.length;i++){
$('<option class="added">'+arr[i]+'</option>').appendTo('#citta')
}
}
})
$('#citta').on('change',function(){
var ind=($(this).find('option:selected').index())-1
var quale=$('#paese').find('option:selected').attr('id')
var arr=obj.localita[quale][ind]
if(arr){
$('#località').removeAttr('disabled')
$('#località option.added').remove()
for(i=0;i<arr.length;i++){
$('<option class="added">'+arr[i]+'</option>').appendTo('#località')
}
}
})
})
</script>
If this solution does not suit your needs, i apologize for making you lose time.
Hi i have done this for license and its dependent subject in yii 1.
The license dropdown
//php code
foreach($subject as $v) {
$subj .= $v['licenseId'] . ":" . $v['subjectId'] . ":" . $v['displayName'] . ";";
}
Yii::app()->clientScript->registerScript('variables', 'var subj = "' . $subj . '";', CClientScript::POS_HEAD);
?>
//javascript code
jQuery(document).ready(function($) {
//subject. dependent dropdown list based on licnse
var ty, subjs = subj.split(';'), subjSel = []; //subj register this varible from php it is
for(var i=0; i<subjs.length -1; i++) { //-1 caters for the last ";"
ty = subjs[i].split(":");
subjSel[i] = {licId:ty[0], subjId:ty[1], subjName:ty[2]};
}
//dropdown license
jQuery('#license#').change(function() {
$('#add').html(''); //clear the radios if any
val = $('input[name="license"]:checked').val();
var selectVals = "";
selectVals += '<select>';
for(var i=0; i<subjSel.length; i++) {
if(subjSel[i].licId == val) {
if(subjSel[i].subjId *1 == 9) continue;
selectVals += '<option value="'+subjSel[i].subjId+'">'+subjSel[i].subjName+'</option>';
}
}
selectVals += '</select>';
$("#subject").html(selectVals);
});
});
You seem to be asking two questions:
QUESTION 1. How to have a disabled select box (the second and third select boxes in the case of your example) which is activated upon the selection of an option from the first select box.
ANSWER 1:
simply use the disabled=true/false as below...
<select id="country" name="country" label="Country" onchange="document.getElementById('city').disabled=false; findCities(this.value)"/>
<select id="city" name="city" label="Location" disabled=true/>
NOTE: I changed "s:select" to "select" on the basis that your question does not make reference or tag the Struts framework that uses this syntax.
QUESTION 2: How to populate the second select box when a selection is made in the first.
ANSWER 2: There are many ways to do this, and the choice depends on where you have the data to populate the lists with. In the case of your Rentalcars example, if you chose Barbados, the browser sends an ajax GET request to "http://www.rentalcars.com/AjaxDroplists.do;jsessionid=5DCBF81333A88F37BC7AE15D21E10C41.node012a?country=Barbados&wrapNonAirports=true" -try clicking on this link and you will see what that request is sending back. This '.do' address is a server side file of a type used with the Struts framework I mentioned above.
A more conventional approach, which would be included in your function findCities(country)would be to send an AJAX request to a PHP script which queries a database and sends back an array of place names to the browser. The AJAX javascript code includes instructions as to what to do with the response. Without knowing more about where you want to store your list, giving an example of this would most likely not be useful.
Alternatively, the whole list of places could be included in the javascript script as an array (as demonstarated by Devima, above), in a text document on the server as comma separated values, or you could save it to a browser database like WebSQL or IndexedDB if offline use would be useful.
When you have got your list, probably as an array of values, you could save the array as a variable eg. var cities=result (in the case of a simple ajax request). You will then need to iterate through cities, for example
for (var i = 0; i < cities.length; i++){
var place=cities[i];//an individual city name
document.getElementById("city").innerHTML+="<option value='" + place + "'>" + place + "</option>";//adds an 'option' with the value being the city name and the text you see being the city name
}
IMO this is the base case AngularJS was designed to completely alleviate. Check it out!
I am new to javascript, i am trying to make a small site with two HTML pages (A and B) and a global js file.
So lets say i have selected certain items in page A, the list-preview on Page A gets updated.
But if i want to see the list in detail i have to go to page B.
Page A and B bith use the same .js file, the selected items are saved in a array.
How do i make sure the selected items still stay in the array, and the array doesn't get flushed when i go from page A to page B ?
what i thought of was ...
var selectedProductsName = new Array();
in OwnJS.js
the adding items to the preview list works.
i'm only struggling to keep the array unflushed when i go to page B from page A.
HTML5 introduces a new thing called localStorage. It's basically some kind of storage that is persistent between all pages of your website as well as between user sessions. It can be accessed as a simple key/value store:
var selectedProductsName = localStorage.getItem("selectedProductsName");
And to set:
localStorage.setItem("selectedProductsName", []);
Here's an article about getting started with localStorage, if you want to be able to do more things like checking browser compatibility for localStorage and watching the storage event, among others.
You could use the HTML5 local storage. It lets you tell the browser to save data on the user's machine. (There's also session storage, valid only for the current session.)
Save (in Apply.html)
IN.API.Profile("me")
.fields(["id", "firstName", "lastName", "pictureUrl","headline","industry","location:(name)","positions:(title)","emailAddress"])
.result(function(result) {
profile = result.values[0];
// save all keys to local storage
for (f in profile) localStorage[f] = fields[f];
// more stuff ...
});
to Retrieve (in personal_Info.html)
// retrieve first name from local storage
var firstName = localStorage["firstName"];
if (firstName !== undefined) {
$("#textfield1").attr(value, firstName);
}
Source Page
The Source Page has an HTML Button with a jQuery Click event handler. When the Button is clicked, the values of the Name TextBox and the Technology DropDownList is set as QueryString Parameter and then the page is redirected to the Destination page (Page2.htm).
<input type="button" id="btnQueryString" value="Send" />
<script type="text/javascript">
$(function () {
$("#btnQueryString").bind("click", function () {
var url = "Page2.htm?name=" + encodeURIComponent($("#txtName").val()) + "&technology=" + encodeURIComponent($("#ddlTechnolgy").val());
window.location.href = url;
});
});
</script>
Destination Page
On the Destination page (Page2.htm), inside the jQuery Page Load event handler the URL of the page is first checked to determine whether it has some QueryString Parameters being received, this is done by checking the window.location.search property. If it has some QueryString Parameters then loop is executed and each QueryString Key and Value Pair is inserted in an Array and finally the values are displayed on the page using the HTML span.
<script type="text/javascript">
var queryString = new Array();
$(function () {
if (queryString.length == 0) {
if (window.location.search.split('?').length > 1) {
var params = window.location.search.split('?')[1].split('&');
for (var i = 0; i < params.length; i++) {
var key = params[i].split('=')[0];
var value = decodeURIComponent(params[i].split('=')[1]);
queryString[key] = value;
}
}
}
if (queryString["name"] != null && queryString["technology"] != null) {
var data = "<u>Values from QueryString</u><br /><br />";
data += "<b>Name:</b> " + queryString["name"] + " <b>Technology:</b> " + queryString["technology"];
$("#lblData").html(data);
}
});
</script>