javascript - AngularJS Show typeahead on button click -


i using typeahead directive in angularjs , works fine. however, have button outside of input when clicked show typeahead dropdown. here snippet of after...

<li class="input">    <input focus-me="click" ng-model="something"      typeahead="state state in suggestions | filter:$viewvalue:statecomparator" typeahead-focus typeahead-focus-first="false" typeahead-on-select="updatetaginput(newtagname)">    <a href="" ng-click="opentypeahead()">open</a> </li> 

ok, having absolutely terrible time trying create jsfiddle or plunkr this, give code directive.

this directive comes from..

this epic bootstrap library!

..and stole , played it. if use it, need "bootstrap" (its subset of angular directives) library linked to. can make own subset of library, not entirely sure of of dependencies directive has using entire library in project. basically, need directive starts "typeahead".

as can see, have named directive wwtypeahead (that "ww" webwanderer!). easy use directive , works original.

<input      class="form-control"      type="text"      spellcheck="false"      ng-model="selection"      ng-trim="false"      placeholder="search here"      ww-typeahead="key key.label key in list"      typeahead-on-select="selectionmade($item, $model, $label)"      typeahead-min-length="0"  /> 

the important part note attribute typeahead-min-length="0" has been heart of many discussions online. managed make work.

this directive meant take place of typeahead directive in library linked to. typeahead list shown on focus of input box. no, list not show on click of button, getting there baby-steps here. if need implementing that, happy help.

