【问题标题】:fill out template sheet when a name in a dropdown menu is selected选择下拉菜单中的名称时填写模板表
【发布时间】:2019-10-15 14:55:05
【问题描述】:

我已经创建了一个成绩报告 Google 电子表格,但现在我正在寻找一种方法来用一个学生的成绩填写我的模板报告表。我怎样才能做到这一点?

在文件 1 中,我有学生的所有成绩。在文件 2 中,我有成绩报告的模板。如何在显示所有学生的模板成绩报告中创建一个下拉菜单,并且当我单击其中一个学生时会自动填写成绩报告中的所有字段? 我现在使用 importrange 函数将列中的数据导入模板,但现在我需要每个学生的成绩报告文件。 这确实比为每个学生创建一个成绩报告文件效率更高。

我希望你能帮助我。

文件 1: https://docs.google.com/spreadsheets/d/12M8W7fARJJZN90wM79U4x8RmcnZ08kFSDcZYnB26HB0/copy

文件 2: https://docs.google.com/spreadsheets/d/13-0qhCudC7EYRgOs2UpbJPRSq2nKoBiG2Md3-U8_U1Q/copy

【问题讨论】:

    标签: google-apps-script google-sheets drop-down-menu autofill google-sheets-macros


    【解决方案1】:

    您可以使用以下代码:

    var LIST_WITH_GRADES_ID = 'YOUR_ID';
    var LIST_WITH_GRADES_STUDENTS_A1 = 'Rapportoverzicht!B2:Y2';
    
    function onOpenSpreadsheet(e) {
      var students = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getRange(LIST_WITH_GRADES_STUDENTS_A1).getValues()[0];
      var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(students).setAllowInvalid(false);
      SpreadsheetApp.getActive().getRange('Rapport!E1').setDataValidation(rangeRule);
    }
    
    function onEditSpreadsheet(e) {
      var rapportSheet = SpreadsheetApp.getActive().getSheetByName('Rapport');
      if (e.range.getA1Notation() == 'E1' && e.range.getSheet().getName() == 'Rapport') {
        var studentCol = findStudentCol(e.range.getValue());
        copyStudentGrades(studentCol);
      }
    }
    
    /* Returns 1-indexed student column */
    function findStudentCol(student) {
      var sheet = SpreadsheetApp.openById(LIST_WITH_GRADES_ID);
      var studentsRange = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getRange(LIST_WITH_GRADES_STUDENTS_A1);
      for (var col=1; col<=studentsRange.getWidth(); col++) {
        if (studentsRange.getCell(1, col).getValue() == student) 
          return col + studentsRange.getColumn() - 1;
      }
    }
    
    function copyStudentGrades(studentCol) {
      var gradesSheet = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getSheetByName('Rapportoverzicht');
      var templateSheet = SpreadsheetApp.getActive().getSheetByName('Rapport');
    
      templateSheet.getRange(4, 4, 30, 1).setValues(
        gradesSheet.getRange(4, studentCol, 30, 1).getValues());
    
      templateSheet.getRange(4, 10, 25, 1).setValues(
        gradesSheet.getRange(36, studentCol, 25, 1).getValues());
    }
    

    您必须将成绩表的 ID 放在第一行,然后将此脚本添加到“模板”表的编辑器中。您还需要将onOpenSpreadsheet 和onEditSpreadsheet 设置为可安装的触发器以使其工作(请参阅managing triggers manually)。

    编辑

    为了同时使用两个不同的成绩文件并导入备注,您可以使用之前代码的以下编辑:

    var LIST_WITH_GRADES_ID = 'YOUR_LIST_WITH_GRADES_1_ID';
    var LIST_WITH_GRADES_2_ID = 'YOUR_LIST_WITH_GRADES_2_ID';
    var LIST_WITH_GRADES_STUDENTS_A1 = 'Rapportoverzicht!B2:AG2';
    var NSTUDENTS = 24; // Number of students
    
    function onOpenSpreadsheet(e) {
      var students = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getRange(LIST_WITH_GRADES_STUDENTS_A1).getValues()[0];
      var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(students).setAllowInvalid(false);
      SpreadsheetApp.getActive().getRange('Rapport!E1').setDataValidation(rangeRule);
    }
    
    function onEditSpreadsheet(e) {
      var currentStudent = e.range.getValue();
      var rapportSheet = SpreadsheetApp.getActive().getSheetByName('Rapport');
      if (e.range.getA1Notation() == 'E1' && e.range.getSheet().getName() == 'Rapport') {
        var studentCol = findStudentCol(currentStudent);
        copyStudentGrades(studentCol);
        importRemarks(currentStudent);
      }
    }
    
    /* Returns 1-indexed student column */
    function findStudentCol(student) {
      var sheet = SpreadsheetApp.openById(LIST_WITH_GRADES_ID);
      var studentsRange = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getRange(LIST_WITH_GRADES_STUDENTS_A1);
      for (var col=1; col<=studentsRange.getWidth(); col++) {
        if (studentsRange.getCell(1, col).getValue() == student) 
          return col + studentsRange.getColumn() - 1;
      }
    }
    
    function copyStudentGrades(studentCol) {
      var gradesSheet = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getSheetByName('Rapportoverzicht');
      var gradesSheet2 = SpreadsheetApp.openById(LIST_WITH_GRADES_2_ID).getSheetByName('Rapportoverzicht');
      var templateSheet = SpreadsheetApp.getActive().getSheetByName('Rapport');
    
      templateSheet.getRange(4, 4, 30, 1).setValues(
        gradesSheet.getRange(4, studentCol, 30, 1).getValues());
    
      templateSheet.getRange(4, 10, 25, 1).setValues(
        gradesSheet.getRange(36, studentCol, 25, 1).getValues());
    
      templateSheet.getRange(4, 6, 30, 1).setValues(
        gradesSheet2.getRange(4, studentCol, 30, 1).getValues());
    
      templateSheet.getRange(4, 12, 25, 1).setValues(
        gradesSheet2.getRange(36, studentCol, 25, 1).getValues());
    }
    
    function importRemarks(student) {
      var remarksSheet = SpreadsheetApp.openById(LIST_WITH_GRADES_ID).getSheetByName('opmerkingen rapport');
      var remarksSheet2 = SpreadsheetApp.openById(LIST_WITH_GRADES_2_ID).getSheetByName('opmerkingen rapport');
      var templateSheet = SpreadsheetApp.getActive().getSheetByName('Opmerkingen');
      var studentRow;
    
      for (var i=2; i<(2+NSTUDENTS); i++) {
        if (remarksSheet.getRange(i, 1).getValue() == student) {
          studentRow = i;
          break;
        }
      }
    
      templateSheet.getRange('B5').setValue(remarksSheet.getRange(studentRow, 2).getValue());
      templateSheet.getRange('B11').setValue(remarksSheet2.getRange(studentRow, 2).getValue());
    }
    

    【讨论】:

    • 你好,我试着让它工作,但我仍然在努力解决一些问题。 - 你的_ID是docs.google.com/spreadsheets/d之后链接的最后一部分?
    • @RikKnijnenburgDaltonschoolO 正确,在这种情况下,您的 ID 应为 12M8W7fARJJZN90wM79U4x8RmcnZ08kFSDcZYnB26HB0(摘自您的原始问题)。让我知道这是否适合你。干杯
    • - 我如何创建一个下拉菜单,我可以在其中选择学生来触发脚本? - 如何正确设置触发器?我没有太多使用这些功能的经验。所以我在这里有点迷路了。 docs.google.com/spreadsheets/d/…docs.google.com/spreadsheets/d/…
    • 和脚本编辑器链接:script.google.com/d/…
    • @RikKnijnenburgDaltonschoolO 脚本的第一行应如下所示:var LIST_WITH_GRADES_ID = '12M8W7fARJJZN90wM79U4x8RmcnZ08kFSDcZYnB26HB0'。此外,您必须设置一个 onOpen 触发器(请参阅我的答案)。设置后,将为您创建下拉列表。另外,请记得设置 onEdit 触发器。
    【解决方案2】:

    我认为这不太可能在第一次就起作用。我无法复制您的工作表,所以我根本无法对此进行测试。我以前写过这样的东西,但通常需要一些调整才能使其正常工作。我也不相信 onEdit() 部分将始终在 30 秒内完成,但我愿意给它一个机会,但您可能必须转换为选择一个学期,然后选择一个学生,然后单击一个按钮。

    阅读cmets:

    //add this function to an installable onOpen Trigger
    function onOpenFunc() {
      var ss=SpreadsheetApp.getActive();
      var sh=ss.getSheetByName('Rapport');
      var slss=SpreadsheetApp.openById("12M8W7fARJJZN90wM79U4x8RmcnZ08kFSDcZYnB26HB0");
      var slsh=slss.getSheetByName("Rapportoversicht");
      var namerg=slsh.getRange(2,1,1,slsh.getLastColumn());
      var cell=sh.getRange(1,2);
      cell.clearDataValidations();
      var rule1=SpreadsheetApp.newDataValidation()
      .setAllowInvalid(false)
      .requireValueInRange(namerg)
      .build();//gets student list into drop down
      cell.setDataValidation(rule1);
      var rule2=SpreadsheetApp.newDataValidation()
      .setAllowInvalid(false)
      .requireValueInList([1,2])
      .build();//Semester selection 1 or 2
      cell.offset(1,0).setDataValidation(rule2);
    }
    
    //This has to be an installable trigger
    function onEditFunc(e) {
      var sh=e.range.getSheet();
      if(sh.getName()!='Rapport')return;
      if(e.range.getColumn==5 && e.range.getRow()==1 && e.value && e.value!=e.oldValue ) {
        fillInStudentInformation(e.value,e.range.offset(1,0).getValue());  
      }
    }
    
    //I am not sure that this will always complete in 30 seconds so you may have to revert to clicking a button after selecting a semester and a student.
    function fillinStudentInformation(student,semester) {
      var slss=SpreadsheetApp.openById("12M8W7fARJJZN90wM79U4x8RmcnZ08kFSDcZYnB26HB0");
      var slsh=slss.getSheetByName("Rapportoversicht");
      var hrg=slsh.getRange(2,2,1,slsh.getLastColumn()-1);
      var hA=nrg.getValues()[0];
      var hObj={};
      var lObj={};
      hA.forEach(function(name,i){hObj[name]=i+1;});//column number
      var grdRg=slsh.getRange(4,hObj[student],60,1);
      var lblRg=slsh.getRange(4,1,60,1);
      var grdA=grdRg.getValues();
      var lblA=lblRg.getValues();
      lblA.forEach(function(lbl,i){
        if(lbl && grdA[i]) {
          lObj[lbl]=grdA[i];//object converts from labels to grades
        }
      });
      var ss=SpreadsheetApp.getActive();
      var sh=ss.getSheetByName('Rapport');
      var rg1=sh.getRange(4,2,sh.getLastRow()-3,5);
      var vA=rg1.getValues();
      var rg2=sh.getRange(4,8,sh.getLastRow()-3,5);
      var vB=rg2.getValues();
      //left half
      for(var i=0;i<vA.length;i++) {
        if(vA[i][0] && lObj.hasOwnProperty(vA[i][0])) {
          switch(semester) {
            case 1:
              sh.getRange(i+4,4).setValue(lObj[vA[i][0]]);
              break;
            case 2:
              sh.getRange(i+4,6).setValue(lObj[vA[i][0]]);
              break;
          }
    
        }
      }
      //right half
      for(var i=0;i<vB.length;i++) {
        if(vB[i][0] && lObj.hasOwnProperty(vB[i][0])) {
          switch(semester) {
            case 1:
              sh.getRange(i+4,10).setValue(lObj[vB[i][0]]);
              break;
            case 2:
              sh.getRange(i+4,12).setValue(lObj[vB[i][0]]);
              break;
          }
    
        }
      }
    }
    

    【讨论】:

    • 感谢您的帮助。我已经编辑了链接。单击时,它会自动创建一个副本。我希望这对你更有效。
    • 好的,谢谢,我会在我使用桌面时回复它。
    猜你喜欢
    • 2019-02-10
    • 2012-07-24
    • 1970-01-01
    • 2020-11-25
    • 2016-08-18
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多