ठीक है, मैं एक JSFiddle या यहाँ तक कि इसके लिए एक Plunkr बनाने का प्रयास कर एक बिल्कुल भयानक समय चल रहा है, तो मैं बस आप इस के लिए कोड दे देंगे निर्देश।
यह निर्देश मूल रूप से आता है ..
This epic Bootstrap library!
..और मैं इसे चुरा लिया है और इसके साथ खेला। यदि आप इसका उपयोग करना चाहते हैं, तो आपको "बूटस्ट्रैप" (वास्तव में कोणीय निर्देशों का एक उप-समूह) लाइब्रेरी की आवश्यकता होगी जिसे मैंने लिंक किया था। आप इस लाइब्रेरी का अपना सबसेट बना सकते हैं, लेकिन मेरे निर्देश में सभी निर्भरताओं के बारे में पूरी तरह से यकीन नहीं है क्योंकि मैं अपनी परियोजना में पूरी लाइब्रेरी का उपयोग कर रहा हूं। असल में, आपको "टाइपहेड" से शुरू होने वाले किसी भी निर्देश की आवश्यकता होती है।
जैसा कि आप देख सकते हैं, मैंने निर्देश wwTypeahead
("ww" वेबवांडर के लिए है!) नाम दिया है। यह निर्देश का उपयोग करना बहुत आसान है और यह मूल की तरह ही काम करता है।
<input
class="form-control"
type="text"
spellcheck="false"
ng-model="selection"
ng-trim="false"
placeholder="Search Here"
ww-typeahead="key as key.label for key in list"
typeahead-on-select="selectionMade($item, $model, $label)"
typeahead-min-length="0"
/>
वास्तव में महत्वपूर्ण हिस्सा नोट करने के लिए विशेषता typeahead-min-length="0"
जो वास्तव में ऑनलाइन कई चर्चाओं के दिल की गई है। मैं वह काम करने में कामयाब रहा।
यह निर्देश 0 पुस्तकालय में typeahead
निर्देश की जगह लेने के लिए है। आपकी टाइपहेड सूची आपके इनपुट बॉक्स के focus
पर दिखाई जाएगी। नहीं, सूची एक बटन के क्लिक पर नहीं दिखती है, लेकिन उम्मीद है कि यहां से बच्चे के कदम होंगे। अगर आपको इसे लागू करने में मदद की ज़रूरत है, तो मुझे मदद करने में खुशी होगी।
/*
NOTE:
The following directive is a modification of the
Angular typeahead directive. The normal directives,
unfortunately, do not allow matching on 0 length values
and the user may want a returned list of all values during
the lack of input.
This directives was taken from ...
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 that needs to be 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 it restrict model values to the ones selected from the popup only?
var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
//binding to a variable that indicates if matches are being retrieved asynchronously
var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
//a callback executed when a match is 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 by typeahead
var parserResult = typeaheadParser.parse(attrs.cmcTypeahead);
//pop-up element used to 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 a child scope for the typeahead directive so we are 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 that several async queries were in progress if a user were typing fast
//but we are interested only in responses that correspond to the current view value
//if(matches && inputValue === modelCtrl.$viewValue)
/*
Ehh.. that didn't seem to work when I "cleared" the input box
*/
if(matches)
{
if(matches.length > 0)
{
scope.activeIdx = 0;
scope.matches.length = 0;
//transform labels
for(var i = 0; i < 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 with matches - we need to re-calculate its position each time we are opening a window
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
//due to 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 to make this work...*/
if(attrs.hasOwnProperty('typeaheadBindMatchReloader'))
{
$parse(attrs.typeaheadBindMatchReloader).assign(scope, function()
{
getMatchesAsync(element[0].value);
});
}
//we need to propagate user's query so we can higlight matches
scope.query = undefined;
//Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
var timeoutPromise;
//plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
//$parsers kick-in on all the changes coming from the view as well as manually triggered by $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 that we don't have enough info to properly render input value
//we need to check for this situation and simply return model value if we 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 from within the $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 to the input element if a mach was selected via a mouse click event
element[0].focus();
};
//bind keyboard events: arrows up(38)/down(40), enter(13) and tab(9), esc(27)
element.bind('keydown', function(evt)
{
//typeahead is open and an "interesting" key was 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 to click handler to 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));
}
};
}]);
कार्रवाई के लिए कॉल:
किसी कृपया इस typeahead
निर्देश का एक काम उदाहरण है! मैं हमेशा तुम्हारे लिए ऋण में रहूंगा! (ठीक है, वास्तव में नहीं है, लेकिन यह मुझे बहुत खुश हो जाएगा)
अस्वीकरण:
मैं समझता हूँ कि इस उत्तर के कोई रास्ता नहीं रूढ़िवादी है। मैंने प्रश्नकर्ता के प्रत्यक्ष प्रश्न के साथ पूछताछकर्ता (पूछताछ?) प्रदान नहीं किया था, फिर भी मैंने उन औजारों को प्रदान किया जो मुझे विश्वास है कि उनके जवाब में जाने के लिए आवश्यक हैं। मैं समझता हूं कि मुझे एक कामकाजी उदाहरण बनाने के लिए समय बिताना चाहिए, लेकिन मैं बहुत व्यस्त व्यक्ति हूं और समुदाय के साथ अपना काम साझा करना चाहता हूं, क्योंकि मैंने देखा है कि इस सवाल ने कई बार पूछा है जबकि मैं वापस बैठकर जवाब पकड़ता हूं । अगर आपको कोई समस्या, प्रश्न या जटिलता है तो कृपया मुझे बताएं। मदद करके मुझे खुशी होगी।
धन्यवाद!
आप वास्तव में क्या दिखाने की उम्मीद कर रहे हैं? – charlietfl
यदि उपयोग-केस वास्तविक है, तो यह उनके github https://github.com/angular-ui/bootstrap – Okazari
@charlietfl पर एक महान सुविधा अनुरोध करेगा जो मैं इसके बाद कुछ हूं [लिंक] (http: //plnkr.co/edit/bZMEOx0Qwo6VzW7oSuEE?p=preview) लेकिन फ़ोकस ईवेंट पर टाइपहेड मेनू खोलने के बजाय मैं दाईं ओर एक बटन जोड़ना चाहता हूं जो मेनू खोल देगा। – kgalb