今天一同僚問我這個問題:S/4HANA Fiori應用裡的清單,一旦Scroll到底部就會自動向背景發起新的請求把更多的資料讀取到前台顯示。
以Product Master這個應用為例,我點選搜尋之後,結果區域顯示目前系統一共有140個product,但是隻有前25個傳回并顯示在浏覽器裡。

這個分頁效果是UI5 OData的參數實作的:$skip=0&top=25。
而總數140,是通過參數$inlinecount實作,其原理和ABAP Open SQL的SELECT COUNT(*)類似。
從Chrome開發者工具能觀察到頭25個product的payload:
當将清單滾動至底部時,第二批共25個product從背景讀取出來,顯示在前台:
這個http請求的參數:$skip=25&top=25,用于讀取從第25個到第50個product。
從調用棧能清楚發現是scroll這個事件觸發的第二批product的讀取動作。
然後再去GrowingEnablement.requestNewPage這一個調用棧,發現一個屬性_iLimit維護了一個開始索引,每次scroll到底部的事件觸發之後,該屬性值都會被GrowingThreshold累加。 因為API this._oControl.getGrowingThreshold每次傳回的是一個常量25, 是以_iLimit的值每次scroll到底部之後看起來是這樣的:25,50,75,100 … 這些值會被用來作為HTTP請求參數$skip的值傳到背景:
我同僚的問題:growingThreshold在檔案sap.m.ListBase.js裡被寫死成20, 但是運作時在何處被改寫成了25?
要回答這個問題,需要了解一些UI5 Smart Template的知識,因為例子裡這個Product Master的Fiori應用,也是基于Smart Template開發的。可以參考我的部落格My understanding about how object page in Smart Template is rendered 來了解其工作原理。
當Product Master這個應用的UI Component被加載并馬上開始渲染時,需要先加載Smart Template的庫檔案:
在我部落格My understanding about how object page in Smart Template is rendered 提到,ListReport.view.xml這個檔案裡有若幹view fragment的聲明,每個聲明指向了一些其他的Smart Template庫檔案。
這些庫檔案一覽:
在Chrome開發者工具檢視從ABAP背景加載的庫檔案SmartTable.fragment.xml,能發現屬性growingThreshold在此處被寫死成25。
當SmartTable.fragment.xml被加載之後其内容會被解析, growingThreshold值為25,會通過控件的setter API寫入到控件屬性裡。這樣接下來在處理清單的scroll事件是,25這個值就會通過控件的getter API傳回并累加到_iLimit上。
關于XML view從ABAP背景加載到浏覽器後是如何被解析并生成對應的UI5控件,可以參考我的部落格Why my formatter does not work? A trouble shooting example to know how it works
也許您按照我上面描述的步驟操作,但是無法觸發斷點。原因是因為UI5架構針對基于Smart Template開發的Fiori應用的XML view設計了一套緩存機制。當待渲染的XML view已經在緩存中存在時,不會去ABAP背景加載Smart Template的庫檔案, 而是直接執行第428行的IF分支。
通過調試我們可以發現緩存是通過IndexedDB加上LRU(Least recently used)算法實作的。
通過Chrome開發者工具可以觀察到待渲染的view已經有記錄存儲在IndexedDB裡了:
如果想觀察Smart Template庫檔案的加載,需點選"Delete database"以手動清除緩存。
緩存清除完畢後,即可觀察到期望中的Smart Template庫檔案加載。
這篇文章介紹了如何通過調試找到同僚提出問題的答案。我把它加在了我UI5調試文章分享的合集裡:My UI5 debugging tips and experience collection - how to resolve UI5 issues through debugging by yourself