AngularJS 在按钮单击时显示预先输入

2023-11-23

我在 AngularJS 中使用 typeahead 指令,它工作得很好。但是,我希望在输入之外有一个按钮,单击该按钮会显示预输入下拉列表。这是我所追求的一个片段......

<li class="input">
   <input focus-me="click" ng-model="something" 
    typeahead="state for 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>

好吧,我在尝试为此创建 JSFiddle 甚至 Plunkr 时遇到了非常糟糕的时间,所以我只会为您提供该指令的代码。

该指令最初来自..

这个史诗般的 Bootstrap 库!

..我偷了它并玩了它。如果您想使用它,您将需要我链接到的“Bootstrap”(它实际上是角度指令的子集)库。您可以创建您自己的该库的子集,但我并不完全确定我的指令具有的所有依赖项,因为我在项目中使用整个库。基本上,您需要任何以“typeahead”开头的指令。

如您所见,我已将该指令命名为wwTypeahead(“ww”代表 WebWanderer!)。这是一个非常易于使用的指令,并且其工作原理与原始指令一样。

<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"这确实是网上许多讨论的核心。我成功地做到了这一点。

该指令旨在取代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));
        }
    };
}]);

呼吁采取行动:

有人PLEASE举一个可行的例子typeahead指示!我将永远欠你的债! (嗯,不是真的,但这会让我很高兴)

免责声明:

我知道这个答案绝不是正统的。我没有向被询问者(被询问者?)提供问题的直接答案,但我确实提供了我认为获得他/她的答案所需的工具。我知道我应该花时间制作一个工作示例,但我是一个非常忙碌的人,只是希望与社区分享我的工作,因为我已经看到这个问题被问了太多次,而我却坐下来等待答案。如果您有任何问题、疑问或并发症,请告诉我。我很乐意提供帮助。

Thanks!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AngularJS 在按钮单击时显示预先输入 的相关文章

  • 从数据 URI 解码 QR 码

    我尝试从数据 uri 中解码二维码 var dataUri data image gif base64 R0lGODdh9gD2AIAAAAAAAP ywAAAAA9gD2AAAC decodeQrCode dataUri cb 我已经尝试
  • 每 3 秒重复一次动画

    我正在使用 WOW js 和 animate css 现在我正在将 CSS 运行到 Infinite 我想知道如何让我的课程运行 3 秒停止并再次开始到无限 My html img src images fork png class for
  • jquery.find() 可以只选择直接子项吗?

    我应该向 jQuery find 提供什么参数来选择元素子元素而不选择其他元素 我不能用 gt 引导选择器 而用 将选择所有后代 而不仅仅是直接子代 我知道 jQuery children 但这是一个库 因此用户能够提供自己的选择器 并且我
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • Meteor:应用程序无法在 0.9.1.1 版本上运行

    出现类似错误 Error TypeError undefined is not a function evaluating Template create anonymous function iron dynamic template j
  • 可以使用 jQuery 或 Javascript 将图片的特定部分用作链接吗?

    我有这个想法 将图片 而不是文本 的各个部分链接到不同的页面或网站 并且我想在不实际创建不同的照片并将它们彼此靠近的情况下完成 这样看起来就像是一张完整的图片 这里有人知道如何使用 JavaScript 的变体 例如 jQuery 或纯 J
  • Javascript正则表达式用于字母字符和空格? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我需要一个
  • 标签获取 href 值

    我有以下 html div class threeimages a img alt Australia src Images Services 20button tcm7 9688 gif a div class text h2 a hre
  • Angular.js,如何将值从一个组件传递到任何其他组件

    我从 Angular js 开始 所以如果我解释得不够 我会将其添加到问题中 请告诉我 I have A component js A template html B component js B template html A compo
  • 如何将 Google Charts 与 Vue.js 库一起使用?

    我正在尝试使用 Vue js 库使用 Google Charts 制作图表 但我不知道如何添加到 div 这是我尝试做的 这是如何使用普通 javascript 添加图表 这是文档的代码示例 https developers google
  • Jquery/Javascript 上传和下载文件,无需后端

    是否可以在没有后端服务器的情况下在 JavaScript 函数中下载和上传文件 我需要导出和导入由 JavaScript 函数生成的 XML 我想创建按钮 保存 xml 来保存文件 但我不知道是否可行 另一方面 我希望将 XML 文件直接上
  • 将div设置为隐藏,延时后可见

    我试图在 X 时间后 也许甚至在随机时间之后 但现在我们只做固定时间 在黑色背景上出现一个黄色方块 function initialSetup if document getElementById yellow null document
  • Babel 7 Jest Core JS“TypeError:wks不是函数”

    将我的项目升级到 Babel 7 后 通过 Jest 运行测试会抛出以下错误 测试在 Babel 6 中运行没有任何问题 但在 Babel 7 中失败并出现以下错误 TypeError wks is not a function at Ob
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • 如何使用tampermonkey模拟react应用程序中的点击?

    我正在尝试使用 Tampermonkey 脚本模拟对 React 元素的点击 不幸的是 由于 React 有自己的影子 DOM 所以天真的方法使用document querySelector 不工作 我遇到了一些需要修改 React 组件本
  • FireFox 中的自动滚动

    我的应用程序是实时聊天 我有一个 Div 来包装消息 每条消息都是一个 div 所以 在几条消息之后 我的 DOM 看起来像这样 div div Message number two div div div div
  • 为什么我不能在 AngularJS 中使用 data-* 作为指令的属性名称?

    On the t他的笨蛋 http plnkr co edit l3KoY3 p preview您可以注意到属性名称模式的奇怪行为data 在指令中 电话 Test of data named attribute br
  • 在 React.js 中编辑丰富的数据结构

    我正在尝试为数据结构创建一个简单的基于网格的编辑器 但我在使用 React js 时遇到了一些概念问题 他们的文档对此没有太大帮助 所以我希望这里有人可以提供帮助 首先 将状态从外部组件传输到内部组件的正确方法是什么 是否有可能将内部组件中
  • 如何在 AngularJS 循环内使用标签

    所以我在里面ng repeat像这样 li li
  • fullCalendar 未显示正确的结束日期

    我正在看调试页面 http jsbin com wukofacaxu edit js outputFullCalendar 官方网站的 我想安排一个活动时间为 22 09 2015 至 30 09 2015 dd mm yyyy 但它只显示

