Я изучаю AngularJS и использую AngularMaterial.
Чтобы проверить это, я решил создать пример из кода, приведенного в документации (check codepen). Мое приложение - приложение nodeJS в Cloud9 и очень простое.
Он разделен на 3 основных файлов, index.html
(который содержит коробку автозаполнения), server.js
(содержащих логику сервера) и autocomplete.js
( на стороне клиента логика).
Ниже приведены файл index.html
а затем файлы autocomplete.js
. Поскольку у меня есть сервер, работающий в Cloud9, и этот пример связан с ним, вы можете проверить небольшой пример работы в прямом эфире!
/*global angular*/
'use strict';
angular.module('MyApp', ['ngMaterial', 'ngMessages', 'material.svgAssetsCache']).controller('DemoCtrl', DemoCtrl);
function DemoCtrl($q, $log, $http) {
this.searchText = null;
this.querySearch =function(query) {
let serverUrl = '//material-complete-fl4m3ph03n1x.c9users.io/getStates';
let deferred = $q.defer();
$http({
method: 'GET',
url: serverUrl,
params: {
word: query
}
}).then(function successCallback(response) {
deferred.resolve(response.data);
}, function errorCallback(response) {
$log.error(response);
});
return deferred.promise;
};
this.searchTextChange = function(text) {
$log.info('Text changed to ' + text);
};
this.selectedItemChange = function(item) {
$log.info('Item changed to ' + JSON.stringify(item));
};
}
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body ng-app="MyApp" ng-cloak>
<div ng-controller="DemoCtrl as ctrl" layout="column" ng-cloak="" class="autocompletedemoBasicUsage" ng-app="MyApp">
<md-content class="md-padding">
<form ng-submit="$event.preventDefault()">
<md-autocomplete md-search-text-change="ctrl.searchTextChange(ctrl.searchText)" md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)" md-items="item in ctrl.querySearch(ctrl.searchText)" md-item-text="item.display" md-min-length="0"
placeholder="What is your favorite US state?">
<md-item-template>
<span md-highlight-text="ctrl.searchText" md-highlight-flags="^i">{{item.display}}</span>
</md-item-template>
<md-not-found>
No states matching "{{ctrl.searchText}}" were found.
</md-not-found>
</md-autocomplete>
<br>
</form>
</md-content>
</div>
<!--CSS files-->
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0-rc4/angular-material.min.css">
<link rel="stylesheet" href="https://material.angularjs.org/1.1.0-rc4/docs.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<!-- Angular Material requires Angular.js Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-messages.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-114/svg-assets-cache.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0-rc4/angular-material.min.js"></script>
<!-- Your application bootstrap -->
<script type="text/javascript" src="js/autocomplete.js"></script>
</body>
</html>
Кроме того, вот код моего файла server.js
, который использует NodeJs и ExpressJs:
//Lets define a port we want to listen to
const PORT = 8080;
//Init Vars
var express = require('express');
var app = express();
//Init Functions
//we allow CORS: http://enable-cors.org/server_expressjs.html
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.listen(PORT, function() {
console.log('Example app listening on port ' + PORT + '!');
});
//GET methods
app.get('/getStates', function(req, res, next) {
var createFilterFor = function(query) {
var lowercaseQuery = query.toLowerCase();
return function filterFn(state) {
return (state.value.indexOf(lowercaseQuery) > -1);
};
};
//get parameters from GET: https://scotch.io/tutorials/use-expressjs-to-get-url-and-post-parameters
var query = req.param('word');
var allStates = 'Alabama, Alaska, Arizona, Arkansas, California, Colorado, Connecticut, Delaware,\
Florida, Georgia, Hawaii, Idaho, Illinois, Indiana, Iowa, Kansas, Kentucky, Louisiana,\
Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana,\
Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina,\
North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina,\
South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia,\
Wisconsin, Wyoming';
var statesMap = allStates.split(/, +/g).map(
function(state) {
return {
value: state.toLowerCase(),
display: state
};
});
var result = query ? statesMap.filter(createFilterFor(query)) : statesMap;
res.send(result);
});
Теперь, если вы играете, вы можете выбрать американское государство в списке. Список фильтрует в соответствии с тем, что вы набираете, и позволяет вам выбрать что-то. Если вы используете инструменты разработчика, вы также можете увидеть журналы в консоли, еще раз продемонстрировав, что запрос работает, а также выбор.
Проблема здесь, когда вы очищаете текстовое поле. Если вы выберите состояние, а затем очистите его (нажав крестик или нажав Escape), вы увидите синюю полосу ниже поля ввода:
Это означает, что запрос выполняется. Проблема в том, что я не вижу отправки какого-либо запроса на сервер, а я застрял в бесконечном запросе! Даже когда, видимо, я этого не делаю!
Что мне здесь не хватает? Кто-нибудь может мне помочь?
Для тех, кого это интересует, вот репозиторий GitHub на примере!
Вся помощь приветствуется!
Вы возвращаете обещание из-за неправильного местоположения и не возвращаете цепочку должным образом, чтобы оно не разрешалось должным образом.
Попробуйте это (обратите внимание на возврат перед вызовом в $ http):
this.querySearch =function(query) {
let serverUrl = '//material-complete-fl4m3ph03n1x.c9users.io/getStates';
let deferred = $q.defer();
return $http({
method: 'GET',
url: serverUrl,
params: {
word: query
}
}).then(function successCallback(response) {
if(response.data.length>0) {
deferred.resolve(response.data); }
else {
var nada=[]
deferred.resolve(nada); }
}
return deferred.promise;
}, function errorCallback(response) {
$log.error(response);
deferred.reject(response);
return deferred.promise;
});
};
Версия TL;DR из комментариев. Это известная ошибка, и исправление не выпущено на момент написания этой статьи. Обходной путь - либо откат до AM 1.06, либо использование css, чтобы скрыть панель прогресса. CSS:
md-autocomplete md-progress-linear { display: none; }
Установите md-min-length
в 1
- вы действительно не хотите предлагать доработки до внешней службы до тех пор, пока пользователь не начнет вводить текст.
<md-autocomplete
md-search-text-change="ctrl.searchTextChange(ctrl.searchText)"
md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)"
md-items="item in ctrl.querySearch(ctrl.searchText)"
md-item-text="item.display"
md-min-length="1"
placeholder="What is your favorite US state?">
<md-item-template>
<span md-highlight-text="ctrl.searchText" md-highlight-flags="^i">{{item.display}}</span>
</md-item-template>
<md-not-found>
No states matching "{{ctrl.searchText}}" were found.
</md-not-found>
</md-autocomplete>
min-length="0"
. Если бы мне это не нужно, ваш ответ был бы принят. Престижность ++ за попытку.