Reputation: 318
I'm trying to get md-autocomplete to play nice with Algolia's Angular service. I'm stuck on getting the dropdown to display the results being returned from Algolia. The content is in console yet the dropdown will not populate with the updated results. What am I missing?
tl;dr: Plnkr
"Backend"
.controller('DemoCtrl', DemoCtrl);
function DemoCtrl ($timeout, $q, $log, algolia, $http, $scope) {
var self = this;
self.simulateQuery = false;
self.isDisabled = false;
self.repos = loadAll();
self.querySearch = querySearch;
self.selectedItemChange = selectedItemChange;
self.searchTextChange = searchTextChange;
// Algolia demo keys below
var client = algolia.Client('latency', '6be0576ff61c053d5f9a3225e2a90f76');
var index = client.initIndex('contacts');
$scope.query = '';
$scope.hits = [];
// Disable cache
$scope.noCacheResults = false;
// ******************************
// Internal methods
// ******************************
/**
* Search for repos... use $timeout to simulate
* remote dataservice call.
*/
function querySearch (query) {
// This returns objects in console
var results = self.algoliaSearch(query);
// This returns: TypeError: Cannot read property 'then' of undefined
// var results = query ? self.algoliaSearch( createFilterFor(query) ) : self.repos, deferred;
return results;
}
function searchTextChange(text) {
$log.info('Text changed to ' + text);
}
function selectedItemChange(item) {
$log.info('Item changed to ' + JSON.stringify(item));
}
/**
* Build `components` list of key/value pairs
*/
function algoliaSearch(text) {
try {
index
.search(text)
.then(function(content) {
// if (content.query !== $scope.query) {
// // do not take out-dated answers into account
// return;
// }
$scope.hits = content.hits;
return content.hits.map( function (hit) {
hit.value = hit.name.toLowerCase();
$log.debug(hit);
return hit;
});
}, function(content) {
console.log('Error: ' + content.message);
});
} catch(e) {
$log.debug(e);
}
}
function loadAll() {
var repos = [
{
'name' : 'Angular 1',
'url' : 'https://github.com/angular/angular.js',
'watchers' : '3,623',
'forks' : '16,175',
}
];
return repos.map( function (repo) {
repo.value = repo.name.toLowerCase();
return repo;
});
}
/**
* Create filter function for a query string
*/
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(item) {
return (item.value.indexOf(lowercaseQuery) === 0);
};
}
}
"Frontend"
<div ng-controller="DemoCtrl as ctrl" layout="column" ng-cloak>
<md-content layout-padding layout="column">
<form ng-submit="$event.preventDefault()">
<p>Use <code><md-autocomplete></code> with custom templates to show styled autocomplete results.</p>
<md-autocomplete
ng-disabled="ctrl.isDisabled"
md-no-cache="ctrl.noCacheResults"
md-selected-item="ctrl.selectedItem"
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.name"
md-min-length="0"
placeholder="Pick an Angular repository"
md-menu-class="autocomplete-custom-template">
<md-item-template>
{{item}}
<span class="item-title">
<md-icon md-svg-icon="img/icons/octicon-repo.svg"></md-icon>
<span> {{item.name}} </span>
</span>
<span class="item-metadata">
<span class="item-metastat">
<strong>{{item.watchers}}</strong> watchers
</span>
<span class="item-metastat">
<strong>{{item.forks}}</strong> forks
</span>
</span>
</md-item-template>
</md-autocomplete>
</form>
</md-content>
</div>
"Algolia default"
<section class="panel">
<header class="panel-heading">
<div class="search_box">
<form action="#" method="get">
<input autocomplete="off" class="autocomplete" placeholder="Start typing" type="text" spellcheck="false" id="q" ng-model="query" />
<div class="searchbutton">
<i class="icon-search icon-large"></i>
</div>
</form>
</div>
</header>
</section>
<h1>Results</h1>
<div class="hit" ng-repeat="hit in hits">
<div class="attribute" ng-repeat="(attribute,v) in hit._highlightResult">
<span>{{ attribute }}: </span>
<span ng-bind-html="v.value"></span>
</div>
</div>
<script type="text/javascript">
angular
.module('myapp', ['algoliasearch', 'ngSanitize'])
.controller('SearchCtrl', ['$scope', 'algolia', function($scope, algolia) {
$scope.query = '';
$scope.hits = [];
// Replace the following values by your ApplicationID and ApiKey.
var client = algolia.Client('latency', '6be0576ff61c053d5f9a3225e2a90f76');
// Replace the following value by the name of the index you want to query.
var index = client.initIndex('contacts');
$scope.$watch('query', function() {
index.search($scope.query, { hitsPerPage: 5 }).then(function(content) {
if (content.query !== $scope.query) {
// do not take out-dated answers into account
return;
}
$scope.hits = content.hits;
}, function(content) {
console.log('Error: ' + content.message);
});
});
}]);
</script>
Upvotes: 1
Views: 1586
Reputation: 1840
You should return a Promise
since the call to AlgoliaSearch is asynchronous:
function querySearch(query) {
return algoliaSearch(query);
// var results = query ? self.algoliaSearch( createFilterFor(query) ) : self.repos, deferred;
}
You can find the updated code here: http://plnkr.co/edit/C8fmsNRzNsXEC7InNM6a
Upvotes: 2