autocomplete + elasticsearch + symfony2 - symfony

I'm on symfony 2.2 + FoqElasticaBundle
I try to use autocomplete from a result query elasticsearch
<input type="text" class="span3" id="search" data-provide="typeahead" data-items="4" />
var subjects = ['PHP', 'MySQL', 'SQL', 'PostgreSQL', 'HTML', 'CSS', 'HTML5', 'CSS3', 'JSON'];
$('#search').typeahead({source: subjects})
autocomplete works like this, but...
How to get my elasticsearc url replace the subjects like this?
var subjects = "http://myhost:9200/_search?pretty=true";
I want that the source of my autocomplete is the result of my query elasticsearch

With typeahead you can use the data coming from the server like:
function search() {
$('#search').typeahead({
source: function (query, process) {
return $.get("{{path("url_to_fetch_from_server", {_format: "json"})}}", { "query" : query }, function (data) {
return process(data);
});
}
});
};
$(function(){
search();
});
As you can see the typeahead source function take 2 arguments.
query is the text type in the typeahead box. you need to pass this to the server
process is the callback.
The server should response back in JSON format. you can replace "{{path("url_to_fetch_from_server", {_format: "json"})}}" to your real url.
public function queryAction(){
$query = $this->getRequest()->query->get("query");
$gType = $this->container->get('foq_elastica.finder.search_db');
$results = $gType->find($query, 20);
$tools = [];
foreach($results as $result){
$tools[] = $result->getTool();
}
return new Response(json_encode($tools));
}

Related

Razor #Html.ActionLink not getting passed control value correctly

