简体   繁体   English

Javascript & HTML - 传递下拉索引值作为对象属性返回未定义

[英]Javascript & HTML - Passing dropdown index value as object property returns undefined

I'm brand new to this language and I've hit a road block.我是这种语言的新手,但遇到了障碍。 I've searched for a few hours about this specific problem but can't seem to figure out why my situation is so hard to fix.我已经针对这个特定问题搜索了几个小时,但似乎无法弄清楚为什么我的情况如此难以解决。 I'm sure I just need a set of eyes that knows what they're looking at.我确定我只需要一双知道自己在看什么的眼睛。

I'm trying to pass the index of a dropdown select into my Code.gs function so that I can use it elsewhere to select a certain row of a data in a spreadsheet.我正在尝试将下拉选择的索引传递到我的 Code.gs 函数中,以便我可以在其他地方使用它来选择电子表格中的某一行数据。 I set up the object driverPicked and give it the property selected, and then hunt for the selected index property.我设置了对象 driverPicked 并为其指定了选定的属性,然后寻找选定的索引属性。 As I'm really new to this, I'm having a hard time understanding the consequences of nesting properties like this and could use a clue as to how to solve the "TypeError: Cannot read property 'selected' of undefined (line 39, file "Code")" error I've been getting for hours now.由于我对此非常陌生,因此我很难理解像这样嵌套属性的后果,并且可以使用线索来解决如何解决“TypeError:无法读取未定义的属性‘selected’(第 39 行,文件“代码”)”错误我已经有几个小时了。

There are so many similar answers but I can't sort out exactly how they apply to me - so forgive me for that!有很多类似的答案,但我无法确切地弄清楚它们如何适用于我 - 所以请原谅我!

var url = "REDACTED";

function doGet(e){

//var x = document.getElementById("driver").selectedIndex;  

var driverIndex = userClicked();
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Results_2019");
var listDrivers = ws.getRange(4,1,ws.getRange("A3").getDataRegion().getLastRow(),1).getValues();
var infoHeading = ws.getRange(3, 1, 1, 8).getValues();
var driverInfo = ws.getRange(driverIndex, 1, 1 ,8).getValues();


var tmp = HtmlService.createTemplateFromFile("page"); 
tmp.title = "GLTC Driver List";
//tmp.listDrivers = listDrivers.map(function(r){r[0];});
tmp.listDrivers = [].concat.apply([], listDrivers);
tmp.infoHeading = [].concat.apply([], infoHeading);
tmp.driverInfo = [].concat.apply([], driverInfo);
tmp.driverIndex = driverIndex;


return tmp.evaluate();

}


function include(filename){
  return HtmlService.createHtmlOutputFromFile(filename).getContent();
}


function userClicked(driverPicked) {
  console.log(driverPicked); 
  var driverName = driverPicked.value;
  return driverName;
}


<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <!--Let browser know website is optimized for mobile-->
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <!--Import Google Icon Font-->
     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <?!= include("page-css"); ?>
  </head>
  <body>

    <h1><?= title; ?></h1>

    <div class="input-field">
  <select id="driver">
    <option disabled selected>Choose Driver</option>
    <? for(var i=0;i<listDrivers.length;i++){ ?>
      <option class="selected">
        <?= listDrivers[i]; ?>
      </option>
      <? } ?>
  </select>
</div>

  <h5><?= infoHeading; ?></h5>

  <h5><?= driverInfo; ?></h5>

  <h5><?= driverIndex; ?></h5>

<script>  

document.getElementById("driver").addEventListener("change", doStuff); // add onchange listener to the select element instead of options

function doStuff(event) {
  var driverPicked = {};

  driverPicked.driver = event.target.value;
  driverPicked.selected = event.target.options.selectedIndex;
  userClicked(driverPicked);
}


  </script>

    <!-- Compiled and minified JavaScript -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <?!= include("page-js"); ?>

  </body>
</html>

A few issues with the code:代码的几个问题:

  1. DOM elements' ids have to be unique, so when rendering options you either need to add index to id or use a class name instead. DOM 元素的 id 必须是唯一的,因此在呈现选项时,您需要为 id 添加索引或使用类名。
  2. Instead of click use change event for select elements.select元素使用change事件而不是click
  3. You can access event object as an argument inside doStuff function instead of querying DOM elements manually.您可以在doStuff函数中访问事件对象作为参数,而不是手动查询 DOM 元素。 I'm not sure why would you need to get an index, but in order to get driver's name you can do smth like this:我不确定为什么需要获取索引,但是为了获取驱动程序的名称,您可以这样做:
<div class="input-field">
  <select id="driver">
    <option disabled selected>Choose Driver</option>
    <? for(var i=0;i<listDrivers.length;i++){ ?>
      <option class="selected"> // use class instead of id here
        <?= listDrivers[i]; ?>
      </option>
      <? } ?>
  </select>
</div>
document.getElementById("driver").addEventListener("change", doStuff); // add onchange listener to the select element instead of options

function doStuff(event) {
  var driverPicked = {};

  driverPicked.driver = event.target.value;
  driverPicked.selected = event.target.options.selectedIndex;

  google.script.run.userClicked(driverPicked);
}

function userClicked(driverPicked) {

  var driverName = driverPicked.value;
  return driverName;
}

Here's a runnable example with some mock select options:这是一个带有一些模拟select选项的可运行示例:

 document.getElementById("driver").addEventListener("change", doStuff); // add onchange listener to the select element instead of options function doStuff(event) { var driverPicked = {}; driverPicked.driver = event.target.value; driverPicked.selected = event.target.options.selectedIndex; userClicked(driverPicked); } function userClicked(driverPicked) { console.log(driverPicked); var driverName = driverPicked.value; return driverName; }
 <div class="input-field"> <select id="driver"> <option disabled selected>Choose Driver</option> <option class="selected"> Driver 1</option> <option class="selected"> Driver 2</option> </select> </div>

There aa few simplifications done here.这里做了一些简化。 Main one would be that instead of invoking the function via google.script.run I am just directly calling it.主要的是,我不是通过google.script.run调用该函数,而是直接调用它。

UPDATE更新

I forgot to include in the initial response.我忘了包括在最初的回应中。 Element id s are supposed to be unique.元素id应该是唯一的。 If you loop through all your elements and do not change their id value then you are crafting incorrect HTML and the function getElementById(...) will return an array of elements instead of just on (thus, the rest of the code will not work as expected)如果您遍历所有元素并且不更改它们的 id 值,那么您正在制作不正确的 HTML,并且函数getElementById(...)将返回一个元素数组而不是仅返回一个元素数组(因此,其余代码将不起作用正如预期的那样)

See demo below见下面的演示

 document.getElementById("driver").addEventListener("change", doStuff); function doStuff() { var driverPicked = {}; selectBox = document.getElementById("driver"); driverPicked = selectBox.options[selectBox.selectedIndex]; console.log('User changed value to: '); console.log(driverPicked); // will this work on other browsers? // google.script.run.userClicked(driverPicked); // I am using this instead for demo purposes userClicked(driverPicked); } function userClicked(driverPicked) { var driverName = driverPicked.value; var driverText = driverPicked.text; console.log('name/value: ' + driverName + ' text: ' + driverText); return driverName; }
 <div class="input-field"> <select id="driver"> <option disabled>Choose Driver</option> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> <option value="4">Four</option> </select> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM