今天來完成第二個目標
廢話不多說,開始動作囉~
筆者的習慣會先把畫面先寫一版,再調整 JS 的部分
首先,先調整 action_view.xml
,這裡算是大調整了
<!-- ironman_js/static/src/xml/action_view.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t t-name="IronmanActionView">
<t t-call="todoList">
<t t-set="items" t-value="widget.todoList || []" />
</t>
</t>
<t t-name="todoList">
<table>
<tbody>
<t t-if="items.length">
<tr t-foreach="items" t-as="item">
<td>
<input type="checkbox"
class="finished"
t-att-checked="item.finished ? 'checked' : undefined"
t-att-data-index="item_index"
/>
</td>
<td t-esc="item.name" t-att-data-index="item_index"/>
<td>
<i class="fa fa-times" t-att-data-index="item_index"/>
</td>
</tr>
</t>
<tr t-else="">
<td colspan="3">
<span class="alert alert-success">無任何的待辦事項</span>
</td>
</tr>
</tbody>
</table>
</t>
</templates>
接著調整 JS,等等會解釋一下寫模板要注意的地方
// ironman_js/static/src/js/action_view.js
// ...
const IronmanActionView = AbstractAction.extend({
template: 'IronmanActionView',
willStart: async function () {
let def = this._super(...arguments);
let dataPromise = this._rpc({
model: 'todo.list',
method: 'get_self_todo_list',
args: [[]],
});
let [defReturn, data] = await Promise.all([def, dataPromise]);
this.todoList = data || [];
return defReturn;
},
});
// ...
調整好後直接重新整理網頁就能看到結果了
補充一下: 這裡的資料是在昨天建立的 tree view 增加的,如果各位發現沒有資料,可以先到 tree view 增加後回來看 action view 就會有了
各位應該有注意到有把 todoList
另外拆一個模板
而在原本的 IronmanActionView
可以使用 t-call
來呼叫模板
呼叫模板時,內部可以先預設一些變數,所以可以注意到筆者有定義一行變數 items
<t t-set="items" t-value="widget.todoList || []" />
而很多剛接觸的人可能會想說應該可以直接 t-value="todoList"
來取得 widget 的屬性
但在這裡 Qweb
模板系統的 this
並不是指向 widget
還是很混亂嗎?
來,我們來看一下模板執行時情況
先在剛剛的 t-if
前增加一個 t-log
,內容隨便,主要是要能快速跳到 source 裡
...
<tbody>
<t t-log="123"/>
<t t-if="items.length">
...
改好後,重新整理畫面,觀察 console
頁面
在跳出的訊息右邊有個程式碼的定位,點一下就能跳過去剛剛定義的 t-log
接著在 console.log(123)
前面點一下來下斷點
下完斷點後在從選單重新進入一次 action view
停在斷點後,應該有發現定義的 t-if
也被解析出來
變成 if(dict['items'].length)
,而 items
是去找 dict
這個物件
所以往右看 scope
,展開 dict
,裡面的內容代表是在模板內可以取得
可以發現 widget
則是指向 action view 的 class
這樣各位應該能清楚為什麼要取用 widget 屬性時,需要使用 widget.
來處理了