I am new to Razor. I am making good progress on this project but have hit a major road block with something that would seem to be easy. I have read a lot of posts about how to pass the value of a control as a parameter to a controller in order to redirect to a new view. The problem is that I either get the value passed to the controller but can't redirect OR I redirect and the parameter is not passed.
This is my latest attempt. I was hoping to pass the return of GetSelectedEmail to the controller (the value of "selectedEmail"). I can see that the Javascript is getting the correct value and the controller is being called, but the value is always NULL.
#Html.ActionLink("Get Scoring Report...", "History", "Student", null, new { onclick = "return GetSelectedEmail();" });
<select id="selectedEmail" name="align">
#foreach( var s in Model.Students )
{
<option id=#s.Email>#s.Email</option>
}
</select>
function GetSelectedEmail() {
var str = "new {email=" + $("#selectedEmail").val() + "}";
return str;
}
The controller...
public ActionResult History(string email, string sort)
{
string localEmail="";
if ( email == null || email == "" )
localEmail = AccountProfile.CurrentUser.UserName;
...
I have also tried to call the controller with Ajax like below. The controller does get the "selectedEmail" parameter but the page never redirects. I just does nothing. I tried both having the action link with the link parameters or not (show below).
#Html.ActionLink("Get Scoring Report...", "", "", null, new { onclick = "return GetSelectedEmail();" });
<select id="selectedEmail" name="align">
#foreach( var s in Model.Students )
{
<option id=#s.Email>#s.Email</option>
}
</select>
function GetSelectedEmail() {
$.ajax({
url: '/Student/History',
data: { email: $("#selectedEmail").val(), sort: "CaseID" },
type: 'POST',
dataType: 'json',
});
return true;
}
Any ideas?
Your first approach is not actually doing the redirection. ( also it calls a different method, which i am assuming a copy paste mistake)
Your current code is not passing the values because it is a link and when it is clicked, it is supposed to navigate to that url, which is exactly what it is doing.
I just changed the code to use unobtrusive javascript. Replaced the onclick with an id for the link
#Html.ActionLink("Get Scoring Report", "History", "Student", null, new { id="score" });
and when the click happens on this link, read the value of the select element and navigate to the second action method by setting the location.href property value
$(function () {
$("#score").click(function(e) {
e.preventDefault(); // Stop the normal redirection
var url = $(this).attr("href"); //Get the url to action method
url += "?email=" + $("#selectedEmail").val(); //append querystrings
window.location.href = url; // redirect to that url
});
});
For what I needed the solution was simple.
Show Student Scores
<select id="selectedEmail" name="align">
#foreach( var s in Model.Students )
{
<option id="#s.Email">#s.LastName,#s.FirstName</option>
}
</select>
And the Javascript magic...
function GetScoreHistory() {
var emailVal = $('#selectedEmail').find('option:selected').attr('id');
var url = '#Url.Action("History", "Student")';
url += "?email=" + escape(emailVal);
window.location.href = url;
}
The controller was called exactly how I needed it to be called.

Meteor mongodb insert document of an array

This code has the server insert some documents in a collection for the client to find it later.
I need to return the array for a given task
But the page is saying
No data received
Why is that and how to fix it? Thanks
//Both
FooterButtons2 = new Mongo.Collection('footerButtons2');
//Server
Meteor.publish('footerButtons2', function(){
return FooterButtons2.find();
});
FooterButtons2.insert(
{ "task1": ["submit"]},
{ "task2": ["cancel","continue"]}
);
//client
Meteor.subscribe('footerButtons2');
var res = FooterButtons2.findOne("task1");
When you search like this:
var res = FooterButtons2.findOne("task1");
you are searching an object that has the "_id" key equal to "task1", this is not correct.
You want the object that has the key "task1" in it. The correct way would be:
var res = FooterButtons2.findOne({
task1: { $exists: true }
});
But ideally, you should be doing searches based on values and not keys. Something like this:
FooterButtons2.insert({
task: "task1",
buttons: ["submit"]
}, {
task: "task2",
buttons: ["cancel", "continue"]
});
var res = FooterButtons2.findOne({
task: "task1"
});

$scope issue on ngGridEventEndCellEdit event when i rollback data

I probably misunderstood something but here is my problem on plunker.
I put the relevant code here anyway:
var app = angular.module('myApp', ['ngGrid']);
app.controller('MyCtrl', function($scope) {
var cellNameEditable =
'<cell-template model=COL_FIELD input=COL_FIELD entity=row.entity></cell-template>';
var cellNameDisplay =
'<div class="ngCellText" ng-class="col.colIndex()">{{row.getProperty(col.field)}}</div>';
$scope.myData= [{"id":1,"code":"1","name":"Ain"},{"id":2,"code":"2","name":"Aisne"},{"id":3,"code":"3","name":"Allier"},{"id":4,"code":"5","name":"Hautes-Alpes"},{"id":5,"code":"4","name":"Alpes-de-Haute-Provence"},{"id":6,"code":"6","name":"Alpes-Maritimes"},{"id":7,"code":"7","name":"Ardèche"},{"id":8,"code":"8","name":"Ardennes"},{"id":9,"code":"9","name":"Ariège"},{"id":10,"code":"10","name":"Aube"}];
$scope.gridOptions = {
data: 'myData',
multiSelect: false,
enableCellSelection: true,
enableRowSelection: false,
enableCellEditOnFocus: false,
rowHeight: 100,
columnDefs: [
{field:'id', displayName:'Id', visible: false},
{field:'code', displayName:'Code', enableCellEdit:true},
{
field:'name', displayName:'Name', enableCellEdit:true,
cellTemplate: cellNameDisplay,
editableCellTemplate: cellNameEditable
}
]
};
});
app.directive('cellTemplate', function () {
var cellTemplate =
'<div><form name="myForm" class="simple-form" novalidate>' +
'<input type="text" name="myField" ng-input="localInput" ng-model="localModel" entity="entity" required/>' +
'<span ng-show="myForm.myField.$error.required"> REQUIRED</span>' +
'localModel = {{localModel}} localInput = {{localInput}} entity = {{entity}}' +
'</form></div>';
return {
template: cellTemplate,
restrict: 'E',
scope: {
localModel:'=model',
localInput:'=input',
entity:'=entity'
},
controller: function ($scope) {
$scope.$on('ngGridEventStartCellEdit', function (event) {
console.log('cellTemplate controller - ngGridEventStartCellEdit fired');
$scope.oldEntity = angular.copy(event.currentScope.entity);
$scope.oldValue = angular.copy(event.currentScope.localModel);
});
$scope.$on('ngGridEventEndCellEdit', function(event) {
console.log('ngGridEventEndCellEdit fired');
if(event.currentScope.myForm.$valid) {
if(!angular.equals($scope.oldEntity, event.currentScope.entity)) {
alert('data saved !');
}
} else {
$scope.localModel = angular.copy($scope.oldValue);
$scope.localInput = angular.copy($scope.oldValue);
$scope.entity = angular.copy($scope.oldEntity);
}
});
}
};
});
Then explanations:
I have a ng-grid and based on the official example named "Excel-like Editing
Example" but with enableCellEditOnFocus option turned to false.
The cell "name" is defined in a directive containing a form to handle
data validation before updating the model.
I want to implement this behavior: When a user put invalid data, the
directive display error message and when the user leave the field, the
directive rollback data. If everything ok then I let the data updated.
The rollback part does not work. On the given plunker line 67 to 72 (last block on the code given here) it
fails to retore data. But my binding is with "=" so it should. Or maybe
because I am on the ngGridEventEndCellEdit event it breaks the links ?
I really don't understand why it fail.
So to reproduce my issue: enter in modification on a name cell, delete
all the data, REQUIRED is shown, then go out from the cell -> model is
not rolled back.
If you use a custom template, you should emit ngGridEventEndCellEdit event.

How to implement Full Text Search in Meteor/Telescope

I have attempted implementing search in Telescope using pure javascript, since it looks like FTS is a while off for Meteor to implement and I couldn't get 2.4 playing nicely with Meteor yet.
I'm using the existing pagination model that is already implemented in Telescope to display the Top/New/Best posts, plus a Session variable for the search keyword that is set in the Router when you navigate to e.g. /search/foobar.
However, it doesn't quite seem to be working; when I have, say, 100 posts, the regular paginated subscription only comes back with 25 of these and my search results only show the posts in the first 25.
I've been banging my head against a wall for days trying to debug this one: sometimes it works, sometimes it doesn't!
Here's the code (I've included all additional search code for reference):
app.js:
var resultsPostsSubscription = function() {
var handle = paginatedSearchSubscription( 10, 'searchResults' );
handle.fetch = function() {
return limitDocuments( searchPosts( Session.get( 'keyword' ) ), handle.loaded() );
};
return handle;
};
var resultsPostsHandle = resultsPostsSubscription();
paginated_sub.js:
I duplicated the existing paginatedSubscription because I can't pass a Session var in as an arg; it needs to be dynamic. I'll probably refactor later.
paginatedSearchSubscription = function (perPage/*, name, arguments */) {
var handle = new PaginatedSubscriptionHandle(perPage);
var args = Array.prototype.slice.call(arguments, 1);
Meteor.autosubscribe(function() {
var subHandle = Meteor.subscribe.apply(this, args.concat([
Session.get( 'keyword' ), handle.limit(), function() { handle.done(); }
]));
handle.stop = subHandle.stop;
});
return handle;
}
search.js: (new file, in /common directory)
// get all posts where headline, categories, tags or body are LIKE %keyword%
searchPosts = function( keyword ) {
var query = new RegExp( keyword, 'i' );
var results = Posts.find( { $or: [ { 'headline': query }, { 'categories': query }, { 'tags': query }, { 'body': query } ] } );
return results;
};
publish.js:
Meteor.publish( 'searchResults', searchPosts );
posts_list.html:
<template name="posts_results">
{{> posts_list resultsPostsHandle}}
</template>
posts_list.js:
Template.posts_results.resultsPostsHandle = function() {
return resultsPostsHandle;
};
router.js:
there's a search bar in the nav that redirects to here
posts_results = function( keyword ) {
Session.set( 'keyword' , keyword );
return 'posts_results';
};
Meteor.Router.add({
...
'/search/:keyword':posts_results,
...
})
Any help would be greatly appreciated!
A little late but here is a full write up on how to implement full text search in meteor.
"The simplest way without editing any Meteor code is to use your own mongodb."

