【问题标题】:Conditional formatting script - set iteration条件格式脚本 - 设置迭代
【发布时间】:2019-04-10 15:20:16
【问题描述】:

我有一个用于条件格式规则的自定义公式。我正在尝试编写一个脚本来检查列('Mine'表上的 B 列)上的多个值(大约 50),如果单元格等于特定字符串(M1、M2 或 M3),则指定公式条件格式应用于“日历视图”工作表。我目前拥有的代码是:

function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Calendar View");
sheet.getRange("C4:NC50").clearFormat();
var range = sheet.getRange("C4:NC4");
var rule = SpreadsheetApp.newConditionalFormatRule()
    .whenFormulaSatisfied('=AND(indirect("Mine!$B5")="M1", C$2>=indirect("Mine!$C5"), C$2<indirect("Mine!$D5"))')
    .setBackground("#FF0000")
    .setRanges([range])
    .build();
var rules = sheet.getConditionalFormatRules();
rules.push(rule);
sheet.setConditionalFormatRules(rules);
}

如何在.whenFormulaSatisfied上输入迭代方法,如:

.whenFormulaSatisfied('=AND(indirect("Mine!$B6")="M1", C$2>=indirect("Mine!$C6"), C$2<indirect("Mine!$D6"))')
.whenFormulaSatisfied('=AND(indirect("Mine!$B7")="M1", C$2>=indirect("Mine!$C7"), C$2<indirect("Mine!$D7"))')
.whenFormulaSatisfied('=AND(indirect("Mine!$B8")="M1", C$2>=indirect("Mine!$C8"), C$2<indirect("Mine!$D8"))')
............

这是我正在处理的工作表: https://docs.google.com/spreadsheets/d/1Af84aHaG0VjXmtaWc0-uAdGFrX1LozRNLQLMatSOqgU/edit?usp=sharing

【问题讨论】:

    标签: google-sheets formatting conditional


    【解决方案1】:

    提问者的方法存在一些挑战 - 首先,动态识别每个属性的开始和结束日期,其次,创建多达 50 条单独的条件格式规则。众所周知,电子表格的性能受条件格式规则数量的影响。

    我建议采用稍微不同的方法。
    1) 获取我的数据并构建日历。
    2) 在预订日期字段中输入值。
    3) 为日历应用单一条件格式规则。

    识别预订日期的方法是在相应的单元格中插入一个名义值。然后应用规则.whenCellNotEmpty() 而不是指定特定值。此外,代码格式化了背景和字体颜色,以便隐藏任何数据。

    还要注意:在脚本的开头,代码会同时删除内容和格式。

    function so_53185335() {
        // build the spreadsheet app and set source and target sheets
        var ss = SpreadsheetApp.getActiveSpreadsheet();
        var calSheet = ss.getSheetByName("Calendar View");
        var dataSheet = ss.getSheetByName("Mine");
    
        // get the last rows and start rows for both sheets 
        var lrMine = dataSheet.getLastRow();
        var lrCal = calSheet.getLastRow();
        var dataRowStart = 5;
        var calRowStart = 4;
    
        // clear formats and data from Calendar  
        calSheet.getRange(calRowStart, 2, lrCal, 366).clear({
            contentsOnly: true,
            formatOnly: true
        });
    
        // get Mine rows with data, define the range and  get data
        var dataRows = lrMine - dataRowStart + 1;
        //Logger.log("Mine: number of data rows "+dataRows);// DEBUG  
        var dataRange = dataSheet.getRange(dataRowStart, 2, dataRows, 3);
        //Logger.log("data range is "+dataRange.getA1Notation());// DEBUG
        var dataValues = dataRange.getValues();
    
        //set some variables for use in loop  
        var i = 0; // counter
        var z = 0; // counter
        var calstartCol = 3; // equals first day of the year
        var calrow = 0; // counter row for Calendar sheet
        var calArray = [];
        var masterArray = [];
    
        // loop through the rows in Mine
    
        for (i = 0; i < dataRows; i++) {
            // test for value 
            if (dataValues[i][0] === "M1" || dataValues[i][0] === "M2" || dataValues[i][0] === "M3") {
                //Logger.log("Match: i="+i+", value = "+dataValues[i][0]);//DEBUG
                calArray = [];
                masterArray = [];
                calrow = calrow + 1;
    
                // calculate the start day (as a day in the year)
                var now = new Date(dataValues[i][1]);
                var start = new Date(now.getFullYear(), 0, 0);
                var diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
                var oneDay = 1000 * 60 * 60 * 24;
                var startday = Math.floor(diff / oneDay);
    
                // calculate the end day (as a day in the year)
                var fnow = new Date(dataValues[i][2]);
                var fstart = new Date(fnow.getFullYear(), 0, 0);
                var fdiff = (fnow - fstart) + ((fstart.getTimezoneOffset() - fnow.getTimezoneOffset()) * 60 * 1000);
                var foneDay = 1000 * 60 * 60 * 24;
                var endday = Math.floor(fdiff / foneDay);
                var nod = endday - startday + 1;
    
                // assign the value for the Property
                var cell = calSheet.getRange(calstartCol + calrow, 2);
                cell.setValue(dataValues[i][0]);
    
                // create an array of values for booked dates; just insert the number "1"
                for (z = 1; z < nod + 1; z++) {
                    calArray.push(1);
                }
                masterArray.push(calArray);
    
                // Assign the values for booked dates
                var cell = calSheet.getRange(calstartCol + calrow, startday + 2, 1, nod);
                cell.setValue(masterArray);
            }
    
        }
    
        // create and apply a single Conditional forma rule for the data range on Calendar
        var range = calSheet.getRange(calRowStart, calstartCol, calstartCol + calrow, 366);
        var rule = SpreadsheetApp.newConditionalFormatRule()
            .whenCellNotEmpty()
            .setFontColor("#FF0000")
            .setBackground("#FF0000")
            .setRanges([range])
            .build();
        var rules = calSheet.getConditionalFormatRules();
        rules.push(rule);
        calSheet.setConditionalFormatRules(rules);
    
    }
    

    日历看起来像这样。


    【讨论】:

    • 非常感谢您的回答!您的方法听起来很棒,我已经可以看到电子表格正在努力应对一些条件格式规则。我刚刚在上面的测试电子表格上尝试过,但出现以下错误:“范围的坐标或尺寸无效。(第 70 行,文件“测试宏”)”,在这一行:var cell = calSheet.getRange( calstartCol + calrow, startday + 2, 1, 点头);
    • @Spyr 您的原始电子表格具有芬兰的语言环境和赫尔辛基 (GMT+2) 的时区,并且原始项目时区也是赫尔辛基 (GMT+2)。目前您的电子表格区域设置 = 英国,电子表格时区 = 赫尔辛基 (GMT+2) 和(显着)项目时区 = 东部 (GMT-5)。编辑您的电子表格设置和项目设置,使它们都具有相同的时区;我也会调整语言环境。修复这些并重新运行 - 应该没问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    相关资源
    最近更新 更多