Làm mới dữ liệu được truy xuất bởi một chức năng tùy chỉnh trong Google Trang tính


92

Tôi đã viết một Tập lệnh Google Apps tùy chỉnh sẽ nhận idvà tìm nạp thông tin từ một dịch vụ web (một mức giá).

Tôi sử dụng tập lệnh này trong một bảng tính và nó hoạt động tốt. Vấn đề của tôi là những giá này thay đổi và bảng tính của tôi không được cập nhật.

Làm cách nào để tôi có thể buộc nó chạy lại tập lệnh và cập nhật các ô (mà không cần chuyển qua từng ô theo cách thủ công)?


1
Vâng, đây là một lời giải thích tôi đã làm về vấn đề này: stackoverflow.com/questions/9022984/...
Henrique G. Abreu

Tôi đọc lời giải thích của bạn như một phần của nghiên cứu của tôi. Rất hữu ích, cảm ơn. Tôi đã thêm liên kết vào câu trả lời của mình.
tbkn23

Đối với những người gặp phải hành vi tương tự (được xác định và logic, nhưng đôi khi không may), có thể hữu ích khi phản đối yêu cầu tính năng này trong Trình theo dõi vấn đề của Google: Issuetracker.google.com/issues/36763858 .
Timothy Johns

Đây là một câu trả lời đơn giản tôi đã làm.
Aerials

Câu trả lời:


92

Ok, có vẻ như vấn đề của tôi là google hoạt động theo một cách kỳ lạ - nó không chạy lại tập lệnh miễn là các thông số tập lệnh tương tự nhau, nó sử dụng kết quả được lưu trong bộ nhớ cache từ các lần chạy trước. Do đó, nó không kết nối lại với API và không tìm nạp lại giá, nó chỉ trả về kết quả tập lệnh trước đó đã được lưu trong bộ nhớ cache.

Xem thêm thông tin tại đây: https://code.google.com/p/google-apps-script-issues/issues/detail?id=888

và đây: Tập lệnh tóm tắt dữ liệu không cập nhật

Giải pháp của tôi là thêm một tham số khác vào tập lệnh của tôi, mà tôi thậm chí không sử dụng. Bây giờ, khi bạn gọi hàm với một tham số khác với các lần gọi trước, nó sẽ phải chạy lại tập lệnh vì kết quả cho các tham số này sẽ không có trong bộ nhớ cache.

Vì vậy, bất cứ khi nào tôi gọi hàm, đối với tham số bổ sung, tôi chuyển "$ A $ 1". Tôi cũng đã tạo một mục menu có tên là refresh và khi tôi chạy nó, nó sẽ đặt ngày và giờ hiện tại ở A1, do đó tất cả các lệnh gọi tới tập lệnh có $ A $ 1 làm tham số thứ hai sẽ phải tính toán lại. Đây là một số mã từ tập lệnh của tôi:

function onOpen() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [{
    name : "Refresh",
    functionName : "refreshLastUpdate"
  }];
  sheet.addMenu("Refresh", entries);
};

function refreshLastUpdate() {
  SpreadsheetApp.getActiveSpreadsheet().getRange('A1').setValue(new Date().toTimeString());
}

function getPrice(itemId, datetime) {
  var headers =
      {
        "method" : "get",
        "contentType" : "application/json",
        headers : {'Cache-Control' : 'max-age=0'}
      };

  var jsonResponse = UrlFetchApp.fetch("http://someURL?item_id=" + itemId, headers);
  var jsonObj = eval( '(' + jsonResponse + ')' );
  return jsonObj.Price;
  SpreadsheetApp.flush();
}   

Và khi tôi muốn đặt giá của mặt hàng có ID 5 trong một ô, tôi sử dụng công thức sau:

=getPrice(5, $A$1)

Khi tôi muốn làm mới giá, tôi chỉ cần nhấp vào mục menu "Làm mới" -> "Làm mới". Hãy nhớ rằng bạn cần tải lại bảng tính sau khi thay đổi onOpen()tập lệnh.


4
tại sao không sử dụng now () làm tham số bổ sung?
Nâng cao

