チュートリアル:カスタムウィジェットをビルドする

  • リリースバージョン: Australia
  • 更新日 2026年03月12日
  • 所要時間:22分
  • このチュートリアルに従って、 サービスカタログ アイテムを表示するカスタムウィジェットをビルドします。このチュートリアルをモデルとして使用すると、 サービスポータル の高度なスクリプティング能力を理解するのに役立ちます。

    このチュートリアルでは、クイック注文ウィジェットを作成します。このウィジェットでは、次のことを行います。
    • 検索の前に人気のあるアイテムをユーザーに表示します。
    • サービスカタログを照会し、利用可能なオプションをユーザーに表示します。
    • SC カタログアイテムウィジェットが埋め込まれており、ユーザーはクイック注文ウィジェット内でアイテムを表示および注文できます。
    • Angular プロバイダーを使用して、クエリーされた各アイテムの横にカテゴリアイコンを表示します。

    ウィジェットの作成とテンプレートの設定

    サービスカタログ内のアイテムをクエリするためのクイック注文ウィジェットを作成します。

    始める前に

    必要なロール:admin または sp_admin

    手順

    1. 移動先 すべて > サービスポータル > サービスポータル構成 をクリックし、[ ウィジェットエディター] をクリックします。
    2. [新規ウィジェットの作成] をクリックします。
    3. 次の値を定義します。
      • ウィジェット名:クイック注文
      • ウィジェット ID:quick_order
      • テストページの作成:アクティブ
      • ページ ID:quick_order

      テストページにウィジェットを追加すると、次の各テーブルにレコードが作成されます。

      • sp_page
      • sp_container
      • sp_row
      • sp_column
      • sp_instance
      • sp_widget
      注:
      サービスポータル設定のページエディターを使用して、テストページ上の要素の階層を表示できます。
    4. [送信] をクリックします。
    5. ウィジェットエディターから、クイック注文ウィジェットを開きます。
    6. 次の簡易テンプレートを HTML フィールドに追加します。
      <div class="panel panel-primary">
       <div class="panel-heading">Request an item from the catalog</div>
       <div class="panel-body">
         My catalog results
       </div>
      </div>
      
    7. [保存] をクリックします。
    8. 次の URL を使用して、新しいタブで <yourInstanceUrl>/sp?id=quick_order を使用してテストページをプレビューします。

      ウィジェットテンプレートがテストページに表示されます。

      ページ上のウィジェットレンダリング

    インスタンステーブル クエリするためのサーバースクリプトの追加

    ウィジェットを追加して基本テンプレートを作成したら、ユーザーがインスタンステーブルからデータをクエリできるようにする高度なクライアントおよびサーバースクリプトを定義できます。データベースからデータを照会し、そのデータをユーザーに表示し、更新をサーバーに送り返すことで、クライアントとサーバーの間でデータモデルを渡すことができます。

    始める前に

    必要なロール:admin または sp_admin

    手順

    1. ウィジェットエディターから、クイック注文ウィジェットを開きます。
    2. [ サーバースクリプト ] を選択して、サーバースクリプトフィールドを開きます。
    3. デフォルトのサーバースクリプトを次のカスタムスクリプトに置き換えます。
      (function() {
      	if (input.keywords != null && input.keywords != '')
      		data.items = getCatalogItems(input.keywords);
      	
      	function getCatalogItems(keywords) {
      		var sc = new GlideRecord('sc_cat_item');
      		sc.addActiveQuery();
      		sc.addQuery('123TEXTQUERY321', keywords);
      		sc.addQuery('sys_class_name', 'NOT IN', 'sc_cat_item_wizard,sc_cat_item_content');
      		sc.addQuery('sc_catalogs', 'e0d08b13c3330100c8b837659bba8fb4');
      		sc.setLimit(100);
      		sc.orderByDesc("ir_query_score");
      		sc.query();
      		var results = [];
      		while (sc.next()) {
      			if (!$sp.canReadRecord(sc))
      				continue;
      
      			var item = {};
      			$sp.getRecordDisplayValues(item, sc, 'name,price,sys_id');
      			item.category = sc.getValue('category');
      			results.push(item);
      		}
      		return results;
      	}
      })();
      

      このスクリプトは、123TEXTQUERY321 クエリメソッドを使用してsc_cat_itemテーブルでキーワード検索を実行します。

    4. HTML テンプレートを次のスクリプトに置き換えます。
      <div class="panel panel-primary">
       <div class="panel-heading">Request an item from the catalog</div>
       <div class="panel-body">
         <input class="form-control" type="search" placeholder="Start typing here to search the list of catalog items" ng-model="c.data.keywords" ng-change="c.server.update()" ng-model-options="{debounce: 250}" />
         <ul class="list-group result-container">
           <li class="list-group-item" ng-repeat="item in c.data.items">
             <a href>{{item.name}}</a><span class="pull-right">{{item.price}}</span>
           </li>
         </ul>
       </div>
      </div>
      

      このテンプレートは検索フィールドを追加し、次の Angular ディレクティブを使用してサーバースクリプトで実行されたクエリの結果を表示します。これらのディレクティブの詳細については、「 Angular API リファレンス」を参照してください。

      表 : 1. テンプレートで使用される角度ディレクティブ
      角度ディレクティブ 説明
      ng-model モデル変数 c.data.keywords に対する値の変更を自動的に読み書きします。
      ng-model-options ng モデルの動作を構成します。このテンプレートでは、ユーザーが入力を 250 ミリ秒停止した後に ng-model がモデルを更新します。
      ng-change モデル値の変更後に c.server.update() を実行します。この関数は、データオブジェクトをサーバースクリプトに投稿します。スクリプトが実行されると、データオブジェクトはサーバーで生成されたデータオブジェクトの新しい値で自動的に更新されます。
      ng-repeat 親要素と子要素からテンプレートを作成します。c.data.items 内の各アイテムについて、テンプレートのインスタンスが作成され、式 {{item.name}}{{item.price}} が各アイテムの値に置き換えられます。
    5. 次のスクリプトを [CSS - SCSS] フィールドに追加します。
      .result-container {
       margin-top: 10px;
      }
      
    6. テストページのプレビューを更新して変更を表示します。

      検索ボックスに入力すると、一致するカタログアイテムが表示されます。ipadを検索してみてください。

      検索すると iPad 向けの結果が表示されます。

    ウィジェットの空ステータスの管理

    検索用語を入力する前に、人気のあるアイテムのリストをユーザーに表示します。

    始める前に

    必要なロール:admin または sp_admin

    このタスクについて

    ウィジェットの初期化時に検索が実行されていないため、サーバー 入力 変数は未定義です。この空の状態は、ユーザーが最初にウィジェットを操作したときに混乱を招く可能性があります。この問題を解決するには、 入力 変数が空のときにウィジェットに表示する内容を指定します。この初期データは、ユーザーが最初にウィジェットを操作する際のガイドとなります。

    手順

    1. ウィジェットエディターから、クイック注文ウィジェットを開きます。
    2. 既存のサーバースクリプトを次のスクリプトに置き換えます。
      (function() {
          if (input.keywords != null && input.keywords != '')
              data.items = getCatalogItems(input.keywords);
          else data.items = getPopularItems();
      
          function getCatalogItems(keywords) {
              var sc = new GlideRecord('sc_cat_item');
              sc.addActiveQuery();
              sc.addQuery('123TEXTQUERY321', keywords);
              sc.addQuery('sys_class_name', 'NOT IN', 'sc_cat_item_wizard,sc_cat_item_content');
              sc.addQuery('sc_catalogs', 'e0d08b13c3330100c8b837659bba8fb4');
              sc.setLimit(100);
              sc.orderByDesc("ir_query_score");
              sc.query();
              var results = [];
              while (sc.next()) {
                  if (!$sp.canReadRecord(sc))
                      continue;
      
                  var item = {};
                  $sp.getRecordDisplayValues(item, sc, 'name,price,sys_id');
                  item.category = sc.getValue('category');
                  results.push(item);
              }
              return results;
          }
      
          function getPopularItems() {
              var items = [];
              var count = new GlideAggregate('sc_req_item');
              count.addAggregate('COUNT', 'cat_item');
              count.groupBy('cat_item');
              count.addQuery('cat_item.sys_class_name', 'NOT IN', 'sc_cat_item_guide,sc_cat_item_wizard,sc_cat_item_content');
              count.addQuery('cat_item.sc_catalogs', 'e0d08b13c3330100c8b837659bba8fb4');
              count.orderByAggregate('COUNT', 'cat_item');
              count.query();
              while (count.next() && items.length < 9) {
                  if (!$sp.canReadRecord("sc_cat_item", count.cat_item.sys_id.getDisplayValue()))
                      continue; // user does not have permission to see this item
      
                  var item = {};
                  item.name = count.cat_item.name.getDisplayValue();
                  item.category = count.cat_item.category.toString();
                  item.price = count.cat_item.price.getDisplayValue();
                  item.sys_id = count.cat_item.sys_id.getDisplayValue();
                  items.push(item);
              }
              return items;
          }
      })();

      このスクリプトでは、データベースを照会し、入力変数が空の場合に人気のあるアイテムを返す新しい関数 getPopularItems() が導入されています。

    3. HTML テンプレートを次のスクリプトに置き換えます。
      <div class="panel panel-primary">
        <div class="panel-heading">Request an item from the catalog</div>
        <div class="panel-body">
          <input class="form-control" type="search" placeholder="Start typing here to search the list of catalog items" ng-model="c.data.keywords" ng-change="c.server.update()" ng-model-options="{debounce: 250}" />
          <h5 ng-if="!c.data.keywords">Showing the most popular items</h5>
          <ul class="list-group result-container">
            <li class="list-group-item" ng-repeat="item in c.data.items">
              <a href>{{item.name}}</a><span class="pull-right">{{item.price}}</span>
            </li>
          </ul>
        </div>
        <div class="panel-footer" ng-if="c.data.keywords">
          <ng-pluralize count="c.data.items.length"
                       when="{'0': 'No items found for ',
                           '1': 'One item matching ',
                           'other': 'Found {} items matching '}">
          </ng-pluralize>
          {{c.data.keywords}}
        </div>
      </div>
      

      このスクリプトは、サーバースクリプトから返された人気のあるアイテムを表示するテンプレートを提供します。

    4. テストページのプレビューを更新して変更を表示します。

      ウィジェットでは、検索入力の前に人気のあるアイテムをユーザーに表示します。

      「カタログアイテムのリストを検索するには、ここから入力を開始します (Start typing here to search the list of catalog items)」というテキストを含む検索ボックス。

    既存のウィジェットの埋め込み

    SC カタログアイテムウィジェットを埋め込むことで、ユーザーがクイック注文ウィジェットで サービスカタログ アイテムを表示および購入できるようにします。

    始める前に

    必要なロール:admin または sp_admin

    このタスクについて

    コードを複製する代わりに、ウィジェットを埋め込んで既存の機能を活用できます。SC カタログアイテムウィジェットは、ユーザーが サービスカタログ アイテムを表示および購入できるようにするベースシステムウィジェットです。

    手順

    1. SC カタログアイテムウィジェットを調べます。
      SC カタログアイテムウィジェットを埋め込む前に、ウィジェットを調べて、アクセスする必要があるデータを把握します。正しいデータが埋め込みウィジェットに渡されるように、クイック注文ウィジェットのクライアントまたはサーバースクリプトを更新する必要がある場合があります。
      1. <yourInstanceURL>/sp_config?id=widget_editor に移動します。
      2. SC カタログアイテムウィジェットを開きます。
      3. ウィジェット ID は widget-sc-cat-item であることに注意してください。
        この ID を使用して、ウィジェットモデルをクライアントスクリプトに埋め込みます。
      4. サーバースクリプトを調べます。

        データオブジェクトには、input オブジェクトまたはオプションオブジェクトのいずれかによって設定される sys_id プロパティが含まれていることに注意してください。入力オプションにもsys_idが含まれていない場合、$sp.getParameter() メソッドは要求クエリ文字列からsys_idを取得します。

        If Else ステートメントを使用してsys_idを取得するサンプルサーバースクリプト。

        入力オブジェクトを入力するには、クイック注文ウィジェットクライアントスクリプトからカタログアイテムsys_id渡します。

    2. ウィジェットエディターから、クイック注文ウィジェットを開きます。
    3. クイック注文ウィジェットのクライアントスクリプトを次のスクリプトに置き換えます。
      function($location, spUtil) {
          var c = this;
      
          c.select = function(item_id) {
              if (c.openItem == item_id) {
                  c.openItem = null;
                  return;
              }
      
              renderCatalogItemWidget(item_id);
          }
      
          function renderCatalogItemWidget(item_id) {
              c.catalogItemWidget = null;
              spUtil.get("widget-sc-cat-item", {
                  sys_id: item_id
              }).then(function(response) {
                  c.catalogItemWidget = response;
                  c.openItem = item_id;
              });
          }
      }

      このスクリプトは spUtil.get() を使用してウィジェットモデルを ID (widget-sc-cat-item) で取得し、 {sys_id: item_id} オブジェクトを定義します。このオブジェクトは、サーバースクリプトに 入力として投稿します。

    4. HTML テンプレートを次のスクリプトに置き換えます。
      <div class="panel panel-primary">
        <div class="panel-heading">Request an item from the catalog</div>
        <div class="panel-body">
          <input class="form-control" type="search" placeholder="Start typing here to search the list of catalog items" ng-model="c.data.keywords" ng-change="c.server.update()" ng-model-options="{debounce: 250}" />
          <h5 ng-if="!c.data.keywords">Showing the most popular items</h5>
          <ul class="list-group result-container">
            <li class="list-group-item" ng-repeat="item in c.data.items">
              <a href ng-click="c.select(item.sys_id)">{{item.name}}</a><span class="pull-right">{{item.price}}</span>
              <div class="catalog-item" ng-if="item.sys_id == c.openItem">
                  <sp-widget ng-if="c.catalogItemWidget" widget="c.catalogItemWidget" />
              </div>
            </li>
          </ul>
        </div>
        <div class="panel-footer" ng-if="c.data.keywords">
          <ng-pluralize count="c.data.items.length"
                       when="{'0': 'No items found for ',
                           '1': 'One item matching ',
                           'other': 'Found {} items matching '}">
          </ng-pluralize>
          {{c.data.keywords}}
        </div>
      </div>

      このテンプレート:

      • ng-click ディレクティブを使用してクリック時の動作を追加します。
      • sp-widget ディレクティブを使用して埋め込み SC カタログアイテムウィジェットを表示します。
    5. CSS を次のスクリプトに置き換えます。
      .result-container {
        margin-top: 10px;
      }
      
      .catalog-item {
        background-color: #f5f5f5;
        padding: 10px;
        @include border-top-radius($panel-border-radius);
        @include border-bottom-radius($panel-border-radius);
      }
      
    6. テストページのプレビューを更新して変更を表示します。

      検索結果を選択すると、埋め込みの SC カタログアイテムウィジェットでアイテムが開きます。

      埋め込みウィジェットに表示されている選択したアイテムを示すテストページ。

    再利用可能なディレクティブを作成してウィジェットに追加する

    Angular プロバイダーは、複数のウィジェットに追加できる再利用可能なコンポーネントです。[ウィジェット角度プロバイダー] テーブルを使用して、[クイックオーダー] ウィジェットの各結果の横にカテゴリアイコンを表示するディレクティブを作成します。

    始める前に

    必要なロール:admin または sp_admin

    このタスクについて

    Angular プロバイダーを使用すると、クライアントスクリプトコントローラーに挿入できる Angular ディレクティブとサービスを構築できます。プロバイダーのコードは、特定のモジュールに追加されることなく匿名である必要があるため、一般的な Angular ディレクティブやサービスとは異なります。

    手順

    1. 移動先 すべて > サービスポータル > サービスポータル構成 > ポータルテーブル > ウィジェット Angular プロバイダー.
      [ウィジェット Angular プロバイダー] テーブルが開きます。
    2. [新規] を選択して、新しいレコードを作成します。
    3. フォームに記入します。
      1. タイプと名前を追加します。
        • タイプ:ディレクティブ
        • 名前:categoryIcon
      2. クライアントスクリプトを追加します。
        function() {
            return {
                template: '<span class="fa fa-stack fa-lg"><i class="fa fa-circle fa-stack-2x"></i><i class="fa fa-{{::icon}} fa-stack-1x fa-inverse"></i></span>',
                restrict: 'E',
                replace: true,
                scope: {
                    category: '='
                },
                link: function(scope, element) {
        
                    var _iconMap = {
                        "b06546f23731300054b6a3549dbe5dd8": "tablet",
                        /* Tablets */
                        "15706fc0a0a0aa7007fc21e1ab70c2f": "question",
                        /* Can we help you? */
                        "d68eb4d637b1300054b6a3549dbe5db2": "mobile-phone",
                        /* Mobiles */
                        "109cdff8c6112276003b17991a09ad65": "print",
                        /* Office and Print */
                        "5d643c6a3771300054b6a3549dbe5db0": "print",
                        /* Printers */
                        "2c0b59874f7b4200086eeed18110c71f": "plug",
                        /* Peripherals */
                        "2809952237b1300054b6a3549dbe5dd4": "desktop", 
                        /* Software */
                    };
        
                    scope.icon = _iconMap[scope.category] || "shopping-cart";
                }
            }
        }

        このスクリプトは、カテゴリレコードのsys_idを サービスカタログ アイテムに関連付けます。表示されるアイコンは、 サービスカタログのカテゴリレコードで定義されたアイコンです。

      3. [Save (保存)] を選択します。
    4. 新しい Angular ディレクティブをクイック注文ウィジェットに関連付けます。
      1. 移動先 すべて > サービスポータル > ウィジェット.
      2. クイック注文ウィジェットを開きます。
      3. [関連リスト] で、[Angular プロバイダー] を選択します。
      4. [Angular プロバイダー] リストで [ 編集] を選択し、categoryIcon Angular プロバイダーをクイック注文ウィジェットに関連付けます。
      5. [Save (保存)] を選択します。
    5. クイック注文 HTML テンプレートに categoryIcon ディレクティブを追加します。
      1. ウィジェットエディターから、クイック注文ウィジェットを開きます。
      2. HTML テンプレートを次のスクリプトに置き換えます。
        <div class="panel panel-primary">
          <div class="panel-heading">Request an item from the catalog</div>
          <div class="panel-body">
            <input class="form-control" type="search" placeholder="Start typing here to search the list of catalog items" ng-model="c.data.keywords" ng-change="c.server.update()" ng-model-options="{debounce: 250}" />
            <h5 ng-if="!c.data.keywords">Showing the most popular items</h5>
            <ul class="list-group result-container">
              <li class="list-group-item" ng-repeat="item in c.data.items">
                <a href ng-click="c.select(item.sys_id)"><category-icon category="item.category" style="margin-right: 10px"></category-icon>{{item.name}}</a><span class="pull-right">{{item.price}}</span>
                <div class="catalog-item" ng-if="item.sys_id == c.openItem">
                    <sp-widget ng-if="c.catalogItemWidget" widget="c.catalogItemWidget" />
                  </div>
              </li>
            </ul>
          </div>
          <div class="panel-footer" ng-if="c.data.keywords">
            <ng-pluralize count="c.data.items.length"
                         when="{'0': 'No items found for ',
                             '1': 'One item matching ',
                             'other': 'Found {} items matching '}">
            </ng-pluralize>
            {{c.data.keywords}}
          </div>
        </div>
        
    6. テストページのプレビューを更新して変更を表示します。

      各結果の横にカテゴリアイコンが表示されます。