--- title: 在 MultiSelectDialog 中設定預設 Filter --- ## 在 MultiSelectDialog 中預設 Filter ![](https://i.imgur.com/cb08axt.png) 在上圖的情境中,點選右上角的「從...獲取項目」後,會出現途中的 Dialog,由於客戶要求在 Dialog 中可以有預設的 Filter,這在 Frappe 的 Dialog 物件中有類似的 function 能用,但 ERPNext 在產生這個 Dialog 時([utils.js #L705](https://github.com/frappe/erpnext/blob/version-13/erpnext/public/js/utils.js#L705)),雖然 map_current_doc 有回傳 Dialog 的物件,不過在[purchase_invoice.js #L109](https://github.com/frappe/erpnext/blob/version-13/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js#L109)中,並沒有變數去接這個物件,因此為了達成這個功能,就需要稍微修改一下 map_current_doc 才能夠達成。 #### Step.1 透過 Form Event 掛載自定義的 JS [Frappe Form Event](https://frappeframework.com/docs/v13/user/en/api/form) 新增一個 JS 檔,設定 Listen 「Purchase Invoice」(這邊能換成任何一個 Module,此部分以 Purchase Invoice 為例),以及一個 onload 事件。 ```javascript= frappe.ui.form.on("Purchase Invoice", { onload: function(frm){ // do Something } }) ``` #### Step.2 覆寫 map_current_doc 因為主要目的是要存取到 map_current_doc 所回傳的 dialog 物件,因此將 map_current_doc 的原始碼貼過來後,只需要在建立 Dialog 後,將 Dialog 存在 frappe 這個全域變數中。(Frappe 建立的專案基本上都會有這個全域變數) ```javascript= // ... let d = new frappe.ui.form.MultiSelectDialog({ ... }); // 將 dialog 物件存取到全域變數中 frappe.mulit_seleect_dialge = d; // ... ``` #### Step.3 Listen Bootstrap Modal Frappe 的 Dialog 是基於 Bootstrap 的 Modal 建立的,因此需要 Listen Bootstrap Modal 的 ```shown.bs.modal ``` 事件,才能在使用者開啟 Dialog 後,執行我們要做的事情。 ```javascript= $("body").on("shown.bs.modal", function(e){ // do Something // do Step.4 }) ``` #### Step.4 預設 Filter 由於 JS 非同步的特性,在新增 filter 時,可能會出現 filter 還沒產生完,但是 JS 已經在執行後續的 Code 的情況,因此為了確保流程一定會等到 filter 都產生完,才執行後續的程式,所以這邊需要使用 Async/Await 的方式去處理。 ```javascript= function step1(){ return new Promise((resolve) => { frappe.mulit_seleect_dialge.filter_group.add_filter(frappe.mulit_seleect_dialge.doctype, field, condition, filter_value, false); resolve(); }) } async function step2(){ await step1(); } step2().then((v) => { frappe.mulit_seleect_dialge.filter_group.on_change(); }) ``` 該流程會先執行 step2,而 step2 則會等待 step1 的 Promise 被 resolve,在 step1 中,會使用到 Step.3 中所存放的 frappe.mulit_seleect_dialge,在這個 Dialog 物件下的 filter_group 中,有一個 method 叫 add_filter,透過這個方式,傳入 doctype / 欄位名稱 / 條件 / 值 後,便可以新增一個 filter。 當 filter 新增完成之後,就會 resolve 當前的 promise,接著 step2 便會繼續往下執行,執行完畢後便會呼叫 on_change() 事件去更新 Dialog 中的資料了。 延伸參考:[MultiSelectDialog Bug](/0LhTApfiRq-zly6pE9NsFw)