I'm trying to implement an autocomplete feature using Elasticsearch, angularJS and bootstrap.
I've got inspired by this solution :
autocomplete/typeahead angularjs bootstrap on elasticsearch
This is my Angular code:
angular.module('cineAngularApp')
.service('client', function (esFactory) {
return esFactory({
host: 'localhost:9200',
apiVersion: '2.2',
log: 'trace'
});
});
angular.module('cineAngularApp')
.controller('AutocompleteCtrl', function ($scope,client) {
$scope.getResult = function(val){
return client.search({
index: 'autocomplete_test',
fields: 'city',
q: 'city:'+val
}).then(function (resp) {
var keywords = [];
for(var i in resp.hits.hits){
var fields = (resp.hits.hits[i]).fields["city"];
keywords.push(fields);
}
return keywords;
}, function (err) {
console.trace(err.message);
});
};
});
Here is my problem
The above code works fine when I use a simple query, but as soon as I change the query by adding body it doesn't work.
angular.module('cineAngularApp')
.controller('AutocompleteCtrl', function ($scope,client) {
$scope.getResult = function(val){
return client.search({
index: 'autocomplete_test',
fields: 'city',
body: {
query: {
match: {
city: val
}
}
}
}).then(function (resp) {
var keywords = [];
for(var i in resp.hits.hits){
var fields = (resp.hits.hits[i]).fields["city"];
keywords.push(fields);
}
return keywords;
}, function (err) {
console.trace(err.message);
});
};
});
I don't know if it can help but I've also noticed when debugging that it's not a POST request anymore but it's an OPTION one.
Thanks in advance for your help.
Try with this:
return client.search({
index: 'movies',
"fields": [ "title" ],
"body": { // Use body field on elasticsearch client library
"query": {
"query_string": {
"fields": ["title"],
"query": "title:"+val
}
}
}
}).then(function (resp) {
// ....
})
Related
I'm trying to send by post a json with restangular but this don't return me anything.
Code:
$scope.userPost = {
title: 'foo',
body: 'bar',
userId: 1
}
$scope.registerUser=function(){
$scope.people = Restangular.all('post').post($scope.userPost);
console.log($scope.people);
}
It return me this:
{ "restangularCollection": false, "$object": {} }
http://jsonplaceholder.typicode.com/post 404 (Not Found)
Usually I use this with ajax and it return me a json:
$.ajax('http://jsonplaceholder.typicode.com/posts', {
method: 'POST',
data: {
title: 'foo',
body: 'bar',
userId: 1
}
}).then(function(data) {
console.log(data);
});
Any ideas ?
Restangular works with promises, so, you should be doing something like:
$scope.registerUser = function () {
Restangular.all('post').post($scope.userPost).then((data) => {
$scope.people = data;
console.log($scope.people);
});
}
Or you can take advantage of its enhanced promises and do something like:
$scope.registerUser = function () {
$scope.people = Restangular.all('post').post($scope.userPost).$object;
}
In Angular 4+
constructor(private restangular: Restangular){}
// latter in your method
const baseUsers = this.restangular.all('post');
baseUsers.post({'title':'foo','body': 'bar','userId': '1'})
.subscribe(data => { console.log(data); });
I intend to return few resource from a factory, but unfortunately it failed in my case. It shows the error message Entry is not a function Scope.$scope.create.
This is working code with one resource:
angular.module('Entry').factory('Entry', function($resource) {
return $resource('/api/entries/:id', { id: '#_id' }, {
update: {
method: 'PUT'
}
});
});
$scope.create = function() {
var entry = new Entry({
});
entry.$save(function() {});
}
This is not working code after adding multiple resource:
angular.module('Entry').factory('Entry', function($resource) {
return {
'EntryA': $resource('/api/entries/:id', { id: '#_id' }, {
update: {
method: 'PUT'
}
}),
'EntryB': $resource('/api/entries/:id', { id: '#_id' }, {
update: {
method: 'PUT'
}
}),
};
});
$scope.create = function() {
var entry = new Entry({
});
entry.EntryA.$save(function() {});
}
I tried to create an item on the API and return a value with new 'ScheduleID', When I did a trace, API does return a new ScheduleID in the newly created object, but ScheduleID is never saved in the dataSource. Anyone know why?
vm.schedulerOptions = {
date: new Date(classStartDate.getUTCFullYear(), classStartDate.getUTCMonth(), classStartDate.getUTCDate(), 0, 0, 0),
height: 600,
views: [
"day",
{type: "week", selected: true},
],
dataSource: {
transport: {
read: function (options) {
if ($stateParams.classId) {
scheduleDf.getScheduleByClassId($stateParams.classId).success(function (result) {
options.success(result);
}).error(function (err) {
options.error(err);
})
} else if ($stateParams.sectionId) {
scheduleDf.getScheduleBySectionId($stateParams.sectionId).success(function (result) {
options.success(result);
}).error(function (err) {
options.error(err);
})
}
},
create: function (options) {
options.data.ClassId = classInfor.data[0].ClassID;
options.data.AtLocationId = vm.locationCb.dataItem().LocationID;
options.data.ConfirmationNumber = vm.ConfirmationNumber;
scheduleDf.createSchedule(options.data).success(function (result) {
//vm.grid.dataSource.read();
options.success(result);
}).error(function (err) {
options.error(err);
})
},
update: function (options) {
if (!fromMovingBar) {
options.data.AtLocationId = vm.locationCb.dataItem().LocationID;
fromMovingBar = false;
}
scheduleDf.updateSchedule(options.data).success(function (result) {
vm.grid.dataSource.read();
options.success(result);
}).error(function (err) {
options.error(err);
})
},
destroy: function (options) {
scheduleDf.deleteSchedule(options.data.ScheduleID).success(function (result) {
vm.grid.dataSource.read();
options.success();
}).error(function (err) {
options.error(err);
})
}
},
schema: {
model: {
id: "ScheduleID",
fields: {
start: {type: "date", from: "FromTime"},
end: {type: "date", from: "ToTime"}
}
}
}
},
editable: {
template: '<div ng-include="' + "'/schedule/_schedule_editor.html'" + '"></div>',
create: false
},
edit: function (e) {
e.container.data("kendoWindow").center();
e.container.find(".k-edit-form-container").width("auto");
e.container.data("kendoWindow").wrapper.css({width: 700});
},
moveEnd: function (e) {
fromMovingBar = true;
},
resizeEnd: function (e) {
fromMovingBar = true;
},
resources: [{
field: 'SessionTypeID',
dataColorField: 'ColorCode',
dataValueField: 'SessionTypeID',
dataTextField: 'SessionTypeName',
dataSource: sessionTypes.data
}]
};
The reason for current behavior is that the response from the server is not formatted the same way as the "read" request. You should try to insert the record inside array. For more info you can check this help article.
Also I notice that the Scheduler have no timezone option set. Please note that the timezone option is highly recommended to be set - for more details you can check the new Timezones help article.
I have following service method with return statement.
this.partnersListForAutocomplete = function (container, options) {
$("#autocompletePartners").kendoAutoComplete({
dataSource : {
type: "json",
serverFiltering: true,
transport: {
read: function (options) {
console.log("List");
console.log(options.data);
requestParams = {
"entityName": "dvd",
"page": 1,
"pageSize": 20,
"filter": options.data.filter,
"sort": [
{
"field": "name",
"ord": "asc"
}
]
};
ApiService.doHttpRequest(
"POST",
$rootScope.apiBaseUrl + "partner/search",
requestParams
)
.success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
}
}
},
dataTextField: "name" ,
dataValueField: "id",
filter: "contains",
minLength: 1,
change : function (e) {
// I WANT RETURN IT
return "test";
},
select : function (e) {
// I WANT RETURN IT
return "test";
}
});
};
Which is called by this code from controller method:
selectedPartnerId = GlobalHelperService.partnersListForAutocomplete();
$scope.projectDetail.test = selectedPartnerId;
Problem is that returned value is not passed into selected scope.
How can i solve it please?
Note: Method for autocomplete is assync.
Thanks for any help.
You have a couple of options that I can think of from the top of my head:
You could return a promise from the partnersListForAutocomplete() method, and then inside your controller you would then do something like the following pseudocode:
GlobalHelperService.partnersListForAutocomplete()
.then(function(response) {
$scope.projectDetail.test = response;
});
Or, accept a callback to your partnersListForAutocomplete() method, and then inside your controller you would then do something like the following pseudocode:
GlobalHelperService.partnersListForAutocomplete(function(response) {
$scope.projectDetail.test = response;
});
I have few resources written on AngularJS that access a Tastypie API. Everything works fine, except for a detail: tastypie always encapsulate the actual result inside a objects attribute on a JSON, example:
/api/v1/reminder/:
{
meta: {
limit: 20,
next: null,
offset: 0,
previous: null,
total_count: 3
},
objects: [{
category: {
color: "#999999",
id: 1,
name: "Groceries",
resource_uri: "/api/v1/category/1"
},
description: "",
due_date: "2010-10-16",
id: 1,
repeat: "weekly",
resource_uri: "/api/v1/reminder/1",
value: "-50"
}, {
category: {
color: "#999999",
id: 1,
name: "Groceries",
resource_uri: "/api/v1/category/1"
},
description: "",
due_date: "2010-10-17",
id: 2,
repeat: "weekly",
resource_uri: "/api/v1/reminder/2",
value: "-50"
}
}
It was wasy to fix using a callback to the get() call:
Reminder.get().$then(function (result) {
$scope.reminders = result.data.objects;
});
But I know result.resource is an actual Reminder instance.
.factory('Reminder', ['$resource', function($resource){
var Reminder = $resource('/api/v1/reminder/:id', {}, {
get: {
method: 'GET',
isArray: false
}
});
Reminder.prototype.TESTE = function () {console.log('asd');};
return Reminder;
}])
Now I need to implement behavior on my Reminder class, and I need every element on my meta.objects to be an instance of Reminder:
Reminder.get().$then(function (result) {
$scope.reminders = result.data.objects;
result.resource.TESTE(); // -> outputs 'asd'
o = result.data.objects[0];
o.TESTE // -> undefined, obvisously
i = new Reminder(o);
i.TESTE() // -> outputs 'asd'
});
So, how to I get angularjs to understand that every object on objects is the actual result so it behaves like a list of instances?
The workaround is to creating a new list iterating on the results creating the instances, but it's not optimal...
Suggestions?
Solution by #rtcherry:
As suggested by rtcherry, I used restangular
Configuring the reading of request data:
.config(['RestangularProvider', function(RestangularProvider) {
RestangularProvider.setBaseUrl("/api/v1");
RestangularProvider.setResponseExtractor(function(response, operation, what, url) {
var newResponse;
if (operation === "getList") {
newResponse = response.objects;
newResponse.metadata = response.meta;
} else {
newResponse = response.data;
}
return newResponse;
});
}])
Loading the reminders:
function RemindersCtrl ($scope, $rootScope, Reminder) {
$scope.reminders = Reminder.getList();
}
Adding my custom method to Reminder (not as clean as ngResource, but doable):
.factory('Reminder', ['Restangular', '$filter', function(Restangular, $filter){
var Reminder = Restangular.all('reminder');
var remainingDays = function () {
//do stuff
};
// adding custom behavior
Restangular.addElementTransformer('reminder', false, function (reminder) {
reminder.remainingDays = remainingDays;
return reminder;
});
return Reminder;
}])
Solution by #moderndegree:
I used pure ngResource:
var tastypieDataTransformer = function ($http) {
return $http.defaults.transformResponse.concat([
function (data, headersGetter) {
var result = data.objects;
result.meta = data.meta;
return result;
}
])
};
...
.factory('Reminder', ['$resource', '$http', function($resource, $http){
var Reminder = $resource('/api/v1/reminder/:id', {}, {
query: {
method: 'GET',
isArray: true,
transformResponse: tastypieDataTransformer($http)
}
});
Reminder.prototype.remainingDays = function () {
// doing stuff
};
return Reminder;
}])
My controller:
Transaction.query(filter).$then(function (result) {
$scope.days = [];
var transactions = result.resource;
resource[0].remainingDays(); // it works
});
If you wanted to avoid using an additional library, you should be able to do the following:
$resource('/api/v1/reminder/', {}, {
query: {
method: 'GET',
isArray: true,
transformResponse: $http.defaults.transformResponse.concat([
function (data, headersGetter) {
return data.objects;
}
])
}
});
This will append your transform to $HttpProvider's default transformer.
Note: Correct me if I'm wrong on this one but I believe this feature requires v1.1.2 or greater.
You may want to try something like restangular.
There is some configuration needed to make that work. An example is here.
I ended up doing the following in order to preserve the meta object directly on the results returned by Reminder.query() (expanding on the answer from #moderndegree).
var Reminder = $resource('/api/v1/reminder/', {}, {
query: {
method: 'GET',
isArray: true,
transformResponse: $http.defaults.transformResponse.concat([
function (data, headersGetter) {
return data.objects;
}
]),
interceptor: {
response: function(response) {
response.resource.meta = response.data.meta;
}
}
}
});
That allows you to get the meta value directly on the returned object:
var reminders = Reminder.query(...);
console.log(reminders.meta); // Returns `meta` as expected.
I think it would also be possible to do something similar inside the callback from Reminder.query since the response object is available there as well.