Bootstrap Typeahead with AJAX source (not working) - ajax

I'm trying to implement a search bar dropdown using bootstrap v3.0.0 with typeahead.js.
My search bar will take a student's firstname and lastname. I'm using a MYSQL database which consists of a table called practice with afirstname, alastname, aid as columns. The search bar should not only contain the firstname and lastname in the dropdown, but also the id associated with it in a second row. I've read all the examples on the typeahead.js page and I'm unable to do it with ajax call.
Below is the code of my index.php
JS
<script type="text/javascript">
$(document).ready(function() {
$('.cr.typeahead').typeahead({
source: header: '<h3>Select</h3>',
name: 'accounts',
source: function (query, process) {
return $.getJSON(
'localhost/resultly/source.php',
{ query: query },
function (data) {
return process(data);
});
});
});
</script>
HTML:
<body>
<div class="container">
<br/><br/>
<input type="text" name="query" class="form-control cr typeahead" id="firstname" />
<br/><br/>
</div>
</body>
Code for source.php : This should return the firstname and lastname from my database in the form of a json string or object?
<?php
$query = $_POST['query'];
try {
$conn = new PDO('mysql:host=localhost;dbname=practice','root','');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
$stmt->execute();
}
catch (PDOException $e) {
echo 'ERROR:' . $e->getMessage();
}
foreach ($stmt as $row) {
$afirstname[] = $row['afirstname'];
$alastname[] = $row['alastname'];
}
echo json_encode($afirstname);
echo json_encode($alastname);
?>
result:
http://oi41.tinypic.com/50moi1.jpg
Nothing shows up. I've tried adding a prefetch:
prefetch: {
url: 'localhost/resultly/source.php',
filter: function(data) {
r1 = [];
for (var i = 0; i < data.length; i++) {
r1.push({
value: data[i].afirstname,
tokens: [data[i].afirstname, data[i]alastname],
afirstname: data[i].afirstname,
alastname: data[i].alastname,
template: '<p>{{afirstname}} - {{alastname}}</p>',
});
}
return r1;
}
}
Please do provide a solution or an example which I could refer.
Update:
The source.php should return a list of json encoded data. I debugged by looking at the output that the source.pho created. What I did wrong was whenever I was supposed to put a url I did localhost/source.php instead of just source.php.
Solution provided by Bass Jobsen works and now I have run into another problem.
I'm using
if(isset($_POST['query']))
{ $q_uery = $_POST['query'];
$query = ucfirst(strtolower($q_uery))};
to take the user's data and use it for searching logic
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
The updated source.php is http://pastebin.com/T9Q4m10g
I get an error on this line saying Notice: Undefined variable: stmt I guess the $query is not being initialized. How do I get this to work. Thanks.
Update 3
I used prefetch: instead of 'remote:' that did all the matching.

Your return is not correct:
echo json_encode($afirstname);
echo json_encode($alastname);
See for example Twitter TypeAhead.js not updating input
Try echo json_encode((object)$stmt);, see: typeahead.js search from beginng
Update
I tried echo json_encode((object)$stmt);still doesn't work.
Do you use any kind of debugging? What does? source.php return? Try to follow the steps from
typeahead.js search from beginng without the filter.
html:
<div class="demo">
<input class="typeahead" value="" type="text" spellcheck="off" autocomplete="off" placeholder="countries">
</div>
javascript:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10
});
php (source.php):
<?php
$people = array();
$people[] = array("lastname"=>"Inaw",
"firstname"=>"Dsajhjkdsa");
$people[] = array("lastname"=>"Dsahjk",
"firstname"=>"YYYsgbm");
$people[] = array("lastname"=>"Dasjhdsjka",
"firstname"=>"JHJKGJ");
$datums = array();
foreach($people as $human)
{
$datums[]=(object)array('value'=>$human['firstname'],'tokens'=>array($human['firstname'],$human['lastname']));
}
echo json_encode((object)$datums);
This should work
update2
Thanks, it worked. How do I display 2 or more 'value'?
add some values to your datums in source.php:
foreach($people as $human)
{
$datums[]=(object)array
(
'value'=>$human['firstname'],
'tokens'=>array($human['firstname'],$human['lastname']),
'firstname'=>$human['firstname'],
'lastname'=>$human['lastname']
);
}
firstname and lastname now are field you csn use in your templates
Add a template and template engine to your javascript declaration:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10,
template: [
'<p>{{firstname}} - {{lastname}}</p>'
].join(''),
engine: Hogan
});
The above make use of https://github.com/twitter/hogan.js. You will have to include the template engine by javascript, for example:
<script src="http://twitter.github.io/typeahead.js/js/hogan-2.0.0.js"></script>

It is working for me. please follow below step.
Please add below Js and give proper reference.
bootstrap3-typeahead
--- Ajax Call ----
$("#cityId").keyup(function () {
var al = $(this).val();
$('#cityId').typeahead({
source: function (valuequery, process) {
var states = [];
return $.ajax({
url: http://localhost:4000/GetcityList,
type: 'POST',
data: { valueType: "", valueFilter: valuequery },
dataType: 'JSON',
success: function (result) {
var resultList = result.map(function (item) {
states.push({
"name": item.Value,
"value": item.Key
});
});
return process(states);
}
});
},
});
});
---- Cs Code ---
public JsonResult SearchKeyValuesByValue(string valueType, string valueFilter)
{
List<KeyValueType> returnValue = SearchKeyValuesByValue(valueType, valueFilter);
return Json(returnValue);
}
Auto suggest of Bootstrap typehead will get accept only "name" and "value" so create reponse accordinly

Related

my code does not safe different pages in my db

js:
$('#sortable').sortable({
stop: function(event, ui) {
saveContentOrder();
}
});
function saveContentOrder()
{
const idsInOrder = $("#sortable").sortable("toArray");
var data = {
idsInOrder:idsInOrder
};
$.ajax({
type: "POST",
url: "/xxx/yyy/zzz",
data: data
}).done( function() {
}).fail(function() {
});
}
index.blade.php:
<tbody id="sortable" >
#foreach ($references as $index => $reference)
<tr id="reference_id_{{$reference->id}}">
<td width="65%">
<a href="{{ route('admin.reference.edit', $reference->id ) }}"><b>{{ $reference->title }}</b>
</a><br>
</td>
<td>
#if(!count($reference->images))<span style="color:#ff0000;font-weight:700;">0</span>#else{{ count($reference->images) }}#endif
</td>
<td>
{{ $reference->priority }}
my webroute:
Route::post('/xxx/yyy/zzz', 'AdminReferenceController#reorder');
my Controller:
public function reorder(Request $request)
{
$order = $request->get('idsInOrder',[]);
if (is_array($order))
{
foreach($order as $position => $idName)
{
$id = str_replace("reference_id_","",$idName);
$gesamt = Reference::all()->count();
$c = \App\Reference::find($id);
if($c)
{
$c->priority = $gesamt-$position;
$c->save();
}
}
}
when i am on my first page it saves the position and priority change that i drag and drop.but when i go to the second page for example and drag and drop the order it gives the same priority as in page 1. which means it displays thinks first that should be 20th or 30th. i basically want it to be on the right order all the time. i have a show 10, show 30, and show 100. when i for example get to the show 30 and i have no pages since i dont have so many entries right now it works without issues. but as soon as i go to show 10 and got 3 pages the priority gets mixed up. how can i fix this
this is js File:
$('#sortable').sortable({
update: function(event, ui) {
saveContentOrder();
}
});
function saveContentOrder()
{
const idsInOrder = $(this).sortable("serialize");
var data = {
idsInOrder:idsInOrder
};
$.ajax({
type: "POST",
url: "/xxx/yyy/zzz",
data: data
}).done( function() {
}).fail(function() {
});
}
this is controller file
public function reorder(Request $oRequest)
{
//$oRequest->idsInOrder get all orders positiion ids.affter drag
data like,
//orders[]=6&orders[]=5&orders[]=3&orders[]=4&orders[]=2&orders[]=1
parse_str($oRequest->idsInOrder);
$nCount = 1;
foreach($orders as $order)
{
// update database order
$nCount++;
}
return Response::json(['success' => true]);
}

Jhipster generator doesn't generate filter panel in UI

I am using jhipster to generate CRUD for my web application.
by configuring jdl generator I expect to see search panel in UI for each entity. But it just generates EntityQueryService classes in backend,it works fine
and it is reachable in swagger-ui in the API docs page
Is there any UI library thing to help me pass parameters as expected format or any predicate filter panel ?
Thanks.
Finally I addded manual search panel as below :
<div class="container-fluid">
<div class="row">
<jhi-alert-error></jhi-alert-error>
<div class="col-sm-4">
<label for="field_billOrgType">organization</label>
<select id="field_billOrgType" ng-model="vm.searchModel.billOrgType">
<option ng-repeat="x in vm.Utilities" value="{{x.key}}">{{x.name}} - {{x.key}}</option>
</select>
</div>
</div>
</div>
My controller:
( function () {
'use strict';
angular
.module('ebppApp')
.factory('TmpBill', TmpBill);
TmpBill.$inject = ['$resource'];
function TmpBill($resource) {
var resourceUrl = 'api/tmp-bills/:id';
return $resource(resourceUrl, {}, {
'search': {
method: 'GET'
, isArray: true
, url: 'api/tmp-bills?:billOrgType',
params: {
billOrgType: '#billOrgType'
}
}
}
});
} })();
function search() {
TmpBill.search({
billOrgType: vm.searchModel.billOrgType ? "billOrgType.equals=" + vm.searchModel.billOrgType : ''
page: vm.page - 1,
size: vm.itemsPerPage,
sort: sort()
}, onSuccess, onError);
function sort() {
var result = [vm.predicate + ',' + (vm.reverse ? 'asc' : 'desc')];
if (vm.predicate !== 'id') {
result.push('id');
}
return result;
}
function onSuccess(data, headers) {
vm.links = ParseLinks.parse(headers('link'));
vm.totalItems = headers('X-Total-Count');
vm.queryCount = vm.totalItems;
vm.tmpBills = data;
// vm.page = pagingParams.page;
}
function onError(error) {
AlertService.error(error.data.message);
}
}

How to populate Kendo Upload with previously uploaded files

I'm using the Kendo UI File Upload for MVC and it works great. On my edit page, I want to show the files that were previously uploaded from the Create page. For visual consistency, I would like to re-use the upload widget on my edit page so the user can use the "remove" functionality, or add additional files if they choose. Does the upload widget support this?
Thanks!
So, I realize this is question pretty old, but I recently figured out how to do this reliably. While the other answer on here will certainly display the files, it doesn't really wire it up to any of the events (specifically the "remove" event). Also, rather than manually setting all of this up, I figured I'd much rather have Kendo do all of the real dirty work.
Note, this only applies if your file upload is not set to autosync. If you use the auto upload feature, you can find examples in the Kendo documentation here: http://docs.kendoui.com/api/web/upload#configuration-files
So anyway, let's assume we have a file input that we've made into a Kendo Upload:
<input id="files" name="files" type="file" multiple="multiple" />
$(document).ready(function () {
var $upload = $("#files");
var allowMultiple = Boolean($upload.attr("multiple"));
$upload.kendoUpload({
multiple: allowMultiple,
showFileList: true,
autoUpload: false
});
}
Then, we just need to get the information about the files to our jQuery. I like to jam it into JSON strings in hidden fields, but you can do it however you want.
Here's an example using the Mvc HtmlHelpers and Newtonsoft's JSON.NET (I don't use Razor, but you should get the general idea):
if (Model.Attachments.Count > 0)
{
var files = Model.Attachments.Select(x => new { name = x.FileName, extension = x.FileExtension, size = x.Size });
var filesJson = JsonConvert.SerializeObject(files);
Html.Render(Html.Hidden("existing-files", filesJson));
}
Note, the format there is incredibly important. We're tying to match the structure of the JavaScript object that Kendo is expecting:
{
relatedInput : sourceInput,
fileNames: [{ // <-- this is the collection we just built above
name: "example.txt",
extenstion: ".txt",
size: 1234
}]
}
So, then all that's left to do is put it all together. Basically, we're going to recreate the onSelect function from Kendo's internal syncUploadModule:
$(document).ready(function () {
// setup the kendo upload
var $upload = $("#files");
var allowMultiple = Boolean($upload.attr("multiple"));
var upload = $upload.kendoUpload({
multiple: allowMultiple,
showFileList: true,
autoUpload: false
}).getKendoUpload();
// initialize the files
if (upload) {
var filesJson = $("[name$='existing-files']").val();
if (filesJson) {
var files = JSON.parse(filesJson);
var name = $.map(files, function (item) {
return item.name;
}).join(", ");
var sourceInput = upload._module.element.find("input[type='file']").last();
upload._addInput(sourceInput.clone().val(""));
var file = upload._enqueueFile(name, {
relatedInput : sourceInput,
fileNames : files
});
upload._fileAction(file, "remove");
}
}
});
And that's pretty much it!
I came up with a way to do this.
Basically, you need HTML that mimics what the Upload control generates, and you use a bit of JavaScript to hook each item up. I initially render the HTML as hidden, then after you initialize the Kendo Upload control, you append the HTML list to the parent container that Kendo creates.
This is my MVC view:
#if (Model.Attachments != null && Model.Attachments.Count > 0)
{
<ul id="existing-files" class="k-upload-files k-reset" style="display: none;">
#foreach (var file in Model.Attachments)
{
<li class="k-file" data-att-id="#file.Id">
<span class="k-icon k-success">uploaded</span>
<span class="k-filename" title="#file.Name">#file.Name</span>
<button type="button" class="k-button k-button-icontext k-upload-action">
<span class="k-icon k-delete"></span>
Remove
</button>
</li>
}
</ul>
}
and here is the JavaScript (note, it was generated from CoffeeScript):
var $fileList, $files, item, _fn, _i, _len;
$fileList = $("#existing-files");
if ($fileList.length > 0) {
$(".k-upload").append($fileList);
$files = $(".k-file");
_fn = function(item) {
var $item, fileId, filenames;
$item = $(item);
fileId = $item.data("att-id");
filenames = [
{
name: fileId
}
];
return $item.data("fileNames", filenames);
};
for (_i = 0, _len = $files.length; _i < _len; _i++) {
item = $files[_i];
_fn(item);
}
$fileList.show();
}
You can find the full write up on my blog where I go into depth on the topic. I hope this helps you!
Some additional searches gave me the answer I wasn't looking for - According to this and this, Telerik does not support pre-populating an upload widget with previously uploaded documents.
It has been added in the options since this question has been asked.
Check out http://docs.telerik.com/kendo-ui/api/web/upload#configuration-files
It only works in async mode.
Try this...
#(Html.Kendo().Upload()
.Name("files")
.Async(a => a
.Save("SaveFile", "Home")
.Remove("RemoveFile", "Home")
.AutoUpload(true))
.Files(files =>
{
foreach (var file in Model.FundRequest.Files)
{
files.Add().Name(file.Name).Extension(Path.GetExtension(file.Name)).Size((long)file.SizeKb * 1024);
}
}))
My Model has a reference to my "FundRequest" object that has a List of "File" objects, so I just loop through each "File" and add.
Check this out!
<script>
var files = [
{ name: "file1.doc", size: 525, extension: ".doc" },
{ name: "file2.jpg", size: 600, extension: ".jpg" },
{ name: "file3.xls", size: 720, extension: ".xls" },
];
$("#upload").kendoUpload({
async: {
saveUrl: "Home/Save",
removeUrl: "Home/Remove",
autoUpload: true
},
files: files
});
</script>
<input type="file" name="files" id="upload" />
Check this out, this is it.
Below code is copied and adapted from kendo-ui documentation:
<div id="example">
<div>
<div class="demo-section">
<input name="files" id="files" type="file" />
</div>
</div>
<script>
$(document).ready(function () {
if (sessionStorage.initialFiles === undefined) {
sessionStorage.initialFiles = "[]";
}
var initialFiles = JSON.parse(sessionStorage.initialFiles);
$("#files").kendoUpload({
showFileList: true,
multiple: true,
async: {
saveUrl: "save",
autoUpload: false,
batch: true
},
files: initialFiles,
success: onSuccess
});
function onSuccess(e) {
var currentInitialFiles = JSON.parse(sessionStorage.initialFiles);
for (var i = 0; i < e.files.length; i++) {
var current = {
name: e.files[i].name,
extension: e.files[i].extension,
size: e.files[i].size
}
if (e.operation == "upload") {
currentInitialFiles.push(current);
} else {
var indexOfFile = currentInitialFiles.indexOf(current);
currentInitialFiles.splice(indexOfFile, 1);
}
}
sessionStorage.initialFiles = JSON.stringify(currentInitialFiles);
}
});
</script>
</div>

Load JavaScript when partial is called via ColorBox?

It seems when loading a Razor partial view via ColorBox (not using an iframe), the JavaScript libraries do not initialize properly or it is an artifacte of the partial. If I include the libraries in the parent page, the JavaScript function runs inside the partial jsut fine. I don't see any errors coming from the browser when the library is in the partial, but it is not working. If I move the library (in this case fileuploader.js) outside of the partial and keep the function in the partial it works fine.
Example:
<script src="#Url.ContentArea("~/Scripts/plugins/ajaxUpload/fileuploader.js")" type="text/javascript"></script>
<div id="file-uploader">
<noscript>
<p>
Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
<script>
$(function () {
var fileCount = 0;
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/Admin/Avatar/AvatarUpload',
debug: true,
params: {
'userId': '#ViewBag.UserId'
},
onSubmit: function (id, fileName) {
fileCount++;
},
onComplete: function (id, fileName, responseJson) {
if (responseJson.success) {
if (createAvatar(responseJson.file, responseJson.imageId)) {
fileCount--;
} else {
fileCount--;
}
} else {
$("span.qq-upload-file:contains(" + fileName + ")").text(responseJson.errorMessage);
fileCount--;
}
if (fileCount == 0) {
.....
}
},
onCancel: function (id, fileName) {
fileCount--;
if (fileCount == 0) {
....
}
}
});
});
<script>
You may want to check whether there are duplicate references to the JavaScript libraries you are using (one in the parent and one in the partial).
This is a common issue and it will not raise any errors whatsoever, but will stop your JavaScript code from executing.
I think this is a time line problem.Before the "Partial View" load(or appending the div) JavaScript try to bind it and fail.So it cannot find a element which is in your Partial View document.I had a problem with like this with "ColorBox".I have found a solution for this problem.For example : When you call GET or POST method ,after the query put a control point like this .For example for binding "colorbox" :
function getMyPartial(partialname) {
var resultDiv = document.getElementById("content");
$.ajax({
type: "GET",
url: partialname,
async: false,
success: function (data) {
resultDiv.innerHTML = "";
resultDiv.innerHTML = data.toString();
}
});
var indd = 0; //This is Control Point
if (partialname == "YourPartialName") {
var yourelementinpartial= document.getElementById("example");
while (!yourelementinpartial) {
indd++;
}
$(".group4").colorbox({ rel: 'group4' }); //binding point
}
}
At the control point, if any of the element in your PartialView document has found it will bind.

In Backbone Collection, delete a model by link on itself

Im just trying to delete a model from a collection, with a link on itself.
I've attach the event to the "Eliminar button" but it seems Im losing the reference to the model element that contains it... and can't find it.. can you?:
(function ($) {
//Model
Pelicula = Backbone.Model.extend({
name: "nulo",
link: "#",
description:"nulo"
});
//Colection
Peliculas = Backbone.Collection.extend({
initialize: function (models, options) {
this.bind("add", options.view.addPeliculaLi);
this.bind("remove", options.view.delPeliculaLi);
}
});
//View
AppView = Backbone.View.extend({
el: $("body"),
initialize: function () {
this.peliculas = new Peliculas( null, { view: this });
//here I add a couple of models
this.peliculas.add([
{name: "Flying Dutchman", link:"#", description:"xxxxxxxxxxxx"},
{name: "Black Pearl", link: "#", description:"yyyyyyyyyyyyyy"}
])
},
events: {"click #add-movie":"addPelicula", "click .eliminar":"delPelicula"},
addPelicula: function () {
var pelicula_name = $("#movieName").val();
var pelicula_desc = $("#movieDesc").val();
var pelicula_model = new Pelicula({ name: pelicula_name },{ description: pelicula_desc });
this.peliculas.add( pelicula_model );
},
addPeliculaLi: function (model) {
var str= model.get('name').replace(/\s+/g, '');
elId = str.toLowerCase();
$("#movies-list").append("<li id="+ elId +"> " + model.get('name') + " <a class='eliminar' href='#'>Eliminar</a> </li>");
},
delPelicula: function (model) {
this.peliculas.remove();
console.log("now should be triggered the -delPeliculaLi- event bind in the collection")
},
delPeliculaLi: function (model) {
console.log(model.get('name'));
$("#movies-list").remove(elId);
}
});
var appview = new AppView;
})(jQuery);
And my html is:
<div id="addMovie">
<input id="movieName" type="text" value="Movie Name">
<input id="movieDesc" type="text" value="Movie Description">
<button id="add-movie">Add Movie</button>
</div>
<div id="lasMovies">
<ul id="movies-list"></ul>
</div>
There are several things in this code that won't work. Your major problem here is that you don't tell your collection which model to remove. So in your html you have to assign so unique id that later will identify your model.
// set cid as el id its unique in your collection and automatically generated by collection
addPeliculaLi: function (model) {
$("#movies-list").append("<li id="+ model.cid +"> <a href="+ model.get('link')+">" +
model.get('name') + "</a> <a class='eliminar' href='#'>Eliminar</a> </li>"
);
},
// fetch and delete the model by cid, the callback contains the jQuery delete event
delPelicula: function (event) {
var modelId = this.$(event.currentTarget).attr('id');
var model = this.peliculas.getByCid(modelId);
this.peliculas.remove(model);
// now the remove event should fire
},
// remove the li el fetched by id
delPeliculaLi: function (model) {
this.$('#' + model.cid).remove();
}
If there aren't other errors that I have overlooked your code should work now. This is just a quick fix. Maybe you should have a look at the todos example of Backbone to get some patterns how to structure your app.
http://documentcloud.github.com/backbone/examples/todos/index.html

Resources