5
Bạn thấy đấy, giống như hàm của tôi sẽ không được đánh giá lại vì các tham số của nó không thay đổi (tức là giá trị của các ô), bây giờ () cũng sẽ không được đánh giá lại vì nó không có tham số, do đó giá trị trả về của nó sẽ không thay đổi và vì vậy các tham số của hàm của tôi sẽ không thay đổi. Ngoài ra, việc sử dụng now () sẽ khiến hàm của tôi đánh giá lại mọi lúc, hơi nặng khi nó tạo ra một số cuộc gọi HTTP ...
tbkn23

2
Tốt tìm thấy. Tôi đã gặp sự cố này khi sử dụng phạm vi được đặt tên làm đầu vào. Sử dụng câu trả lời của bạn, tôi nhận ra rằng nó thường đủ tốt để chuyển một tổng giả trên phạm vi đầu vào, như trong "sum (B: D)", trong đó các hàng BD nằm trong phạm vi được hàm tùy chỉnh tra cứu. Thay đổi bất kỳ ô nào sẽ kích hoạt tổng thay đổi và hàm tùy chỉnh để làm mới. Nhân tiện, có vẻ như hàm tùy chỉnh thậm chí không phải khai báo tham số bị bỏ qua.
Shawn Hoover

1
Thật tiếc rằng đây vẫn là giải pháp tốt nhất mà tôi tìm thấy cho vấn đề này. Thay vì Google chỉ cho phép chúng tôi tắt bộ nhớ cache cho các lệnh gọi hàm cụ thể, chúng tôi tự ý tăng những gì đang được lưu trữ trong bộ nhớ cache chỉ để đảm bảo rằng chúng tôi không nhận được giá trị được lưu trong bộ nhớ cache ... Tuy nhiên, cảm ơn bạn đã đăng bài,
GrayedFox

Hãy thử sử dụng một tham số cho chức năng tùy chỉnh của bạn như ví dụ này
Aerials

33

Tôi biết đây là một câu hỏi hơi cũ. Nhưng phương pháp này không yêu cầu bất kỳ hành động nào của người dùng ngoại trừ việc thực hiện thay đổi.

Những gì tôi đã làm tương tự như tbkn23.

Hàm tôi muốn đánh giá lại có thêm một tham số không được sử dụng, $ A $ 1. Vì vậy, lời gọi hàm là

=myFunction(firstParam, $A$1)

Nhưng trong mã chữ ký hàm là

function myFunction(firstParam)

Thay vì có chức năng Làm mới, tôi đã sử dụng hàm onEdit (e) như thế này

function onEdit(e)
{
   SpreadsheetApp.getActiveSheet().getRange('A1').setValue(Math.random());
}

Chức năng này được kích hoạt bất cứ khi nào bất kỳ ô nào trong bảng tính được chỉnh sửa. Vì vậy, bây giờ bạn chỉnh sửa một ô, một số ngẫu nhiên được đặt trong A1, điều này sẽ làm mới danh sách tham số như tbkn23 đã đề xuất, khiến cho hàm tùy chỉnh được đánh giá lại.


5
Hoạt động tuyệt vời. Nhược điểm là, lịch sử hoàn tác (ctrl + z) bị rối tung.
Jon

1
Đẹp trick với một nhược điểm gây phiền nhiễu như Jon chỉ ra ... Tôi hy vọng ai đó sẽ cải thiện nó :-)
Enissay

Cảnh báo nhỏ và lớn với câu trả lời này; trong trường hợp cực kỳ khó xảy ra Math.random trả về cùng một số, trong trường hợp đó, nó sẽ không cập nhật, vì số cụ thể đó đã được lưu vào bộ nhớ đệm.
Woody Payne

12

Điều này là rất muộn và tôi không biết nó sẽ hữu ích nhưng thực sự có cài đặt ở đây bạn có thể NOW()cập nhật tự động

nhập mô tả hình ảnh ở đây


1
NOW()là một chức năng tích hợp, không phải là một chức năng tùy chỉnh.
Rubén

@ Rubén Vấn đề là bạn có thể bao gồm NOW () chức năng trong bất kỳ chức năng tùy chỉnh bạn muốn có nó cập nhật
Thaina

13
Tại thời điểm này, các đối số của hàm tùy chỉnh phải là đối số xác định, nói cách khác, chúng không phân bổ NOW () làm đối số. Xem developer.google.com/apps-script/guides/sheets/functions
Rubén

3
Nó sẽ xảy ra lỗi nếu bạn cố gắng sử dụng NOW () bên trong một hàm tùy chỉnh
Stefano Giacone

