AngularJS搜索输入远程数据库自动补全失效排查及简化方案咨询
一、md-autocomplete未生效的核心原因
先看你的代码,几个关键问题直接导致组件无法工作:
缺少Angular Material依赖
md-autocomplete是Angular Material专属组件,你的模块只注入了ngRoute,完全没加ngMaterial(以及它必须的依赖ngAria、ngAnimate),这是最根本的问题。而且页面里也没引入Angular Material的CSS和JS文件,组件根本无法被识别。$http响应数据处理错误
你的query函数里,$http.get的回调返回了整个响应对象data,但实际后端返回的业务数据在data.data里。另外如果接口返回的是Job对象数组,模板里直接写{{item}}只会显示[object Object],必须取具体属性比如item.JobTitleText。原生input与md-autocomplete冲突
你页面里同时放了一个原生input和md-autocomplete,两者都绑定了inSearch,双向绑定会互相干扰——md-autocomplete本身就自带输入框,完全不需要额外加原生input。缺失Angular Material依赖库
Angular Material运行需要angular-animate和angular-aria的支持,这两个库必须和AngularJS、Angular Material一起引入。
二、修复后的完整代码
1. 页面引入必要资源(放在AngularJS之后)
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.28/angular-material.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular-animate.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular-aria.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.28/angular-material.min.js"></script>
2. 修改JS模块与控制器
var myapp = angular.module("myapp", ['ngRoute', 'ngMaterial']); // 添加ngMaterial依赖 myapp.controller("homeController", ['$scope', '$http',function ($scope, $http) { // 修复自动补全的query函数 $scope.query = function (searchText) { // 空搜索时直接返回空数组,避免无效请求 if (!searchText) return []; return $http .get('http://localhost:59836/api/Jobs/searchjobs/' + searchText) .then(function (response) { // 解析响应体中的数据,假设返回的是Job对象数组 return JSON.parse(response.data); }); }; $scope.search = function (inSearch) { $scope.inSearch = inSearch; $http({ method: "GET", url: "http://localhost:59836/api/Jobs/searchjobs/" + $scope.inSearch }).then(function Success(response) { $scope.jobs = JSON.parse(response.data); }, function Error(response) { alert(response.statusText); }); }; // 可选:选中自动补全项后自动触发搜索 $scope.selectedItemChange = function(item) { if (item) { $scope.inSearch = item.JobTitleText; $scope.search($scope.inSearch); } }; }]);
3. 修改HTML部分(移除冲突的原生input)
<body> <div ng-controller="homeController" ng-cloak> <!-- ng-cloak防止页面初始加载时的组件闪烁 --> <div class="row"> <div class="col-md-9 col-md-offset-1"> <div style="background-color:#1d1a1a; padding:4%;" class="input-group"> <!-- 只保留md-autocomplete,移除原来的原生input --> <md-autocomplete md-selected-item="selectedItem" md-search-text="inSearch" md-items="item in query(inSearch)" md-item-text="item.JobTitleText" <!-- 指定下拉项显示的文本属性 --> md-selected-item-change="selectedItemChange(selectedItem)" placeholder="Job title or keywords"> <md-item-template> <span md-highlight-text="inSearch">{{item.JobTitleText}}</span> </md-item-template> <md-not-found> No jobs matching "{{inSearch}}" were found. </md-not-found> </md-autocomplete> <span class="input-group-btn"> <button type="button" class="btn btn-default" ng-click="search(inSearch)"> <span class="glyphicon glyphicon-search"> <span class="sr-only">Search</span> </span> </button> </span> </div> <div ng-repeat="job in jobs"> <a href="#" class="list-group-item"> <h2 style="color:dodgerblue">{{job.JobTitleText}}</h2> <h4>{{job.job_description}}</h4> </a> </div> </div> </div> </div> </body>
三、更简便的实现方案(无需Angular Material)
如果不想引入Angular Material这种较重的库,推荐用原生HTML5的datalist,实现成本极低,完全满足基础自动补全需求:
1. 修改HTML
<input type="text" class="form-control" placeholder="Job title or keywords" ng-model="inSearch" list="jobSuggestions"> <datalist id="jobSuggestions"> <option ng-repeat="item in suggestions" value="{{item.JobTitleText}}"></option> </datalist>
2. 修改JS控制器(添加输入防抖监听)
myapp.controller("homeController", ['$scope', '$http', '$timeout',function ($scope, $http, $timeout) { var searchTimeout; // 监听输入变化,添加防抖避免频繁调用接口 $scope.$watch('inSearch', function(newVal) { if (!newVal) { $scope.suggestions = []; return; } // 300ms内没有新输入才发起请求,减少无效接口调用 if (searchTimeout) $timeout.cancel(searchTimeout); searchTimeout = $timeout(function() { $http.get('http://localhost:59836/api/Jobs/searchjobs/' + newVal) .then(function(response) { $scope.suggestions = JSON.parse(response.data); }); }, 300); }); // 原有的search函数保持不变 $scope.search = function (inSearch) { $scope.inSearch = inSearch; $http({ method: "GET", url: "http://localhost:59836/api/Jobs/searchjobs/" + $scope.inSearch }).then(function Success(response) { $scope.jobs = JSON.parse(response.data); }, function Error(response) { alert(response.statusText); }); }; }]);
这个方案不需要任何额外库,利用原生HTML5特性实现自动补全,适合需求简单的场景。
内容的提问来源于stack exchange,提问作者meyt

