select2 is a jquery plug-in that is an upgraded version of the normal form select component.
Search can be customized, Remote data sets (the main introduction point in this article), infinite scrolling (data paging is great), and many high-end parameter settings (next introduction if needed).
There are 40 built-in international languages, but here we only need to use Chinese.
It supports both modern and traditional browser built-in, even the unpleasant IE8.
So, now let's start a fantastic trip to select2!
1. Amazing results, let's see them
Local Actual Result
2. Import css and js to website
1. Use CDN to save traffic on your website
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
2. Download the file locally and make some customizations (such as modifying the prompt)
<!-- select2 -->
<link rel="stylesheet" type="text/css" href="${ctx}/common/select2/css/select2.css" />
<script type="text/javascript" src="${ctx}/common/select2/js/select2.full.js"></script>
<!-- Chinese internationalization also requires parameter settings -->
<script type="text/javascript" src="${ctx}/common/select2/js/i18n/zh-CN.js"></script>
3. Real knives, real guns, get dry
Step 1, Customize Page Personalization Elements
<select name="parentid" class="js-data-example-ajax" href="${ctx}/member/loadMembersInfo.do?uid=${mem.uid}" style="width:400px" inputMessage="Please enter a member number(Partially Matchable)">
<option selected="selected" value="666">Silent King Two</option>
</select>
- The Java side obtains the value of select through the name property.
- Set class to js-data-example-ajax to initialize select2 on page load.
- The href property provides a background retrieved URL for ajax.
- style sets the width of the component.
- The inputMessage attribute customizes the personalized prompt. The default English version is Please enter 1 or more characters, and the Chinese internationalization is "Please enter at least one more character." Neither of them meets the personalized requirements, so it needs to be changed. This is described later.
- Provide a default option that will be displayed before the page is retrieved.
Step 2, select2 componentization, detailed comments
<script type="text/javascript">
$(function() {
$("select.js-data-example-ajax").each(
function() {
var $this = $(this);
$this.select2({
language : "zh-CN",// Specify Chinese as the language for internationalization to take effect
inputMessage : $this.attr("inputMessage"),// Add Default Parameters
ajax : {
url : $this.attr("href"),
dataType : 'json',
delay : 250,// Delayed display
data : function(params) {
return {
username : params.term, // The content entered in the search box and the parameter passed to the Java backend is username
page : params.page,// Page number, page breaks
rows : 10// How many rows are displayed per page
};
},
// paging
processResults : function(data, params) {
params.page = params.page || 1;
return {
results : data.data,// Background returned datasets
pagination : {
more : params.page < data.total// Total number of pages is 10, so 1-9 pages can be refreshed drop-down
}
};
},
cache : false
},
escapeMarkup : function(markup) {
return markup;
}, // let our custom formatter work
minimumInputLength : 1,// Enter at least one character to start retrieval
templateResult : function(repo) {// The format of the result set displayed, where you need to write your own css style, can refer to demo
// Retrieving
if (repo.loading)
return repo.text;
var markup = repo.username;
markup += repo.realname;
var markup = "<div class='select2-result-repository clearfix'>" + "<div class='select2-result-repository__avatar'><img src='"
+ repo.headimgUrl + "' /></div>" + "<div class='select2-result-repository__meta'>"
+ "<div class='select2-result-repository__title'>" + repo.username + "</div>";
if (repo.realname) {
markup += "<div class='select2-result-repository__description'>" + repo.realname + "</div>";
}
markup += "<div class='select2-result-repository__statistics'>"
+ "<div class='select2-result-repository__forks'><i class='fa fa-user'></i> Number of subordinate members" + repo.children_count + " </div>"
+ "</div>" + "</div></div>";
return markup;
},
templateSelection : function(repo) {
return repo.realname || repo.text;
}// The content that appears in the text box when an item is selected in the list
});
});
});
</script>
Step 3, Receiving parameters and returning a result set on the Java side, is important, not to mention.
@RequestMapping(value = "loadMembersInfo")
public void loadMembersInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {
Integer uid = StrUtil.parseStringToInt(request.getParameter("uid"));
Members mem = this.memberService.selectByPrimaryKey(uid);
// Paging parameter conversion, needs to match foreground select2, below the code
BaseConditionVO vo = getBaseConditionVOForTable(request);
vo.addParams("username", StrUtil.getUTF8String(request.getParameter("username")));
vo.addParams("uid", uid);
// Encapsulate the result set and match the foreground select2.
PageGrid page = createPageGrid(this.membersMapper.getPromoterList(vo, vo.createRowBounds()), vo,
this.membersMapper.searchPromoterTotalCount(vo));
// Write to response in json format
out(page, response);
}
Next, paste out the key source code, which may not match your project, but it can be used for reference.
BaseConditionVO.java
public class BaseConditionVO {
public final static int PAGE_SHOW_COUNT = 50;
private int pageNum = 1;
private int numPerPage = 0;
private int totalCount = 0;
private String orderField;
private String orderDirection;
/**
* @Fields ps : Encapsulate parameter types.
*/
private Map<String, Object> mo = new HashMap<String, Object>();
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getNumPerPage() {
return numPerPage > 0 ? numPerPage : PAGE_SHOW_COUNT;
}
public void setNumPerPage(int numPerPage) {
this.numPerPage = numPerPage;
}
public String getOrderField() {
return orderField;
}
public void setOrderField(String orderField) {
this.orderField = orderField;
}
public String getOrderDirection() {
return "desc".equals(orderDirection) ? "desc" : "asc";
}
public void setOrderDirection(String orderDirection) {
this.orderDirection = orderDirection;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getStartIndex() {
int pageNum = this.getPageNum() > 0 ? this.getPageNum() - 1 : 0;
return pageNum * this.getNumPerPage();
}
public RowBounds createRowBounds() {
RowBounds ro = new RowBounds(this.getStartIndex(), this.getNumPerPage());
return ro;
}
/**
* @Title: addParams
* @Description: Add Query Criteria
* @param key
* @param value
*/
public void addParams(String key, Object value) {
this.getMo().put(key, value);
}
/**
* @Title: getParams
* @Description: Get Query Conditions
* @param key
* @return
*/
public Object getParams(String key) {
return this.getMo().get(key);
}
/**
* @return the mo
*/
public Map<String, Object> getMo() {
return mo;
}
/**
* @param mo
* the mo to set
*/
public void setMo(Map<String, Object> mo) {
this.mo = mo;
}
}
Paging and Java-side paging parameters match for selec2
protected BaseConditionVO getBaseConditionVOForTable(HttpServletRequest req) {
BaseConditionVO vo = new BaseConditionVO();
// Current Page
int currentPage = StrUtil.parseStringToInt(req.getParameter("page"));
// How many rows are displayed on a page
int sizes = StrUtil.parseStringToInt(req.getParameter("rows"));
// sort
String sortOrder = StrUtil.getString(req.getParameter("sord"));
String sortCol = StrUtil.getString(req.getParameter("sidx"));
vo.setNumPerPage(sizes);
vo.setPageNum(currentPage);
vo.setOrderField(sortCol);
vo.setOrderDirection(sortOrder);
return vo;
}
Data Encapsulation from Java to select2
@XStreamAlias("pageGrid")
@SuppressWarnings("rawtypes")
public class PageGrid {
private int page;
// Total number of pages, matching processResults.pagination of select2
private int total;
private int records;
// Data Result Set, matching processResults.results of select2
private List data;
public int getPage() {
return this.page;
}
public void setPage(int page) {
this.page = page;
}
public int getTotal() {
return this.total;
}
public void setTotal(int total) {
this.total = total;
}
public int getRecords() {
return this.records;
}
public void setRecords(int records) {
this.records = records;
}
public List getData() {
return this.data;
}
public void setData(List data) {
this.data = data;
}
}
mysql acquired data source and PageGrid transformed to match
protected PageGrid createPageGrid(List list, BaseConditionVO vo, int searchTotalCount) {
PageGrid pageGrid = new PageGrid();
// data
pageGrid.setData(list);
// Current Page
pageGrid.setPage(vo.getPageNum());
// Total number
pageGrid.setRecords(list.size());
// PageCount
int total = 0;
if (pageGrid.getRecords() != 0) {
total = searchTotalCount % vo.getNumPerPage() == 0 ? searchTotalCount / vo.getNumPerPage()
: searchTotalCount / vo.getNumPerPage() + 1;
}
pageGrid.setTotal(total);
return pageGrid;
}
Mybatis paging is very simple. As long as createRowBounds is set, mybatis will automatically paginate for you, which is great.
List getPromoterList(BaseConditionVO vo, RowBounds createRowBounds);
The key point here is that you must return the ID (m.uid as id) to select2.
<select id="getPromoterList" resultType="hashmap" parameterType="map">
select
m.uid as id,
convert(m.username,char) username,
m.realname,
m.children_count,
m.headimgUrl
from
members m
where m.deleteflag=0
<if test="mo.username != ''">and m.username like CONCAT('%', '${mo.username}', '%')</if>
<choose>
<when test="orderField !=null and orderField !=''">
ORDER BY ${orderField}
<if test="orderDirection != null and orderDirection != ''">${orderDirection}</if>
</when>
<otherwise>
order by m.username DESC
</otherwise>
</choose>
</select>
Did you not see mysql's paging limit? Well, there's nothing to focus on here. That's what the framework does for us.
Total
int searchPromoterTotalCount(BaseConditionVO vo);
count(0) is fine
<select id="searchPromoterTotalCount" resultType="java.lang.Integer" parameterType="map">
select count(0) as a
from
members m
where m.deleteflag=0
<if test="mo.username != ''">and m.username like CONCAT('%', '${mo.username}', '%')</if>
</select>
out output to response
protected void out(Object result, HttpServletResponse response) throws IOException {
ServletOutputStream out = response.getOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(out, result);
out.flush();
}
At this point, the remote function of select2 is completely pasted out in the code section.
However, I would like to conclude by highlighting a few points:
1. Paging parameters Java side and select2 must be compared.
2. The returned data must pass an id back, otherwise the returned list cannot be selected, why?You can find out by investigating the source of select2.
Results.prototype.option = function (data) {
var option = document.createElement('li');
option.className = 'select2-results__option';
var attrs = {
'role': 'treeitem',
'aria-selected': 'false'
};
if (data.disabled) {
delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
// If the id is empty, the aria-selected is deleted, and aria-selected is exactly the key property for the list selection.
// This is a pit. It can only be said that the api given by select2 does not say this at all. I will go!!!!!!
if (data.id == null) {
delete attrs['aria-selected'];
}
......
}
3. How does the form get the value of select2?The answer is, 1. Return result set must have id, 2.input tag must have name attribute.
4. How do I customize inputMessage?
Find the following code in select2.js, note the comments section
S2.define('select2/data/minimumInputLength',[
], function () {
function MinimumInputLength (decorated, $e, options) {
this.minimumInputLength = options.get('minimumInputLength');
// inputMessage
this.inputMessage = options.get('inputMessage');
decorated.call(this, $e, options);
}
MinimumInputLength.prototype.query = function (decorated, params, callback) {
params.term = params.term || '';
if (params.term.length < this.minimumInputLength) {
this.trigger('results:message', {
message: 'inputTooShort',
args: {
minimum: this.minimumInputLength,
input: params.term,
inputMessage : this.inputMessage, // inputMessage, passed to i18n
params: params
}
});
return;
}
decorated.call(this, params, callback);
};
return MinimumInputLength;
});
Add upper inputMessage to defaults in select2.js
this.defaults = {
...
minimumInputLength: 0,
inputMessage: '',
maximumInputLength: 0,
...
};
Then modify the inputTooShort method in the zh-CN.js file
inputTooShort : function(e) {
if (e.inputMessage) {
return e.inputMessage;// Add inputMessage
} else {
var t = e.minimum - e.input.length, n = "Please re-enter at least" + t + "Characters";
return n
}
},
It's really time to end up here.
Welcome to my public number and give your soul a moment of peace!
WeChat sweeps the two-dimensional code below to focus on the silent king two public numbers: