Typeahead.js JSON response not rendering - laravel-4

I'm trying to integrate Twitter Typeahead into my Laravel (4.2.11) project (with Bootstrap 2.3.2).
I have results being returned as JSON (checked with Fiddler), but a single "undefined" is always displayed instead.
If I enter a search query that doesn't return any results, the "No Results" is displayed correctly.
//Simple query in Laravel
Route::get('/sidebar/clients/{q}', function($q)
{
$companies = DB::table('ViewCompanies')->select(array('CompanyID', 'FullCompanyName'))
->where('FullCompanyName', 'like', '%'. $q .'%')->get();
return Response::json(array('companies' => $companies));
});
//Javascript in page
var clients = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('FullCompayName'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/sidebar/clients/%QUERY',
filter: function (parsedResponse) {
// parsedResponse is the array returned from your backend
console.log(parsedResponse);
return parsedResponse;
}
}
});
clients.initialize();
$('#clients .typeahead').typeahead({
hint: true,
highlight: true,
minLength: 3,
},
{
name: 'clients',
valueKey: 'CompanyID',
displayKey: 'FullCompanyName',
source: clients.ttAdapter(),
templates: {
empty: [
'<div class="tt-empty-message">',
'No Results',
'</div>'
],
header: '<h3 class="tt-tag-heading tt-tag-heading2">Matched Companies</h3>'
}
});
My console log using the above code:

what is the output of the parsedResponse you are logging? I think DB::table returns an object, not an array. Try to replace the response like this:
return Response::json(array('companies' => $companies->toArray()));
Then log the results and format them in the "filter" function in the Bloodhound object.
Hope it helps!

Thanks to Eduardo for giving me the idea of needing to parse my JSON into a JS array.
Doing a search revealed these two questions:
Twitter Typeahead.js Bloodhound remote returns undefined
Converting JSON Object into Javascript array
from which I was able to devise my one-line solution (full remove filter show):
filter: function (parsedResponse) {
console.log(parsedResponse);
var parsedResponse = $.map(parsedResponse, function(el) { return el; });
return parsedResponse;
}

Related

Vue.js 2 & Axios - Filtering an api for a search feature

I'm trying to filter through a collection of films that i'm retrieving using axios. This is so i can compare it to a search string for a search feature. Everything works fine except when using the computed property it returns Cannot read property 'filter' of undefined" but when i check the vue dev tool it says that the computed property contains the array of films which doesn't really add up. The code is as follows.
created(){
this.fetchFilms();
},
methods:{
fetchFilms(page_url){
let vm = this;
// storing the page url
page_url = page_url || '/api/films'
axios.get(page_url)
.then(response => response)
.then(response => {
this.films = response.data;
vm.makePagination(response.meta, response.links);
})
.catch(err => console.log(err));
},
makePagination(meta,links){
let pagination = {
current_page: this.films.meta.current_page,
last_page: this.films.meta.last_page,
next_page_url: this.films.links.next,
prev_page_url: this.films.links.prev
}
this.pagination = pagination;
}
},
computed: {
filteredFilms () {
return this.films.data.filter((film) => {
return film.film_name.toLowerCase().match(this.searchString.toLowerCase())
})
},
}
This is how the data is returned
films:Object
data:Array[10]
links:Object
meta:Object
Any help is appreciated.
You're probably accessing filteredFilms before the request is done. I don't see any code to wait for the request. You could make filteredFilms check if the data is there and return an empty list if it isn't.

How to correctly return html template from ajax request with Symfony

I was wondering how to return correctly an HTML template (SEO friendly) from an ajax call.
In my app, I use 2 differents ways to return response:
For simple template:
public function ajaxCallAction() {
//.....
$response = array(
"code" => 202,
"success" => true,
"simpleData" => $simpleData
);
return new JsonResponse($response);
}
And in the JS I do something like:
$("div#target").click(function(event) {
$.ajax({
type: "POST",
success: function(response) {
if(response.code === 202 && response.success) {
$("div#box").append(response.simpleData);
}
}
});
});
For complexe template (more than 20 lines and various var):
public function ajaxCallAction() {
//...
$listOfObjects = $repo->findAll();
$viewsDatas = [
'listOfObjects' => $listOfObjects,
//....other vars
];
return $this->render('myAppBundle:template:complexTemplate.html.twig', $viewsDatas);
//in complexTemplate.html.twig, I loop on listOfObjects for example...
}
And for this kind of call, the JS looks like:
$("div#target").click(function(event) {
$.ajax({
type: "POST",
success: function(response) {
$("div#box").append(response);
}
});
});
All those methods are working, but with the second one, we dont have status code (does it matter?) and I know that returning directly formated html template can be heavy (according to for example this topic Why is it a bad practice to return generated HTML instead of JSON? Or is it?).
How are you guys doing ajax calls? What are the best practices here?
In my apps, I typically use something like that:
$response = array(
"code" => 200,
"response" => $this->render('yourTemplate.html.twig')->getContent() );
Hope this help!
Edit
To return your response, you should use JsonResponseas explained in docs: http://symfony.com/doc/current/components/http_foundation.html#creating-a-json-response
Simply use that:
return new JsonResponse($response);
Try with "renderView" ;)
return $this->json([
'html' => $this->renderView('template.html.twig', []),
]);

Display result of search within view

I have a page where I display all my clients. It uses paginate and only displays 16 clients per page. As such I have provided realtime search functionality.
When a search is perform, the option selected from the results triggers the following
select: function (event, ui) {
$.ajax({
url: "/returnClient",
type: "GET",
datatype: "html",
data: {
value : ui.item.value
},
success: function(data) {
$('.container').fadeOut().html(data.html).fadeIn();
}
});
}
That essentially calls the following function
public function returnClient(Request $request)
{
if($request->ajax()){
$selectedClient = $request->input('value');
$client = Client::where('clientName', $selectedClient)->first();
$html = View::make('clients.search', $client)->render();
return Response::json(array('html' => $html));
}
}
If I output the client variable above, I can see all the details for this particular client. This is then being passed to the partial clients.search.
Within clients.search, if I do
{{dd($client)}}
I get Undefined variable: client. Why does it not get the parsed Object within the view?
Many thanks
The issue is that you are improperly passing $client to the view. The Views documentation shows how to properly pass data via an associative array. The API docs confirm that an array is what is expected.
Do this instead:
public function returnClient(Request $request)
{
if($request->ajax()){
$selectedClient = $request->input('value');
$client = Client::where('clientName', $selectedClient)->first();
$html = View::make('clients.search', ['client' => $client])->render();
return Response::json(array('html' => $html));
}
}
Also, as a point of habit you may want to consider using dump() instead of dd().

Simple ajax in laravel 4

