Skip to content
This repository was archived by the owner on May 21, 2025. It is now read-only.

Commit 5054709

Browse files
committed
Merge #128: Add custom remote data function
- Rename attribute name - Add a test
1 parent 861a265 commit 5054709

7 files changed

Lines changed: 68 additions & 10 deletions

File tree

CONTRIBUTORS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
* Escape regular expression #123
3434

35+
### [@jbuquet: Javier Buquet](https://github.com/jbuquet)
36+
37+
* Add custom API handler #128
38+
3539
### [@jermspeaks: Jeremy Wong](https://github.com/jermspeaks)
3640

3741
* Support withCredentials for $http #113

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ To see a demo go here: http://ghiden.github.io/angucomplete-alt
3838
* Clear input by sending $broadcast from parent scope. Thanks to @Leocrest for #61.
3939
* Override template with your own. When you use this feature, test throughly as it might break other features. Thanks to @sdbondi for #74.
4040
* Show all items.
41+
* Custom remote API handler which allows you to fully control how to communicate with your remote API. Thanks to @jbuquet
4142

4243
### Getting Started
4344
Download the package, and include the dist/angucomplete-alt.min.js file in your page.
@@ -96,7 +97,6 @@ var app = angular.module('app', ["angucomplete-alt"]);
9697
| pause | The time to wait (in milliseconds) before searching when the user enters new characters. [example](http://ghiden.github.io/angucomplete-alt/#example1) | No | 400 |
9798
| selected-object | Either an object in your scope or callback function. If you set an object, it will be two-way-bound data as usual. If you set a callback, it gets called when selection is made. [example](http://ghiden.github.io/angucomplete-alt/#example1) | Yes | selectedObject or objectSelectedCallback |
9899
| remote-url | The remote URL to hit to query for results in JSON. angucomplete will automatically append the search string on the end of this, so it must be a GET request. [example](http://ghiden.github.io/angucomplete-alt/#example5) | No | http://myserver.com/api/users/find?searchstr= |
99-
| get-remote-data-function | A function in the controller that would receive the string and some parameters like the timeout promise, and would return a promise with the request for the data | No | - |
100100
| remote-url-data-field | The name of the field in the JSON object returned back that holds the Array of objects to be used for the autocomplete list. [example](http://ghiden.github.io/angucomplete-alt/#example5) | No | results |
101101
| title-field | The name of the field in the JSON objects returned back that should be used for displaying the title in the autocomplete list. Note, if you want to combine fields together, you can comma separate them here (e.g. for a first and last name combined). If you want to access nested field, use dot to connect attributes (e.g. name.first). [example](http://ghiden.github.io/angucomplete-alt/#example1) | Yes | firstName,lastName |
102102
| description-field | The name of the field in the JSON objects returned back that should be used for displaying the description in the autocomplete list. [example](http://ghiden.github.io/angucomplete-alt/#example6) | No | twitterUsername |
@@ -111,6 +111,7 @@ var app = angular.module('app', ["angucomplete-alt"]);
111111
| remote-url-request-with-credentials | A boolean that accepts parameters with credentials. | No | true or false |
112112
| remote-url-response-formatter | A function on the scope that will modify raw response from remote API before it is rendered in the drop-down. Useful for adding data that may not be available from the API. The specified function must return the object in the format that angucomplete understands. | No | addImageUrlToObject |
113113
| remote-url-error-callback | A callback funciton to handle error response from $http.get | No | httpErrorCallbackFn |
114+
| remote-api-handler | This gives a way to fully delegate handling of remote search API. This function takes user input string and timeout promise, and it needs to return a promise. For example, if your search API is based on POST, you can use this function to create your own http handler. See example below | No | - |
114115
| clear-selected | To clear out input field upon selecting an item, set this attribute to true. [example](http://ghiden.github.io/angucomplete-alt/#example3) | No | true |
115116
| override-suggestions | To override suggestions and set the value in input field to selectedObject. [example](http://ghiden.github.io/angucomplete-alt/#example4) | No | true |
116117
| field-required | Set field to be required. Requirement for this to work is that this directive needs to be in a form. Default class name is "autocomplete-required". [example](http://ghiden.github.io/angucomplete-alt/#example8) | No | true |
@@ -150,6 +151,23 @@ To clear an angucomplete-alt input field, send this message with id of the direc
150151
$scope.$broadcast('angucomplete-alt:clearInput', 'autocomplete-1');
151152
```
152153

154+
### Remote API Handler
155+
156+
This is an example calling search API with POST.
157+
Pass this searchAPI function to the directive as remote-api-hander.
158+
159+
```js
160+
$scope.searchAPI = function(userInputString, timeoutPromise) {
161+
return $http.post('/yourownapi/', {q: userInputString}, {timeout: timeoutPromise});
162+
}
163+
```
164+
When you use remote-api-handler, these attributes are ignored:
165+
```
166+
remote-url
167+
remote-url-request-formatter
168+
remote-url-request-with-credentials
169+
```
170+
153171
### Contributors
154172

155173
Here is the list of [contributors](CONTRIBUTORS.md).

angucomplete-alt.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
remoteUrlRequestWithCredentials: '@',
8080
remoteUrlResponseFormatter: '=',
8181
remoteUrlErrorCallback: '=',
82-
getRemoteDataFunction: '=',
82+
remoteApiHandler: '=',
8383
id: '@',
8484
type: '@',
8585
placeholder: '@',
@@ -405,6 +405,10 @@
405405

406406
function httpSuccessCallbackGen(str) {
407407
return function(responseData, status, headers, config) {
408+
// normalize return obejct from promise
409+
if (!status && !headers && !config) {
410+
responseData = responseData.data;
411+
}
408412
scope.searching = false;
409413
processResults(
410414
extractValue(responseFormatter(responseData), scope.remoteUrlDataField),
@@ -413,6 +417,10 @@
413417
}
414418

415419
function httpErrorCallback(errorRes, status, headers, config) {
420+
// normalize return obejct from promise
421+
if (!status && !headers && !config) {
422+
status = errorRes.status;
423+
}
416424
if (status !== 0) {
417425
if (scope.remoteUrlErrorCallback) {
418426
scope.remoteUrlErrorCallback(errorRes, status, headers, config);
@@ -449,13 +457,12 @@
449457
.error(httpErrorCallback);
450458
}
451459

452-
function getResourceResults(str) {
460+
function getRemoteResultsWithCustomHandler(str) {
453461
cancelHttpRequest();
454462

455463
httpCanceller = $q.defer();
456-
var params = { timeout: httpCanceller.promise };
457464

458-
scope.getRemoteDataFunction(str, params).$promise
465+
scope.remoteApiHandler(str, httpCanceller.promise)
459466
.then(httpSuccessCallbackGen(str))
460467
.catch(httpErrorCallback);
461468
}
@@ -515,8 +522,8 @@
515522
getLocalResults(str);
516523
});
517524
}
518-
else if (scope.getRemoteDataFunction) {
519-
getResourceResults(str);
525+
else if (scope.remoteApiHandler) {
526+
getRemoteResultsWithCustomHandler(str);
520527
} else {
521528
getRemoteResults(str);
522529
}
@@ -570,6 +577,9 @@
570577
if (scope.localData) {
571578
processResults(scope.localData, '');
572579
}
580+
else if (scope.remoteApiHandler) {
581+
getRemoteResultsWithCustomHandler('');
582+
}
573583
else {
574584
getRemoteResults('');
575585
}

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angucomplete-alt",
3-
"version": "0.0.40",
3+
"version": "0.0.41",
44
"homepage": "http://ghiden.github.io/angucomplete-alt/",
55
"authors": [
66
"Hidenari Nozaki <hidenari@gmail.com>"

dist/angucomplete-alt.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angucomplete-alt",
3-
"version": "0.0.40",
3+
"version": "0.0.41",
44
"description": "Awesome Autocompleteness for AngularJS",
55
"author": "ghiden",
66
"email": "hidenari@gmail.com",

test/angucomplete-alt.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,32 @@ describe('angucomplete-alt', function() {
395395
$httpBackend.verifyNoOutstandingRequest();
396396
});
397397

398+
it('should process via custom handler', inject(function($http) {
399+
var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-api-handler="postFn" search-fields="name" title-field="name" remote-url-data-field="data" minlength="1"/>');
400+
var url = '/api';
401+
$scope.postFn = function(str, timeout) {
402+
return $http.post(url, {q: str}, {timeout: timeout});
403+
};
404+
$compile(element)($scope);
405+
$scope.$digest();
406+
407+
var queryTerm = 'j';
408+
var results = {data: [{name: 'john'}]};
409+
$httpBackend.expectPOST('/api', {q: queryTerm}).respond(200, results);
410+
411+
var inputField = element.find('#ex1_value');
412+
var eKeyup = $.Event('keyup');
413+
eKeyup.which = queryTerm.charCodeAt(0);
414+
inputField.val(queryTerm);
415+
inputField.trigger('input');
416+
inputField.trigger(eKeyup);
417+
expect(element.isolateScope().searching).toBe(true);
418+
$timeout.flush();
419+
$httpBackend.flush();
420+
421+
expect(element.find('.angucomplete-row').length).toBe(1);
422+
}));
423+
398424
it('should url encode input string', function() {
399425
var element = angular.element('<div angucomplete-alt id="ex1" placeholder="Search names" selected-object="selected" remote-url="names?q=" search-fields="name" remote-url-data-field="data" title-field="name" remote-url-error-callback="errorCB" minlength="1"/>');
400426
$scope.errorCB = jasmine.createSpy('errorCB');

0 commit comments

Comments
 (0)