Get /collection/id in backbone without loading the entire collection

Is there a way to load a single entity of a Backbone collection (from the server)?
Backbone.Collection.extend({
url: '/rest/product'
});
The following code can load the entire collection with a collection.fetch() but how to load a single model? Backbone's documentation says clearly that GET can be done /collection[/id] but not how.
The model has to be declared that way:
Backbone.Model.extend({
url: function() {
return '/rest/product/'+this.id;
}
});
Using it is simple as:
var model = new ProductModel();
model.id = productId;
model.fetch({ success: function(data) { alert(JSON.stringify(data))}});
While we set
url:"api/user"
for the collection, the equivalent for the model is
urlRoot:"api/user"
this will make backbone automatically append the /id when you fetch()
collection.fetch( {data: { id:56 } } )
I did this:
Catalog.Categories.Collection = Backbone.Collection.extend({
fetchOne : function (id, success) {
var result = this.get(id);
if (typeof result !== 'undefined') {
console.log(result, 'result')
success.apply(result);
return;
}
var where = {};
where[this.model.prototype.idAttribute] = id;
var model = new this.model(where);
this.add(model);
console.log(this._idAttr, where, this.model)
model.fetch({success: function () {
success.apply(model);
}});
}
};
Now call it:
collection.fetchOne(id, function () {console.log(this)});
No more guessing if the model is already in the collection!. However, you have to use a call back as you can't depend on an intimidate result. You could use async false to get around this limitation.
just .fetch a Model.
So create a model with it's own .url function.
Something like
function url() {
return "/test/product/" + this.id;
}
I did this:
var Product = Backbone.Model.extend({});
var Products = Backbone.Collection.extend({
model: Product,
url: '/rest/product'
});
var products = new Products();
var first = new Product({id:1});
first.collection = products;
first.fetch();
This has the advantage of working when you're not using a REST storage engine (instead, using something like the HTML5 Local storage, or so forth)

Resources