這裡介紹 Ext JS 架構中的 Controller 的使用方式。

在 MVC 架構中,Controller 是一個很重要的角色,以下是 Ext JS 的 Ext.app.Controller 使用教學。

建立基本 Controller

Controller 是 Ext JS 中連接各個應用程式組件的媒介,它主要的作用是傾聽事件(events)然後執行對應的動作,以下是 Controller 的建立方式:

Ext.define('MyApp.controller.Users', {
  extend: 'Ext.app.Controller',

  init: function() {
    console.log('Initialized Users! This happens before ' +
        'the Application launch() function is called');
  }
});

這裡的 init 函數會在應用程式的初始化階段被呼叫,他的呼叫時機是在 Applicationlaunch 之前,這可以讓程式設計者在 Viewport 建立之前,執行一些動作。

Controller 的 control 函數可以讓程式設計者很簡單的設定事件與 handler 函數的對應關係,例如:

Ext.define('MyApp.controller.Users', {
  extend: 'Ext.app.Controller',

  control: {
    'viewport > panel': {
      render: 'onPanelRendered'
    }
  }

  onPanelRendered: function() {
    console.log('The panel was rendered');
  }
});

這裡的 control 透過 ComponentQuery 的方式來指定頁面上的組件,它的用法有點像 CSS,以一個規則來指定頁面中所有匹配的組件。

init 函數中的 'viewport > panel' 代表在 Viewport 中所有直屬的 Panel 元件,而其所指定的物件中,列出了事件與 handler 的對應關係,亦即 render 事件對應 onPanelRendered 這個 handler,如此設定之後,只要是頁面中匹配的元件觸發了 render 事件,那麼 onPanelRendered 這個 handler 就會被直呼叫。

Event Domains

在 Ext JS 4.2 之後,引進了 event domains 的改念,在 MVC 的術語中,event domains 是指 Controller 會傾聽的事件所屬的基礎類別,除了繼承 Ext.Component 類別的 Views,Controller 還可以傾聽資料的 Stores、Ext.Direct Providers、其他的 Controllers 以及 Ext.GlobalEvents,這個特性可以讓應用程式中的不同組件很輕易地互相溝通,不需要互相綁定 Controllers,並且可以讓開者獨立測試不同的元件。

更詳細的說明,請參考 Controller 的 listen 說明文件

使用 refs

refs 系統是 Controllers 中一個很有用的功能,藉由 Ext.ComponentQuery 可以讓開發者很容易指定任何在頁面上的組件,下面是一個眼單的範例:

Ext.define('MyApp.controller.Users', {
  extend: 'Ext.app.Controller',

  refs: [{
    ref: 'list',
    selector: 'grid'
  }],

  control: {
    'button': {
      click: 'refreshGrid'
    }
  },

  refreshGrid: function() {
    this.getList().store.load();
  }
});

這個例子假設頁面中有一個 Grid,而這個 Grid 中包含一個按鈕,按下按鈕時會刷新裡面的資料,在 refs 陣列中指定了一個 grid 的參照,其中包含兩個部分:

selector
一個 ComponentQuery selector,用來指定頁面中的 grid 組件。
ref
將所有 grid 組件指定給 list 這個參照名稱。

在設定好參照名稱之後,我們可以獲得許多很有用的東西,第一個是 refreshGrid 函數中所使用的 getList 函數,這個函數是 Controller 以 ref 所指定的參照名稱所自動產生的,產生的規則是將名稱的第一個字母變為大寫,再加上 get 這個前贅字串。

getList 第一次被呼叫時,ComponentQuery selector 會執行匹配的動作,並且傳會第一個匹配成功的元件,在此之後,當 getList 再度被呼叫時,就會使用快取的方式直接傳回 grid 的參照。一般來說我們會建議使用比較特定性的 ComponentQuery selector,這樣比較可以確保傳回的參照對應到指定的組件。

整個程式串起來之後,就是設定一個 control 傾聽任何按鈕的 click 事件,在使用者按下按鈕時呼叫 refreshGrid 刷新資料。這裏的 button 同樣是不太好的 ComponentQuery selector,實際應用時要改成比較特定的 selector。

開發者可以定義任意個 refs,進而控制任何數量的組件,若想要看實際的範例,可以參考 SDK 中的 Feed Viewer 範例。

產生的 getter 方法

除了 refs 之外,還有其他方式也可以產生 getter 方法,Controllers 常常會需要處理 Models 與 Stores,所以 Ext JS 也提供了其他的方法,以下是一個範例:

Ext.define('MyApp.controller.Users', {
  extend: 'Ext.app.Controller',

  models: ['User'],
  stores: ['AllUsers', 'AdminUsers'],

  init: function() {
    var User, allUsers, ed;

    User = this.getUserModel();
    allUsers = this.getAllUsersStore();

    ed = new User({ name: 'Ed' });
    allUsers.add(ed);
  }
});

在指定了 Models 與 Stores 之後,Controller 會動態從對應的位置(以這個例子來說是 app/model/User.jsapp/store/AllUsers.jsapp/store/AdminUsers.js)載入它們,並且建立 getter 函數。這個例子會建立一個新的 User model 物件,然後放進 AllUsers Store,當然我們可以在這個函數中執行任何程式碼,這裡只是示範其使用方式而已。

參考資料:Ext.app.Controller