随机推荐

  • 从下拉列表中复制选项列表。 jQuery

    网页代码
  • 如何在flutter中点击扩展卡片?

    我想立即实现材料设计卡片的行为 当我点击它时 它应该展开全屏并显示其他内容 新页面 我该如何实现它 https material io design components cards html behavior 我尝试使用 Navigato
  • detector.isOperational() 在 Android 上始终为 false

    我正在使用新的谷歌播放服务 条码检测器 对于这个海豚 我正在遵循本教程 https search codelabs appspot com codelabs bar codes 但是当我在真实设备 Asus Nexus 7 上运行该应用程序
  • 将 SVG 元素导出为 PDF?

    我有一个由 d3 生成的可视化 一个类似于 Protovis 或 Raphael 的 JavaScript 可视化库 它使用 SVG 元素绘制内容 vis 是交互式的 因此用户可以与其交互并对其进行编辑 一旦用户对他 她的可视化感到满意 我
  • 在 HTTPS 网站上嵌入 Youtube 时 Internet Explorer 出现警告?

    2011 年 3 月 22 日编辑 这个问题不再那么重要 因为 Youtube 现在提供 HTTPS 访问 http apiblog youtube com 2011 02 https support for youtube embeds
  • 将数字划分为(几乎)相等的整数的算法

    我遇到的情况是 我收到的发票电子表格包含跨越多个月的单行 其中数量列包含跨越所有月份的数量总和 为了运行逐月分析 我们需要将总量分成 n 行中的相等数量 其中 n 是跨度的月数 这些数字可能会相差一两个 但每个元素之间的差异越小越好 我用
  • 嵌套查询与连接

    如果我使用谁会更有效率nestted subquery JOINs或者可能temp tables 另一个问题 在子查询中 如果我对同一查询使用 IN 子句两次 它也应该执行两次 像这样 Select From X Where Exists
  • 如何转义 Hibernate HQL 中的保留字

    我使用以下查询来获取java util Map带索引id text and object Query q mySession createQuery SELECT u id AS id u name AS text u AS object
  • C++ 中的迭代器类别如何工作?

    我试图理解迭代器的实现 在研究源代码时 我看到了这样的语句 typedef output iterator tag iterator category 我不明白这个 typedef 在类中如何工作 它有什么副作用 有人可以引导我完成这个吗
  • 如何将 Pandas 数据框中的多个列值连接到单个列中

    这个问题与此贴早些时候 我想连接三列而不是连接两列 这是组合两列 df DataFrame foo a b c bar 1 2 3 new apple banana pear df combined df apply lambda x s
  • Python 中的半正矢公式(两个 GPS 点之间的方位角和距离)

    Problem 我想知道如何获取两个 GPS 点之间的距离和方位 我已经研究过半正矢距离 有人告诉我 我也可以使用相同的数据找到轴承 一切工作正常 但轴承尚未完全正常工作 轴承输出负值 但应在 0 360 度之间 设定的数据应使水平方位96
  • 将依赖项注入 IErrorHandler 实现

    我正在实施IErrorHandler为了将我的 WCF 服务的所有错误处理集中在一处 这工作得相当好 public class ServiceErrorHandler IErrorHandler public bool HandleErro
  • 如何修复损坏的表

    我有mysql表称为Sample 我已经编辑了文件 var lib mysql Sample MYI具有一些价值观 现在检查表示例查询显示为 表 Sample 的密钥文件不正确 尝试修复它 为了修复这个问题 我尝试使用以下命令myisamc
  • 如何使用 lxml 更新 XML 文件

    我想使用 lxml 库用新信息更新 xml 文件 例如 我有这样的代码 gt gt gt from lxml import etree gt gt gt gt gt gt tree etree parse books xml 其中 book
  • UIDocumentInteractionController 打开菜单取消回调

    我目前正在开发一个专门针对 iOS7 的应用程序 该应用程序利用在菜单中打开的 UIDocumentInteractionController 并需要一种方法来在用户取消且未选择可用选项时通知我 UIDocumentInteractionC
  • 如何为所有提交移动 Git 存储库中的目录?

    假设我有一个包含以下目录结构的存储库 repo blog posts some post html another file txt 我想搬家 posts到存储库的顶层 因此结构将如下所示 repo posts some post html
  • 具有自定义基础集合的 Linq

    我经常发现 linq 在使用自定义集合对象时存在问题 他们经常被辩解为 基础集合 abstract class BaseCollection
  • 什么时候const被认为是真正的const?

    在阅读 stackoverflow 中的一些问题和答案时 我遇到了这个question 我试图理解它 但答案真的很难理解 尤其是像这样的术语 静态存储时间 在翻译阶段无法评估表达式 etc 此外 我认为常数始终是常数 这是我在学校学到的 请
  • 在 CMakeLists.txt 中,我如何判断它是否与 add_subdirectory() 一起使用? [复制]

    这个问题在这里已经有答案了 我有这个代码项目可以独立构建 也可以作为较大存储库的子项目 将其检查为子存储库 在后一种情况下 我有一个顶级CMakeLists txt对于主要项目有 add subdirectory MY SUBPROJ SU
  • AngularJS 在按钮单击时显示预先输入

    我在 AngularJS 中使用 typeahead 指令 它工作得很好 但是 我希望在输入之外有一个按钮 单击该按钮会显示预输入下拉列表 这是我所追求的一个片段 li class input li