12.08.2017

Visualforce with Vue.js(ES5)

普段、Vue.jsはTypeScriptで単一ファイルコンポーネントで実装し それをwebpackに通してビルドして、とゴリゴリ書いていたのですが、 jQueryで書かれている既存ソースに導入する機会があったのでメモしたいと思います。

1. オブジェクトの準備

今回は、サンプルデータとしてコンビニエンスストアのデータを使用します(今後、このデータを使ってGoogle Maps APIの紹介するかも)。

1.1. カスタムオブジェクトの作成

コンビニ名、位置名、経緯度項目を持ったオブジェクトconvenience_stores__cを作成します。 オブジェクトマネージャ例

1.2. データ準備

東京都コンビニエンスストアの緯度経度データ

上記サイト内にあるtokyo2.csvを使用します。 データローダで投入出来る形に修正してから1.1.で作成したオブジェクトに流し込みます。 サンプルデータ

2. Vue.jsのアップロード

GitHubからVue.jsをダウンロードし静的リソースにアップロードします。

3. ページの作成

下記のVisualforce ページを作成します。

convenience_stores.page

<apex:page>

  <apex:remoteObjects>
    <apex:remoteObjectModel
      name="convenience_stores__c"
      jsShorthand="ConvenienceStores"
      fields="location_name__c, Name, point__Latitude__s, point__Longitude__s" />
  </apex:remoteObjects>


  <div id="app" xmlns:v-bind="/" xmlns:v-on="/">
    <input v-if="is_show_load_button" type="button" value="Load convenience stores" v-on:click="ClickLoadConvenienceStores" />
    <div v-for="cs_ in convenience_stores">
      <input type="button" v-bind:value="cs_.name" v-on:click="ClickConvenienceStore(cs_)" />
    </div>
  </div>


  <script src="{!URLFOR($Resource.Vue_js_2_5_9, '/vue-2.5.9/dist/vue.min.js')}"></script>


  <script>
    new Vue({
      el: '#app',
      data: {
        is_show_load_button: false,
        convenience_stores: []
      },
      mounted: function() {
        var t = this;
        setTimeout(function() {
          t.is_show_load_button = true;
        }, 1000);
      },
      methods: {
        ClickLoadConvenienceStores: function() {
          var t = this;
          new SObjectModel.ConvenienceStores().retrieve({ limit: 100 }, function(error_, records_) {
            if (error_ != null) {
              alert(error_.message);
              return;
            }

            records_.forEach(function(r_) {
              t.convenience_stores.push({ name: r_.get('Name'), location_name: r_.get('location_name__c') });
            });
          });

          this.is_show_load_button = false;
        },
        ClickConvenienceStore: function(convenience_store_) {
          alert(convenience_store_.location_name);
        }
      }
    });
  </script>

</apex:page>

remoteObjects

オブジェクトからのデータの取得方法はいろいろあると思いますが、 今回はクラスを使用せずremoteObjectsタグを使用してデータを取得しています。

Vue.js

Vueはelで指定した要素に適用されます。

dataにはDOM要素でバインドする変数を用意します。 バインドする際はv-bind:で記述します。 v-if v-forでは記述する必要はありません。

mountedはVueのライフサイクルの一つです(DOM読み込み後に呼ばれる)。

methodsには、DOMから呼び出すメソッドを定義します。 DOMからメソッドを呼ぶ際は、v-on:で記述します。

Vue.jsをVisualforceで使用する際の注意

v-on: v-bind:をVisualforce上で記述しようとすると下記のエラーになるので、 親要素の何処かでxmlns:を定義してください。

Error Parsing /apex/convenience_stores: Error Traced[line: 9] The prefix "v-on" for attribute "v-on:click" associated with an element type "input" is not bound.

スクリーンキャプチャ(/apex/convenience_storesにアクセス)

動作例

次はTypeScriptとwebpackを用いた開発方法について書けたら書きます。