/*     note:      following directive modification of     angular typeahead directive. normal directives,     unfortunately, not allow matching on 0 length values     , user may want returned list of values during     lack of input.      directives taken ...           http://angular-ui.github.io/bootstrap/        ..and modified. */ angular.module('ui.directives', []).directive('wwtypeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadparser', function($compile, $parse, $q, $timeout, $document, $position, typeaheadparser) {     var hot_keys = [9, 13, 27, 38, 40];      return {         require:'ngmodel',         link:function(originalscope, element, attrs, modelctrl)         {             //supported attributes (options)              //minimal no of characters needs entered before typeahead kicks-in             //var minsearch = originalscope.$eval(attrs.typeaheadminlength) || 1;             var testeval = originalscope.$eval(attrs.typeaheadminlength);             var minsearch = !isnan(parsefloat(testeval)) && isfinite(testeval) || 1;              //minimal wait time after last character typed before typehead kicks-in             var waittime = originalscope.$eval(attrs.typeaheadwaitms) || 0;              //should restrict model values ones selected popup only?             var iseditable = originalscope.$eval(attrs.typeaheadeditable) !== false;              //binding variable indicates if matches being retrieved asynchronously             var isloadingsetter = $parse(attrs.typeaheadloading).assign || angular.noop;              //a callback executed when match selected             var onselectcallback = $parse(attrs.typeaheadonselect);              var inputformatter = attrs.typeaheadinputformatter ? $parse(attrs.typeaheadinputformatter) : undefined;              //internal variables              //model setter executed upon match selection             var $setmodelvalue = $parse(attrs.ngmodel).assign;              //expressions used typeahead             var parserresult = typeaheadparser.parse(attrs.cmctypeahead);               //pop-up element used display matches             var popupel = angular.element('<typeahead-popup></typeahead-popup>');             popupel.attr({                 matches: 'matches',                 active: 'activeidx',                 select: 'select(activeidx)',                 query: 'query',                 position: 'position'             });             //custom item template             if(angular.isdefined(attrs.typeaheadtemplateurl))             {                 popupel.attr('template-url', attrs.typeaheadtemplateurl);             }              //create child scope typeahead directive not polluting original scope             //with typeahead-specific data (matches, query etc.)             var scope = originalscope.$new();             originalscope.$on('$destroy', function()             {                 scope.$destroy();             });              var resetmatches = function()             {                 scope.matches = [];                 scope.activeidx = -1;             };              var getmatchesasync = function(inputvalue)             {                 var matchparseprefix = originalscope.$eval(attrs.typeaheadparseprefix);                 var locals = {                     $viewvalue: inputvalue.indexof(matchparseprefix) === 0 ? inputvalue.substring(matchparseprefix.length, (inputvalue.length + 1)) : inputvalue                 };                 isloadingsetter(originalscope, true);                 $q.when(parserresult.source(scope, locals)).then(function(matches)                 {                     //it might happen several async queries in progress if user typing fast                     //but interested in responses correspond current view value                     //if(matches && inputvalue === modelctrl.$viewvalue)                      /*                         ehh.. didn't seem work when "cleared" input box                     */                     if(matches)                     {                         if(matches.length > 0)                         {                             scope.activeidx = 0;                             scope.matches.length = 0;                              //transform labels                             for(var = 0; < matches.length; i++)                             {                                 locals[parserresult.itemname] = matches[i];                                 scope.matches.push({                                     label: parserresult.viewmapper(scope, locals),                                     model: matches[i]                                 });                             }                              scope.query = inputvalue;                             //position pop-up matches - need re-calculate position each time opening window                             //with matches pop-up might absolute-positioned , position of input might have changed on page                             //due other elements being rendered                             scope.position = $position.position(element);                             scope.position.top = scope.position.top + element.prop('offsetheight');                          }                         else if(minsearch === 0)                         {                             resetmatches();//temp                         }                         else                         {                             resetmatches();                         }                         isloadingsetter(originalscope, false);                     }                 }, function()                 {                     resetmatches();                     isloadingsetter(originalscope, false);                 });             };              resetmatches();              /*                 can't figure out how make work...*/             if(attrs.hasownproperty('typeaheadbindmatchreloader'))             {                 $parse(attrs.typeaheadbindmatchreloader).assign(scope, function()                 {                     getmatchesasync(element[0].value);                 });             }                 //we need propagate user's query can higlight matches             scope.query = undefined;              //declare timeout promise var outside function scope stacked calls can cancelled later              var timeoutpromise;              //plug $parsers pipeline open typeahead on view changes initiated dom             //$parsers kick-in on changes coming view manually triggered $setviewvalue             modelctrl.$parsers.unshift(function(inputvalue)             {                 resetmatches();                 if((inputvalue && inputvalue.length >= minsearch)                 || minsearch === 0)                 {                     if(waittime > 0)                     {                         if(timeoutpromise)                         {                             $timeout.cancel(timeoutpromise);//cancel previous timeout                         }                          timeoutpromise = $timeout(function()                         {                             getmatchesasync(inputvalue);                         }, waittime);                     }                     else                     {                         getmatchesasync(inputvalue);                     }                 }                  if(iseditable)                 {                     return inputvalue;                 }                 else                 {                     modelctrl.$setvalidity('editable', false);                     return undefined;                 }             });              modelctrl.$formatters.push(function(modelvalue)             {                 var candidateviewvalue, emptyviewvalue;                 var locals = {};                  if(inputformatter)                 {                     locals['$model'] = modelvalue;                     return inputformatter(originalscope, locals);                 }                 else                 {                     //it might happen don't have enough info render input value                     //we need check situation , return model value if can't apply custom formatting                     locals[parserresult.itemname] = modelvalue;                     candidateviewvalue = parserresult.viewmapper(originalscope, locals);                     locals[parserresult.itemname] = undefined;                     emptyviewvalue = parserresult.viewmapper(originalscope, locals);                      return candidateviewvalue!== emptyviewvalue ? candidateviewvalue : modelvalue;                 }             });              scope.select = function(activeidx)             {                 //called within $digest() cycle                 var locals = {};                 var model, item;                  locals[parserresult.itemname] = item = scope.matches[activeidx].model;                 model = parserresult.modelmapper(originalscope, locals);                 $setmodelvalue(originalscope, model);                 modelctrl.$setvalidity('editable', true);                  onselectcallback(originalscope, {                     $item: item,                     $model: model,                     $label: parserresult.viewmapper(originalscope, locals)                 });                  resetmatches();                  //return focus input element if mach selected via mouse click event                 element[0].focus();             };              //bind keyboard events: arrows up(38) / down(40), enter(13) , tab(9), esc(27)             element.bind('keydown', function(evt)             {                 //typeahead open , "interesting" key pressed                 if(scope.matches.length === 0 || hot_keys.indexof(evt.which) === -1)                     return;                  evt.preventdefault();                  if(evt.which === 40)                 {                     scope.activeidx = (scope.activeidx + 1) % scope.matches.length;                     scope.$digest();                 }                 else if(evt.which === 38)                 {                     scope.activeidx = (scope.activeidx ? scope.activeidx : scope.matches.length) - 1;                     scope.$digest();                 }                 else if(evt.which === 13 || evt.which === 9)                 {                     scope.$apply(function()                     {                         scope.select(scope.activeidx);                     });                 }                 else if(evt.which === 27)                 {                     evt.stoppropagation();                     resetmatches();                     scope.$digest();                 }             });              // keep reference click handler unbind it.             var dismissclickhandler = function(evt)             {                 if(element[0] !== evt.target)                 {                     resetmatches();                     scope.$digest();                 }                 else                 {                     getmatchesasync(element[0].value);                 }             };              $document.bind('click', dismissclickhandler);              originalscope.$on('$destroy', function()             {                 $document.unbind('click', dismissclickhandler);             });              element.after($compile(popupel)(scope));         }     }; }]); 

call action:

somebody please make working example of typeahead directive! forever in debt you! (well, not make me happy)

disclaimer:

i understand answer in no way orthodox. did not provide askee (askee?) direct answer question, yet did provide tools believe needed his/her answer. understand should spend time make working example, busy man , wished share work community, have seen question asked many times while sit , hold answer. please let me know if have issues, questions, or complications. happy help.

thanks!


Comments

Popular posts from this blog

Fail to load namespace Spring Security http://www.springframework.org/security/tags -

sql - MySQL query optimization using coalesce -

unity3d - Unity local avoidance in user created world -