コンボボックスをスーパー便利にしてくれる素晴らしいjQueryプラグイン、Select2。
使っている人も多いと思います。
本日4.0系がリリースされたので早速、移行してみました。
リリースノートでは「できるだけ互換性は維持した」とありますが、オプションを一切指定しないような使い方をしていない限り、おそらくそのままでは動かないと思います。
少なくとも僕は、まともに動くようになるまでそれなりに修正が必要でした。
以下、自分の対応内容をメモっときます。
オプションの一覧について
ドキュメントには、指定可能なオプションに関する完全な記述が無い模様。(※パッと見)
ソースを読んだほうが早いです。
http://github.com/select2/select2/blob/master/src/js/select2/defaults.js
当該箇所を抜粋したものが以下。
this.defaults = { amdBase: './', amdLanguageBase: './i18n/', closeOnSelect: true, debug: false, dropdownAutoWidth: false, escapeMarkup: Utils.escapeMarkup, language: EnglishTranslation, matcher: matcher, minimumInputLength: 0, maximumInputLength: 0, maximumSelectionLength: 0, minimumResultsForSearch: 0, selectOnClose: false, sorter: function (data) { return data; }, templateResult: function (result) { return result.text; }, templateSelection: function (selection) { return selection.text; }, theme: 'default', width: 'resolve' }; };
見てわかると思いますが、オプション名が結構変更されています。
formatResult→templateResult
formatResultはtemplateResultという名前に変更されました。
メソッドの仕様は同じなので変更不要。
formatSearching、formatNoMatches→オプション指定不可
formatSearching、formatNoMatchesはオプション指定できなくなりました。
ではどうするかというと、以下のように強引にデフォルト値を書き換えます。
// 元はformatNoMatchesだったもの $.fn.select2.defaults.defaults.language.noResults = function() { return '一致するものがありません'; }; // 元はformatSeachingだったもの $.fn.select2.defaults.defaults.language.searching = function() { return '検索中...'; };
あるいは、手抜きせずきちんとやるなら次の通り。
var jpLang = { errorLoading: function() { return '内容を取得できません'; }, inputTooLong: function(args) { var overChars = args.input.length - args.maximum; return '入力が ' + overChars + ' 文字超過しています'; }, inputTooShort: function(args) { var remainingChars = args.minimum - args.input.length; return '入力が ' + remainingChars + ' 文字不足しています'; }, loadingMore: function() { return '更に読み込んでいます...'; }, maximumSelected: function(args) { return '一度に選択できるのは ' + args.maximum + ' つまでです'; }, noResults: function() { return '一致するものがありません'; }, searching: function() { return '検索中...'; } }; var select2Opts = { ... language: jpLang }; $select.select2(select2Opts);
ところで、理由は調べてませんが
$.fn.select2.defaults.set('language', jpLang);
のようにデフォルト値にセットしても動かないのでご注意を。
選択解除時にコンボボックスがオープンされる振る舞いを解除
選択解除(コンボボックス右側の×マークを押す操作)した時にコンボボックスがオープンされてしまうようです。
ウザったいので、以下のようにして強引に阻止します。
$select.on('select2:unselecting', function(e) { // イベントをキャンセル e.preventDefault(); // 手動で選択解除する $select.val('').change(); });
.select2-choice→.select2-selection (※ただし厳密には違う)
選択済みoption要素には.select2-choice
ではなく.select2-selection
というクラスが付くようになりました。
しかし厳密には同じではなく、選択解除ボタンの"×"のテキストも含まれてしまいます。
ちなみにselect2-4.0系ではアイコン画像が廃止されました。
要するにこういうことです。
// select2-3.0系 $(".foo .select2-choice").text() === "あいう" // select2-4.0系 $(".foo .select2-selection").text() === "×あいう"
Seleniumでテストを書いていたりするとコレは致命的です。
assertEquals($(".foo .select2-selection").text(), "あいう")
のようなコードが全て失敗するようになるからです。
とりあえずの回避策としては
$.fn.select2.defaults.set('templateSelection', function(result) { return $("<span class='select2-choice'/>").text(result.text); });
のように、下位互換性のあるHTMLが生成されるようにすればよいかと。
matcherのインタフェースが変更
元は次のようなインタフェースでしたが、
/** * @param {!string} term 検索文字列 * @param {!string} label option要素の内容 * @param {!jQuery} option要素(jQuery型) * @return {!boolean} マッチしたか否か */ function(term, label, $option) { ... }
select2-4.0系ではこのようになりました。
/** * @typedef { * term:(string|undefined) * } */ SelectionParams; /** * @typedef { * text:!string, * title:!string, * selected:!boolean, * disabled:!boolean, * element:!HTMLOptionElement * } */ SelectionData; /** * @param {!SelectionParams} params 検索条件 * @param {!SelectionData} data 検索対象および結果 * @return {?SelectionData} 検索結果(マッチしたならdata, しないならnullを返す) */ function(params, data) { ... }
手っ取り早く対応するには、
function matcherAdapter(matcher) { return function(params, data) { return matcher( params.term || '', data.text, $(data.element)) ? data : null; }; }
のようなアダプタをかませばよいかと。