i have following code
ajax
//ajax edit button
$('.edit_button').on('click', function(e) {
e.preventDefault();
var id_produk = $(this).attr('id');
$.ajax({
type : "POST",
url : "editproduk",
data : id_produk,
dataType: 'JSON',
success : function(data) {
alert('Success');
console.log(data);
},
error: alert('Errors')
});
});
i always get messagebox error
and don't know where i'm missing,
because in chrome - inspect element - console not give any clue
my route
Route::post('/account/editproduk', array(
'as' => 'edit-produk-post',
'uses' => 'AccountController#postEditProduk'
));
my controller
public function postEditProduk() {
if (Request::ajax()) {
return "test test";
}
}
extended question
i running my script well after using return Response::json() like this
$id_produk = Input::get('id_produk');
$produk = Produk::findOrFail($id_produk);
return Response::json($produk);
and access it in view by this script
success : function(data) {
alert('Success');
console.log(data["name-produk"]);
}
but if i want to return array json like
$id_produk = Input::get('id_produk');
$produk = Produk::findOrFail($id_produk);
$spesifikasi = SpesifikasiProduk::where('id_produk', '=', $id_produk);
return Response::json(array($produk, $spesifikasi));
i can't access it in view like this...
success : function(data1, data2) {
alert('Success');
console.log(data1["name-produk"] - data2["title-spek"]);
}
how to access json array
extended question update
if i'm wrong please correct my script
because i get a litle confused with explenation
is this correct way to return it?
Response::json(array('myproduk' => 'Sproduk', 'data2' => 'testData2'));
result
console.log(produk["myproduk"]);
--------------------------------
Object {id_produk: 1, nama_produk: "produk1", deskripsi: "desc_produk"
console.log(produk["data2"]);
--------------------------------
testData2
and i still don't have idea how to print nama_produk in my_produkarray
Question 1:
Why is this code not sending JSON data back.
public function postEditProduk() {
if (Request::ajax()) {
return "test test";
}
}
Answer: Because this is not the right way to send the JSON data back.
From the Laravel 4 docs, the right way to send JSON data back is linked. Hence the correct code becomes:
public function postEditProduk() {
if (Request::ajax()) {
return Response::json("test test");
}
}
Question 2:
Why am I not able to access the data in data1 and data2
success : function(data1, data2) {
alert('Success');
console.log(data1["name-produk"] - data2["title-spek"]);
}
Answer: Because this is not the right way to catch the JSON data. The right way to send is given in the Laravel 4 API reference docs.
static JsonResponse json(string|array $data = array(), int $status = 200, array $headers = array(), int $options)
As you can see the method json takes string or array as the first parameter. So you need to send all your data in the first parameter itself (which you are doing). Since you passed only one parameter, you have to catch only 1 parameter in your javascript. You are catching 2 parameters.
Depending on what $produk and $spesifikasi is, your data will be present in one single array. Lets say that $produk is a string and $spesifikasi is an array. Then your data on the javascript side will be this:
[
[0] => 'value of $produk',
[1] => array [
[0] => 'value1',
[1] => 'value2'
]
]
It would be best if you print the log your entire data and know the structure. Change your code to this:
success : function(data) {
console.log(data.toString());
}
This will print your entire data and then you can see the structure of your data and access it accordingly. If you need help with printing the data on your console, google it, or just let me know.
I sincerely hope that I have explained your doubts clearly. Have a nice day.
Edit
extended question answer:
Replace this line:
$spesifikasi = SpesifikasiProduk::where('id_produk', '=', $id_produk);
With this:
$spesifikasi = SpesifikasiProduk::where('id_produk', '=', $id_produk)->get();
Without calling the get() method, laravel will not return any value.
Then access your data in javascript like this:
console.log(JSON.stringify(data));
This way you will get to know the structure of your data and you can access it like:
data[0]["some_key"]["some_other_key"];
In your controller you're returning text while your ajax request awaits json data, look at these lines of codes, I think you should get your answer:
if(Request::ajax()) {
$province = Input::get('selectedProvince');
//Get all cites for a province
if ($cityList = City::where('province_id','=', $province)) {
return Response::make($cityList->get(['id', 'name']));
}
return Response::json(array('success' => false), 400);
}

Make a typeahead remote call to codeigniter controller

I want to be able to make a remote data call from bloodhound using typeahead to model with codeigniter.
So I was struggling a bit trying to get typeahead (twitter) remote data and codeigniter to work together, I dint't find a good example that fit with my needs. After a few hours I came up with the following code, hope it helps.
The View:
var proyectos = new Bloodhound({
datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.proyecto_titulo); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'proyectos/proyectos/getProyectos?query=%QUERY',
wildcard: '%QUERY'
}
});
$('#titulo').typeahead({
hint: true,
highlight: true,
minLength: 3
},
{
name: 'proyectos',
displayKey: 'proyecto_titulo',
source: proyectos.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'No se encontraron registros que coincidan con la búsqueda.',
'</div>'
].join('\n'),
suggestion: Handlebars.compile('<p>{{proyecto_titulo}} – <strong>{{tipo_proyecto_nombre}}</strong> </p>')
}
});
The relevant part here is:
remote: {
url: 'proyectos/proyectos/getProyectos?query=%QUERY',
wildcard: '%QUERY'
}
Where proyectos/proyectos is the controller path and getProyectos is the method that answers the request.
Whenever you type, and based on the minLength setting, is going to request a matching string in the back-end.
Note: In order to use the suggestion part in the templates setting, you must download the handlebars.js library.
The Controller:
public function getProyectos() {
$consulta = $this->input->get('query');
$proyectos = $this->proyectos_model->getProyectos($consulta);
if($proyectos->num_rows() > 0){
echo json_encode($proyectos->result());
}
else{
echo '';
}
}
We first get the query string from the view with $this->input->get('query') and afterwards pass it to our model.
The Model:
public function getProyectos($consulta) {
$query = $this->db->query
("select pro.proyecto_id
,pro.proyecto_titulo
,tip.tipo_proyecto_nombre
,tip.tipo_proyecto_id
from proyectos pro
inner join tipos_proyectos tip on tip.tipo_proyecto_id = pro.tipo_proyecto_id
where pro.proyecto_titulo ilike '%" . $consulta . "%' ");
return $query;
}
Here in the model we simply pass the query string to our sql select statement and we're done. The database I'm using is postgresql.
I hope you find this helpful.

Resources