要怎麼簡單快速地做出客製化地文件?今天,我們會教用 GAS 搭配 Goolge Doc。那因為在 Google Slide 中的 Element 也是相同的,所以這邊就會講細一點,之後就可以一起飲用。換句話說,今天會教說怎麼透過 GAS 調整 Google Doc 和 Google Slide 裡面的元素。那今天的問題可以有以下的排列組合——
雖然總共有 4x4 共 16 種的排列組合,我們會用案例一個個來說明。基本上昨天講了講新增與讀取,今天會專注於刪除,就讓我們開始吧!
請問下圖的問號裡,可以填入什麼?
再來問大家兩題是非題,提示:getNumChildren()
可以幫助取得接下來一層有的物件。
答案在今天的文章當中!
考慮到有些夥伴不一定會都看過前面的文章,就撈叨一點把基本步驟再次附上,如果會的夥伴可以直接跳到 Q1。
我們已經知道大致上,每一個 Google 文件都會有 Element (元件),且每一個 Element 都會有 Attribute (屬性)。今天我們主要會介紹藍色的 Element 的部分。
那我們把 Element 展開來看,裡面有很多小的物件,這邊抓出其中最常用的四種。分別是段落、照片、表格與清單。
那我們的目標就是透過讀取、寫入、更新與刪除(對的,參照 CRUD 的 format)來帶大家讓是怎麼操作這些表格。這邊就節錄一本書中的「段落、照片、表格與清單」,來作為今天我們的範例。
那在開始前,先來個重要的概念——
我們確實可以透過 getImages()
、getTables()
來取得幾個比較重要的物件們。當我們想進入更細節的物件取得時,像是細節到 Table 的哪一格時,就會需要知道他們之間的親子關係,或是說上下層關係。
這邊我們要介紹一個觀念叫 Parent()
和 Children()
,基本上我們可以透過 getParent()
和 getChildren()
來取得上下層關係的物件。
但,唯獨 Document
的物件例外,當我們用 let doc = DocumentApp.getActiveDocument();
取得 doc 物件時,它既沒有上層的 parent(用 getParent()
會得到 null),更沒辦法直接取得 children()(沒有 getChildren()
的方式)。
簡單來說,就是你想看到 Document 下層。需要明明白白地指派是要 Header、Body 還是 Footer。
那另外一間值得注意的事是, Child_index
會是每個物件就會算一次。所以當我們看這位在第一頁的三個表單時,他會出現的 ChildIndex 並不是 1, 2, 3。那會是什麼呢?
而是 1, 4, 7,為什麼呢?因為在我們表單的前面有著「換行」剛剛有提到,「每個物件就算一次」,那當然就包括段落(Paragraph),而昨天我們有提到,空白段落(換行)也是一個 Object。
而更重要的是,我們說 parent
和 child
可以幫我們來取得有上下層關係的物件。那 Table 下面也有下層的 TableRow, TableRow 則還有更下層的 TableCell。
好,那到目前為止的概念,應該是能夠幫你回答最前面那兩題的。這邊也公布參考答案——
那 Parent 和 Child 的概念很重要,因為回到我們的目的,當我們要「部分」刪除或更新時,它就會派上用場。也附上這段檢查用的程式碼——
function readChild(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let tables = doc_body.getTables();
for (let i=0;i<tables.length;i++){
Logger.log(doc_body.getChildIndex(tables[i]))
Logger.log(tables[i].getNumChildren())
Logger.log(tables[i].getChild(0).getChild(0))
}
}
好,理解這邊的概念後,再來進入實作囉!
那這次我們不會用 Google Sheet,而是直接用 Google Doc 進入。
一樣第一次會有存取驗證需要大家按一下。這邊仍是借用一下 D2 的影片。
getBody()
我們先用 getActiveDocument()
抓出正在綁定的文件;那假設我們都是針對主要內文(Body)的部分,所以我們先設定好 getbody()
。
let doc_body = DocumentApp.getActiveDocument().getBody();
完整的架構概念,可以參考 Google 的官方文件。
因為更新有比較複雜的細節,我們就先來講講刪除。
刪除之前基本上要先取得,所以先讓我們取得表格。這邊我加入一些假表格。
接著,我們要讀取表格,並進行刪除。
然後接下來要先用昨天的 read
來進行讀取。
function readTables(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let tables = doc_body.getTables();
for (let i=0;i<tables.length;i++){
Logger.log(tables[i].getText())
}
}
來確認一下跑起來如何——
好,看來有抓到範圍。
clear()
刪除整張表單如果要將整個文件全部刪除,程式碼很簡單——
function clearDoc(){
let doc_body = DocumentApp.getActiveDocument().getBody();
doc_body.clear();
}
跑起來長這樣——
如果是要銜接 Step 3,將表格刪除,那要怎麼做?我們來示範只刪掉後面兩個。因為 Tables 回傳會是三個 Table 的 Objects,理論上 Tables 是長這樣 [Table obj 1, Table obj 2, Table obj 3]
,而因為是 Array 的形式,我們要取的條件是 table[i] 中 i > 0 的情況。。
function deleteTables(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let tables = doc_body.getTables();
for (let i=0;i<tables.length;i++){
if(i > 0){
tables[i].clear()
}
}
}
跑起來長這樣——
好,那這就是刪除整個表格的做法。但如果有的時候,我們只是要針對部分內容進行刪除,又要怎麼做?這邊就要用我們最一開始的 Children 的概念了。
假設我想刪掉第一列,那該怎麼辦?我們有提到,因為 table 下面是以 tableRow 作為下層物件,我們可以直接用 table.getChild
來進行刪除。而因為 Table Row 之間不會有其他空白段落,所以可以直接指派特定的那列。
舉例來說,我想將全部表格的「第ㄧ列」刪除。
function deleteSecondRow(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let tables = doc_body.getTables();
for (let i=0;i<tables.length;i++){
tables[i].getChild(0).clear()
}
}
跑起來長這樣——
要注意的是,我對 tables[i]
的 getChild(index)
中的 index
輸入的是 0,因為這邊不是 Google Sheet,要回程式語言的以 0 為基準點。
那如果,我想將右下角的 Cell 刪除呢?
function deleteBottomRightCell(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let tables = doc_body.getTables();
for (let i=0;i<tables.length;i++){
tables[i].getChild(1).getChild(1).clear();
}
}
跑起來長這樣——
值得注意的是,現在 Google Doc 不支援非長方形的表格了,所以用 Clear() 只會清除到裡面的值。換句話說,如果今天你不想刪掉列,而是列裡面的特定值的話,可以寫成——
function deleteRowValue(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let tables = doc_body.getTables();
for (let i=0;i<tables.length;i++){
for (let j=0;j<tables.getChild(0).getNumChildren;i++){
tables[i].getChild(1).getChild(j).clear();
}
}
好,那如果今天我想要將第二直欄的表格刪掉,該怎麼辦?以目前 Google Docs 的架構,我們會需要創造另外一個表單,這另外找時間寫。那因為表單是最複雜的,其他相對清單、照片與段落,基本上都是透過 Clear() 就可以刪除,瞭解完表單後,理論上其他的實作就不會那麼難。
好,那今天就到這邊。
好,那今天我們主要交代了 Parent/Child 和如何刪除,篇幅關係,更新我們留到明天分享;如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。