Select2(バージョン3.5.1)を使用するアプリで作業しています。このドロップダウン/オートコンプリートフィールドを設定するHTMLは次のようになります。
<input id="mySelect" class="form-control" type="hidden">
form-control
このスニペットのクラスは、Bootstrapからのものです。以下を使用して、JavaScriptからこのフィールドを初期化します。
function getItemFormat(item) {
var format = '<div>' + item.ItemName + '</div>';
return format;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 5,
placeholder: 'Search for an item',
allowClear: true,
ajax: {
url: '/api/getItems',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data, id: 'ItemId', text: 'ItemText' };
}
},
formatResult: getItemFormat,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
});
選択フィールドがロードされると、正常にレンダリングされます。少なくとも5文字目を入力すると、サーバーからアイテムが正常にプルされ、オプションとしてリストされます。ただし、それらのいずれかを選択しようとしても、何も起こりません。ドロップダウンポップアップは開いたままです。実際のフィールドには何も入れられません。 JavaScriptコンソールにエラーはありません。何もクリックしなかったようです。
さらに、アイテムの上にマウスを置いたり、矢印キーでオプションのリストをナビゲートしようとしても、何も強調表示されないことに気付きました。
何が間違っていますか?
デフォルトでは、_ajax.results
_で返すオブジェクトのresults
は、この構造体_[{id:1,text:"a"},{id:2,text:"b"}, ...]
_の配列でなければなりません。
_ results: function (data, page) {
var array = data.results; //depends on your JSON
return { results: array };
}
_
Select2.js では、実際に次のように述べています:
_* @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2.
* The expected format is an object containing the following keys:
* results array of objects that will be used as choices
* more (optional) boolean indicating whether there are more results available
* Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
_
ソースコードを読むと、_ajax.results
_がAJAX success:で呼び出されていることがわかります。
_ success: function (data) {
// TODO - replace query.page with query so users have access to term, page, etc.
// added query as third paramter to keep backwards compatibility
var results = options.results(data, query.page, query);
query.callback(results);
}
_
したがって、_ajax.results
_は、データが_[{id:a,text:"a"},{id:b,text:"b"}, ...]
_に渡される前に、データを適切な構造(たとえば_query.callback
_)にフォーマットするための単なる関数です。
_ callback: this.bind(function (data) {
// ignore a response if the select2 has been closed before it was received
if (!self.opened()) return;
self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
self.postprocessResults(data, false, false);
if (data.more===true) {
more.detach().appendTo(results).html(self.opts.escapeMarkup(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)));
window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
} else {
more.remove();
}
self.positionDropdown();
self.resultsPage = page;
self.context = data.context;
this.opts.element.trigger({ type: "select2-loaded", items: data });
})});
_
そして_query.callback
_が最終的に行うことは、アイテムの1つを選択して_.selectChoice
_をトリガーしたときにすべてが正常に動作するようにロジックを適切に設定することです。
_selectChoice: function (choice) {
var selected = this.container.find(".select2-search-choice-focus");
if (selected.length && choice && choice[0] == selected[0]) {
} else {
if (selected.length) {
this.opts.element.trigger("choice-deselected", selected);
}
selected.removeClass("select2-search-choice-focus");
if (choice && choice.length) {
this.close();
choice.addClass("select2-search-choice-focus");
this.opts.element.trigger("choice-selected", choice);
}
}
}
_
したがって、_.select2-search-choice-focus
_が呼び出される前にクラス_.selectChoice
_がDOM要素に追加されない原因となる何らかの構成ミス(たとえば、results
が正しい構造にない)がある場合、これが起こります:
ドロップダウンポップアップは開いたままです。実際のフィールドには何も入れられません。 JavaScriptコンソールにエラーはありません。何もクリックしなかったようです。
これには多くの解決策があります。それらの1つは、もちろん、_ajax.results
_で配列キーを操作することです。
_ results: function (data, page) {
//data = { results:[{ItemId:1,ItemText:"a"},{ItemId:2,ItemText:"b"}] };
var array = data.results;
var i = 0;
while(i < array.length){
array[i]["id"] = array[i]['ItemId'];
array[i]["text"] = array[i]['ItemText'];
delete array[i]["ItemId"];
delete array[i]["ItemText"];
i++;
}
return { results: array };
}
_
しかし、あなたは尋ねるかもしれません:なぜidは配列の "id"であり、テキストは "text"でなければならないのですか?
_[{id:1,text:"a"},{id:2,text:"b"}]
_
代わりに、配列をこの構造にすることはできますか?
_[{ItemId:1,ItemText:"a"},{ItemId:2,ItemText:"b"}]
_
答えはイエスです。 id
およびtext
関数を独自の関数で上書きするだけです。
これは、 Select2.js の_.selecte2
_の元の関数です。
_ id: function (e) { return e == undefined ? null : e.id; },
text: function (e) {
if (e && this.data && this.data.text) {
if ($.isFunction(this.data.text)) {
return this.data.text(e);
} else {
return e[this.data.text];
}
} else {
return e.text;
}
},
_
それらを上書きするには、_.selecte2
_に渡すオブジェクト内に独自の関数を追加するだけです。
_$('#mySelect').select2({
id: function (item) { return item.ItemId },
text: function (item) { return item.ItemText }
......
});
_
ただし、リストを閉じた後、選択したアイテムのテキストはフィールドに表示されません。
これは、_.selectChoice
_が正常に実行されたことを意味します。現在、問題は_.updateSelection
_にあります。ソースコード内:
_ updateSelection: function (data) {
var container=this.selection.find(".select2-chosen"), formatted, cssClass;
this.selection.data("select2-data", data);
container.empty();
if (data !== null) {
formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
}
if (formatted !== undefined) {
container.append(formatted);
}
cssClass=this.opts.formatSelectionCssClass(data, container);
if (cssClass !== undefined) {
container.addClass(cssClass);
}
this.selection.removeClass("select2-default");
if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
this.container.addClass("select2-allowclear");
}
}
_
ここから、対応するテキスト文字列が入力に配置される前に、formatSelection
を呼び出すことがわかります。
_formatSelection: function (data, container, escapeMarkup) {
return data ? escapeMarkup(this.text(data)) : undefined;
},
_
以前は、this.text(data)
をパラメーターにtext: funcion(item){ ... }
を含めることで上書きできると思っていましたが、残念ながらそのようには動作しません。
したがって、フィールドでテキストを適切にレンダリングするには、次のようにしてformatSelection
を上書きする必要があります。
_$('#mySelect').select2({
id: function (item) { return item.ItemId },
formatSelection: function (item) { return item.ItemText }
//......
});
_
text
を上書きしようとする代わりに(これはおそらく同じ効果を持つはずですが、この上書き方法はライブラリでまだサポート/実装されていません)
_$('#mySelect').select2({
id: function (item) { return item.ItemId },
text: function (item) { return item.ItemText } //this will not work.
//......
});
_
あなたが直面している問題は、select2
は、すべての結果にid
プロパティを持たせます。そうでない場合は、各結果からIDを返すid
関数で初期化する必要があります。
これらのいずれかを満たさない限り、結果を選択することはできません。あなたの例の場合:
function getItemFormat(item) {
var format = '<div>' + item.ItemName + '</div>';
return format;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 5,
placeholder: 'Search for an item',
allowClear: true,
id: function(item) { return item.ItemId; }, /* <-- ADDED FUNCTION */
ajax: {
url: '/api/getItems',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data, id: 'ItemId', text: 'ItemText' };
}
},
formatResult: getItemFormat,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
});
@itsmejodieが言ったように、APIから返されるIDを提供する必要があります。もう1つの問題は、select2
formatResult
およびformatSelection
関数を提供する必要があることです。Ajaxから読み込んだ後、html
を追加することはできません。例えば。:
function format (item) {
return item.name;
}
$(function() {
$('#mySelect').select2({
minimumInputLength: 2,
placeholder: 'Search for an item',
allowClear: true,
ajax: {
url: '/api/getItems',
dataType: 'jsonp',
quietMillis: 250,
data: function (term, page) {
return {
query: term
};
},
results: function (data, page) {
return { results: data };
}
},
formatResult: format,
formatSelection: format
});
});