动态创建单元格范围输出

Create a cell range output dynamically

在我的加载项中,我发出 HTTP 请求并接收输出。我想将该输出放入一个绑定中,并在必要时让它扩展绑定,因为用户不一定知道输出将有多少行 x 列。我该怎么做呢?目前我绑定到一个范围,但如果该范围与我提供的 [[]] 的大小不匹配,则数据不会显示在 sheet 中。所以,这最终要求用户知道输出的大小。

我目前使用 Angular 做的事情如下(问题在于输出的大小并不总是与用户在传播中选择的 Office.BindingType.Matrix 相同sheet):

我创建了到应该放置输出的位置的绑定,如下所示:

inputBindFromPrompt(parameterId: number): Promise<IOfficeResult> {
        let bindType: Office.BindingType;
        if(this.inputBindings[parameterId].type != 'data.frame' && this.inputBindings[parameterId].type != 'vector') {
            bindType = Office.BindingType.Text;
        } else {
            bindType = Office.BindingType.Matrix;
        }
        return new Promise((resolve, reject) => {
            this.workbook.bindings.addFromPromptAsync(bindType, { id: this.inputBindings[parameterId].name },
            (addBindingResult: Office.AsyncResult) => {
                if(addBindingResult.status === Office.AsyncResultStatus.Failed) {
                    reject({
                        error: 'Unable to bind to workbook. Error: ' + addBindingResult.error.message
                    });
                } else {
                    this.inputBindings[parameterId].binding = addBindingResult.value;
                    resolve({
                        success: 'Created binding ' + addBindingResult.value.type + ' on ' + addBindingResult.value.id
                    });
                }
            })
        })
    }

然后,当用户通过按钮提交时,输入被传递到 HTTP 请求服务,然后接收输出,我将其处理成数组数组,以便它可以进入 Office.BindingType.Matrix:

this.isBusy = true;
        this.feedback = 'submitted';
        // Grab the values from the form
        // Send as a POST and receive an output
        // Put the output in the Excel sheet
        this.webServicesService.postWebServices(this.service, this.inputParameters)
        .subscribe(
          (data: any) => {
            // Correctly received data
            // Access the data by name while looping through output parameters
            this.error = false;
            this.feedback = 'received data';
            let i = 0;
            this.outputParameters.forEach(element => {
              // temporary name to identify the parameter
              let name = element.name;
              // Set the data value in the parameter
              if(element.type == 'data.frame') {
                let parameter = data[name];
                this.feedback = parameter;
                let excelData = [];
                for(var key in parameter) {
                  if(parameter.hasOwnProperty(key)) {
                    var val = parameter[key];
                    excelData.push(val);
                  }
                }

                element.value = excelData;

              }
              else {
                element.value = data[name];
              }
              // Set value in the form
              let param = (<FormArray>this.serviceForm.controls['outputParameters']).at(i);
              param.patchValue({
                value: element.value
              });
              // Set value in the spreadsheet
              this.excelService.outputSetText(i, element.value)
                .then((result: IOfficeResult) => {
                  this.onResult(result);
                  i++;
                });

            }, (result: IOfficeResult) => {
                  this.onResult(result);
                });
          },
          (error) => {
            if(error.status == 400 || error.status == 401) {
              // Return user to authentication page
              this.authService.logout();
              this.router.navigate(['/']);
            } else {
              // Tell user to try again
              this.error = true;
            }
          }
        );

上面将值设置为 Office.Matrix.Binding 的行是 this.excelService.outputSetText(i, element.value),它在 Excel 服务中调用此方法:

outputSetText(parameterId: number, data: any): Promise<IOfficeResult> {
    return new Promise((resolve, reject) => {
        if(this.outputBindings[parameterId].binding) {
            this.outputBindings[parameterId].binding.setDataAsync(data, function (result: Office.AsyncResult) {
                if(result.status == Office.AsyncResultStatus.Failed) {
                    reject({ error: 'Failed to set value. Error: ' + result.error.message });
                } else {
                    let test: Office.Binding;
                    resolve({
                        success: 'successfully set value'
                    });
                }
            })
        } else {
            reject({
                error: 'binding has not been created. bindFromPrompt must be called'
            });
        }
    })
}

它本质上是使用 addFromPromptAsync() 为 HTTP 请求设置输出点。然后用户提交发送请求,接收回数据并处理成数组[[]]的数组,这样它就可以是Office.BindingType.Matrix的正确数据格式。但是,除非这与最初选择的绑定的行数和列数相同,否则它不会显示在 sheet 中。那么,有没有一种绑定类型会根据我给它的数据动态增长呢?还是只需要释放当前的绑定,根据HTTP响应数据的大小重新绑定?

只要您使用 "shared" (Office 2013) API,就会遇到此问题。

但是,在特定于主机的 (2016+) API 中,您可以通过调整范围大小以满足您的需要来轻松解决问题。或者更准确地说,获取绑定,然后询问其范围,然后只获取第一个(左上角)单元格,然后调整它的大小:

    await Excel.run(async (context) => {
        let values = [
            ["", "Price"],
            ["Apple", 0.99],
            ["Orange", 1.59],
        ];

        let firstCell = context.workbook.bindings.getItem("TestBinding").getRange().getCell(0, 0);
        let fullRange = firstCell.getResizedRange(
            values.length - 1, values[0].length - 1);
        fullRange.values = values;

        await context.sync();
    });

您可以在新的 Script Lab (https://aka.ms/getscriptlab). Simply install the Script Lab add-in (free), then choose "Import" in the navigation menu, and use the following GIST URL: https://gist.github.com/Zlatkovsky/5a2fc743bc9c8556d3eb3234e287d7f3. See more info about importing snippets to Script Lab.

中单击五下即可实时试用此代码段