Angularjs implements select drop-down box instances with search and filtering functions, and angularjsselect
I. background
For the select drop-down list, such as the Country selection function, so many countries around the world, the scroll bar has been pulling much effort, eyes also need to stare, tired! So, in order to optimize the user experience, it is very necessary to bring the search function to the drop-down box. We all know that jquery has such a plug-in, but we use Angularjs. We also hope to solve this problem elegantly by Using Bidirectional binding and instructions.
Analysis:
Target |
Add a new select-search attribute to the original <select ng-options = ""> tag to support the search function. If this attribute does not work, it does not affect the original select function. |
Problem |
1. In the selectSearch command, How can I obtain the data source in ng-options and the specified value (value of the option label) and text (text in the option label) Field names. 2. How can I filter data? Indicates whether to display the matching items each time, hide the non-matching items or repeatedly match from the data source, and regenerate the node. |
Ideas |
1. Refer to the ng-options command provided by angular to obtain the data source, value, and text field name. In particular, only the normal format of ng-options = "obj. value as obj. text for obj in list" is supported, and those with groups are not supported at the moment. 2. regenerate the node. (Why is it so convenient !) |
II. Specific implementation
1. Code Section
1.1 js Code (introduce jquery first, or an error will be reported)
/*** Drop-down box with filtering function * usage <select ngc-select-search name = "select1" ng-options = ""> * description [select must have name, ng-options attribute] */. directive ('ngcselectsearch', function ($ animate, $ compile, $ parse) {function parseOptions (optionsExp, element, scope) {// regular var NG_OPTIONS_REGEXP =/^ \ s * ([\ s \ S] +?) in ngOptions ?) (?: \ S + as \ s + ([\ s \ S] + ?))? (?: \ S + group \ s + by \ s + ([\ s \ S] + ?))? (?: \ S + disable \ s + when \ s + ([\ s \ S] + ?))? \ S + for \ s + (? :( [\ $ \ W] [\ $ \ w] *) | (?: \ (\ S * ([\ $ \ w] [\ $ \ w] *) \ s *, \ s * ([\ $ \ w] [\ $ \ w] *) \ s *\))) \ s + in \ s + ([\ s \ S] + ?) (?: \ S + track \ s + by \ s + ([\ s \ S] + ?))? $/; Var match = optionsExp. match (NG_OPTIONS_REGEXP); if (! (Match) {console. log ('ng-options expression error')} var valueName = match [5] | match [7]; var keyName = match [6]; var displayFn = $ parse (match [2]); var keyFn = $ parse (match [1]); var valuesFn = $ parse (match [8]); var labelArray = [], idArray = [], optionValues = []; scope. $ watch (match [8], function (newValue, oldValue) {if (newValue & newValue. length> 0) {optionValues = valuesFn (scope) | []; labelArray = []; IdArray = [] for (var index = 0, l = optionValues. length; index <l; index ++) {var it = optionValues [index]; if (match [2] & match [1]) {var localIt = {}; localIt [valueName] = it; var label = displayFn (scope, localIt); var dataId = keyFn (scope, localIt); labelArray. push (label); idArray. push (dataId) ;}} scope. options = {'optionvalues': optionValues, 'labelarray': labelArray, 'idarray': idAr Ray }});} return {restrict: 'A', require: ['ngmodel'], priority: 100, replace: false, scope: true, template: '<div class = "chose-container">' + '<div class = "chose-single"> <span class = "j-view"> </span> <I class = "glyphicon-remove"> </I> </div> '+' <div class = "chose-drop chose-hide j-drop"> '+' <div class = "chose-search"> '+' <input class = "j-key" type = "text" autocomplete = "off"> '+' </div>' + '<Ul class = "chose-result">' + // '<li ng-repeat = "' + repeatTempl + '" data-id = "' + keyTempl + '" >{{ '+ valueTempl +' }}</li> '+' </ul> '+' </div> ', link: {pre: function selectSearchPreLink (scope, element, attr, ctrls) {var tmplNode = $ (this. template ). first (); var modelName = attr. ngModel, name = attr. name? Attr. name :( 'def '+ Date. now (); tmplNode. attr ('id', name + '_ chosecontianer'); $ animate. enter (tmplNode, element. parent (), element) ;}, post: function selectSearchPostLink (scope, element, attr, ctrls) {var choseNode = element. next (); // $ ('#' + attr. name + '_ chosecontianer'); choseNode. addClass (attr. class); element. addClass ('chose-hide '); // var ngModelCtrl = ctrls [0]; if (! NgModelCtrl |! Attr. name) return; parseOptions (attr. ngOptions, element, scope); var rs ={}; function setView () {var currentKey = ngModelCtrl. $ modelValue; if (isNaN (currentKey) |! CurrentKey) {currentKey = ''; choseNode. find ('. j-view: first '). text ('Please select'); choseNode. find ('I '). addClass ('chose-hide ');} if (currentKey + ''). length> 0) {for (var I = 0, l = rs. idArray. length; I <l; I ++) {if (rs. idArray [I] = currentKey) {choseNode. find ('. j-view: first '). text (rs. labelArray [I]); choseNode. find ('I '). removeClass ('chose-hide '); break ;}}} function setViewAndData () {if (! Scope. options) {return;} rs = scope. options; setView ();} scope. $ watchCollection ('options', setViewAndData); scope. $ watch (attr. ngModel, setView); function getListNodes (value) {var nodes = []; value = $. trim (value); for (var I = 0, l = rs. labelArray. length; I <l; I ++) {if (rs. labelArray [I]. indexOf (value)>-1) {nodes. push ($ ('<li> '). data ('id', rs. idArray [I]). text (rs. labelArray [I])} return n Odes;} choseNode. on ('keyup ','. j-key', function () {// search the input box keyup and filter the list var value =$ (this) again ). val (); choseNode. find ('ul: first '). empty (). append (getListNodes (value); return false ;}). on ('click', function () {choseNode. find ('. j-drop '). removeClass ('chose-hide '); if (choseNode. find ('. j-view: first '). text ()! = 'Select') {choseNode. find ('I '). removeClass ('chose-hide ');} choseNode. find ('ul: first '). empty (). append (getListNodes (choseNode. find ('. j-key '). val (); return false ;}). on ('click', 'ul> li ', function () {var _ this = $ (this); ngModelCtrl. $ setViewValue (_ this. data ('id'); ngModelCtrl. $ render (); choseNode. find ('. j-drop '). addClass ('chose-hide '); return false ;}). on ('click', 'I', function () {ngModelCtrl. $ setViewValue (''); ngModelCtrl. $ render (); choseNode. find ('. j-view: first '). text ('select '); return false ;}); $ (document ). on ("click", function () {$ ('. j-drop '). addClass ('chose-hide '); choseNode. find ('I '). addClass ('chose-hide '); return false ;});}}};})
1.2 css code (written in less mode, which is compiled below)
.chose-hide { position: absolute!important; top: -999em !important;}.chose-container { border: none!important; float: left; margin-right: 40px; padding: 0!important; position: relative;}.chose-container .chose-single { padding: 6px 12px; color: #333; width: 100%; border: 1px solid #eee; display: inline-block; height: 30px;}.chose-container .chose-single::after { content: ''; position: absolute; border-width: 6px 3px; border-style: solid; /* border-top-color: transparent; */ border-left-color: transparent; border-right-color: transparent; border-bottom-color: transparent; right: 8px; top: 12px;}.chose-container .chose-single i { width: 12px; float: right; right: 8px; font-size: 12px; height: 12px; background-color: #eee;}.chose-container .chose-drop { width: 195px; position: absolute; border: 1px solid #eee; z-index: 1000; background-color: #fff;}.chose-container .chose-search input[type='text'] { margin: 0; padding-left: 12px; width: 100%; height: 30px; border: 1px solid #ccc; float: none;}.chose-container .chose-result { max-height: 370px; overflow-y: scroll; overflow-x: hidden;}.chose-container .chose-result li { padding: 5px 12px; list-style-type: none;}.chose-container .chose-result li:hover { background-color: #e1e2e7;}
1.3 usage and effect
<Select ngc-select-search class = "common-select" ng-model = "aa. B "ng-options =" obj. countryId as obj. countryCnName for obj in vm. countries "name =" country "> <option value =" "> select </option> </select>
2. Detailed Description
The key point in the program is the parseOptions function, that is, question 1 in the previous analysis. ParseOptions is implemented by referring to the ng-options source code. It was originally intended to return an object that contains the data source, but during debugging, it is found that the data in the returned object of this function in the post function is null and the watch is not available. Therefore, use scope instead. options to store data.
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.