要怎麽简单快速地做出客制化地文件?今天,我们会教用 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。如果不想错过可以订阅按赞小铃铛(?),也欢迎留言跟我说你还想知道什麽做法/主题。我们明天见。
要把那些技术混合在一起,才能达到我们的目标呢? 符号式操作 (Symbolic Operation)...
在开发Vue专案时,时常会使用binding的技巧,用以动态变更参数的值, 如下 <div c...
今年春天重版出来的《尼尔:人工生命 ver.1.22474487139...》第二代《尼尔:自动人形...
组件 可重复使用的实例,有自己的名子,引入後当元素使用。 Data 透过 return 定义为函数 ...
上次学的Spinner需要点选下拉钮,才显示项目 而ListView则是直接把所有项目列出来 两者的...