6

Nếu hàm tùy chỉnh của bạn nằm trong một cột cụ thể, chỉ cần sắp xếp bảng tính của bạn theo cột đó.

Hành động sắp xếp buộc làm mới dữ liệu, hành động này sẽ gọi hàm tùy chỉnh của bạn cho tất cả các hàng của cột đó cùng một lúc.


1

Đây có thể là một chủ đề siêu cũ nhưng có thể hữu ích cho ai đó đang cố gắng làm điều này, như tôi vừa rồi.

Làm việc với tập lệnh của Lexi như hiện tại, nó dường như không hoạt động nữa với Trang tính hiện tại, nhưng nếu tôi thêm biến giả vào hàm của mình dưới dạng tham số (không cần thực sự sử dụng nó bên trong hàm), nó thực sự sẽ buộc Google trang tính phải làm mới lại trang.

Vì vậy, khai báo như: function myFunction (firstParam, dummy) và sau đó gọi nó sẽ như đã được đề xuất. Điều đó đã làm việc cho tôi.

Ngoài ra, nếu một biến ngẫu nhiên xuất hiện trên tất cả các trang tính mà bạn chỉnh sửa gây phiền toái, thì một giải pháp dễ dàng để giới hạn ở một trang tính như sau:

function onEdit(e)
{
  e.source.getSheetByName('THESHEETNAME').getRange('J1').setValue(Math.random());
}

1
@ Rubén nó rất giống nhưng với một sự phiền toái tốt; thay vì sử dụng các tấm tích cực nó sử dụng một tên sheet định nghĩa, nâng cao lịch sử của bạn
Jonas D.

1

Logic tập lệnh:

  • Các Hàm Tùy chỉnh không cập nhật trừ khi các đối số của nó thay đổi.
  • Tạo trình kích hoạt onChange để thay đổi tất cả các đối số của tất cả các hàm tùy chỉnh trong bảng tính bằng cách sử dụng textFinder

Đoạn trích:

/*@customfunction*/
function sheetNames(e) {
  return SpreadsheetApp.getActive()
    .getSheets()
    .map(function(sheet) {
      return sheet.getName();
    });
}

/*Create a installable trigger to listen to grid changes on the sheet*/
function onChange(e) {
  if (!/GRID/.test(e.changeType)) return; //Listen only to grid change
  SpreadsheetApp.getActive()
    .createTextFinder('=SHEETNAMES\\([^)]*\\)')
    .matchFormulaText(true)
    .matchCase(false)
    .useRegularExpression(true)
    .replaceAllWith(
      '=SHEETNAMES(' + (Math.floor(Math.random() * 500) + 1) + ')'
    );
}

Đọc:


1

Như đã lưu ý trước đó:

Các Hàm Tùy chỉnh không cập nhật trừ khi các đối số của nó thay đổi.

Giải pháp khả thi là tạo một hộp kiểm trong một ô và sử dụng ô này làm đối số cho hàm tùy chỉnh:

  1. Tạo hộp kiểm: chọn ô trống, ví dụ như [A1], đi tới [Chèn]> [Hộp kiểm]
  2. Đặt ô này làm đối số: =myFunction(A1)
  3. Nhấp vào hộp kiểm để làm mới công thức

-3

Nếu bạn đã viết một hàm tùy chỉnh và sử dụng nó trong bảng tính của mình dưới dạng công thức, thì mỗi lần bạn mở bảng tính hoặc bất kỳ ô tham chiếu nào được sửa đổi, công thức sẽ được tính toán lại.

Nếu bạn chỉ muốn nhìn chằm chằm vào bảng tính và muốn các giá trị của nó thay đổi, thì hãy xem xét thêm một trình kích hoạt định thời sẽ cập nhật các ô. Đọc thêm về trình kích hoạt tại đây


10
Điều đó sẽ rất tuyệt, ngoại trừ nó không hoạt động ... Tải lại trang không làm mới các giá trị. Hơn nữa, xóa ô và nhập lại lệnh gọi hàm tương tự, vẫn giữ giá trị cũ. Nếu tôi gọi chính xác cùng một hàm từ một ô khác, nó sẽ hiển thị giá trị mới, nhưng không hiển thị trong ô cũ.
tbkn23
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.