Hello im learning Laravel and trying to make an autocompletion of search with sugestion from a database. I see a lot of people doing it with JQuery so that is what i've tried. But when i run the site, i only get one letter of suggestion, and sometimes no suggestion at all. I suspekt my routing is off so i tried dd some information in the query function, but that doesnt show up either,
MY BLADE
<!DOCTYPE html>
<html>
<head>
<title>Laravel 8 Autocomplete Search using Bootstrap Typeahead JS -ItSolutionStuff.com</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-3-typeahead/4.0.1/bootstrap3-typeahead.min.js"></script>
</head>
<body>
<div class="container">
<h1>Laravel 8 Autocomplete Search using Bootstrap Typeahead JS - ItSolutionStuff.com</h1>
<input class="typeahead form-control" type="text">
</div>
<script type="text/javascript">
var path = "{{ route('autocomplete') }}";
$('input.typeahead').typeahead({
source: function (query, process) {
return $.get(path, { query: query }, function (data) {
return process(data);
});
}
});
</script>
</body>
</html>
MY CONTROLLER
class TypeaheadController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('welcome');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function autocomplete(Request $request)
{
dd('h');
$data = Edit::select("Adresse")
->where("Adresse","LIKE","%{$request->query}%")
->get();
return response()->json($data);
}
}
MY Routing
Route::get('search', [TypeaheadController::class, 'index'])->name('search');
Route::get('autocomplete', [TypeaheadController::class, 'autocomplete'])->name('autocomplete');
If you guys have any other suggestion on how i can do it. feel free to suggest
$request->query is a reserved function on the $request object. in order to pull the '?query=xyz' from the url in the request you would have to use the $request->query('query') function to return xyz.
Related
I want to add automatic Intellisense (Auto Complete--Filtering Search Result) to a textbox, corresponding to the words that I'm typing in that textbox and the Intellisense is fetched from a database table. How can I achieve this? Can anyone help?
Here is my jQuery code:
$(document).ready(function() {
$('#city').autocomplete({
source:'send.php'
});
});
send.php file given below:
$link=mysqli_connect("localhost","hari","123","hari");
$searchTerm = $_GET['query']; //get search term
$query = $db->query("SELECT fname FROM user WHERE fname LIKE
'%".$searchTerm."%' ORDER BY fname ASC"); //get matched data from user table
while ($row = $query->fetch_assoc()) {
$data[] = $row['fname'];
}
echo json_encode($data);//return json data
Corresponding HTML Code is given below:
<div class="content col-sm-12">
<form>
<h1>Hello!!!</h1>
<input type="text" id="city" name="city" size="20" class="city"
placeholder="Please Enter City or ZIP code"><br><br>
</form>
</div>
You have to include the following scripts in your html page
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
And add the following css in head of your html
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
The mistake you made is the parameter passing with the name term and trying to read with the name query in your php file. In your send.php file change the line
$searchTerm = $_GET['query'];
into
$searchTerm = $_GET['term'];
Try this:
$(document).ready(function() {
$('#city').autocomplete({
source: function( request, response ) {
$.ajax( {
url: "send.php",
dataType: "jsonp",
data: {
query: request.term
},
success: function( data ) {
response( data );
}
} );
},
});
});
I have a recommendation for you, use angular 1 for this, you can simply write that code without additional UI libraries and with much much better performance and issue-free solution.
Add the following parent div to your input element:
Change your input to this:
<input type="text" id="city" name="city" size="20" class="city" ng-model="query" ng-change="fetch()" placeholder="Please Enter City or ZIP code">
Add the following code right under your <input>:
<ul>
<li ng-repeat="text in suggestions">{{ text }}</li>
</ul>
As a basic set up, you need this in your <head> section:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
Finally you will create a new file like in assets directory like "suggestions.js" in your assets directory or somewhere and add this file right before you your </body> tag like this in your template:
<script src="assets/suggestions.js"></script>
The file will have the following lines:
var app = angular.module('myApp', []);
app.controller('suggestionsCtrl', function($scope, $http) {
$scope.suggestions = [];
$scope.query = '';
$scope.fetch = function() {
$http({method: 'POST', url: 'send.php', params: { query: $scope.query } }).
then(function(response) {
$scope.status = response.status;
$scope.suggestions = response.data;
}, function(response) {
/* SOMETHING WENT WRONG WTIH THE CALL DO SOMETHING HERE */
});
};
});
There is very simple set-up/tutorial for Angular 1 here:
https://www.w3schools.com/angular/default.asp
This is not a direct answer but believe me a more efficient answer. Angular 1 and the newer versions save a lot of time and brings performance.
And btw, autocomplete() is not a native jQuery function. Also I do not mention that you need jQuery also for Angular, but I assume it's already added in your template.
This has probably been asked before, but after searching for awhile I'm still a bit confused. I'm trying to make a flask app but I'm not too familiar with JQuery itself, but I would like to create an autocomplete widget in my html. However, instead of querying a database I'd like to just use a static list and a regex to get results. I used this as reference.
What I did was:
#app.route('/autocomplete', methods=['GET'])
def autocomplete():
search = request.args.get('q')
#query = db_session.query(Movie.title).filter(Movie.title.like('%' + str(search) + '%'))
#results = [mv[0] for mv in query.all()]
results = ['Beer', 'Wine', 'Soda', 'Juice', 'Water']
return jsonify(matching_results=results)
while keeping the rest of the code:
<head>
<link href="//code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" rel="Stylesheet"></link>
<script src="//code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="//code.jquery.com/ui/1.10.2/jquery-ui.js" ></script>
<script type="text/javascript">
$(function() {
$("#autocomplete").autocomplete({
source:function(request, response) {
$.getJSON("{{url_for('autocomplete')}}",{
q: request.term, // in flask, "q" will be the argument to look for using request.args
}, function(data) {
response(data.matching_results); // matching_results from jsonify
});
},
minLength: 2,
select: function(event, ui) {
console.log(ui.item.value); // not in your question, but might help later
}
});
})
</script>
</head>
<body>
<div>
<input name="autocomplete" type="text" id="autocomplete" class="form-control input-lg"/>
</div>
</body>
I haven't implemented a regex but I assumed if I typed anything with at least 2 characters I would get a dropdown of the list I wrote above. However, I get nothing. Any ideas on how I can get this autocomplete to work?
I need to display data from two tables which are associated with foreign key
using angularjs in mvc. I am able repeat question but my requirement is display question with 4 options i couldnt get the solution for this, am new to angularjs,I will be thankful if anyone can help me
> Controller code :
public JsonResult displayQuestion()
{
var result = from q in Db.questions
join a in Db.answers on q.Qid equals a.questionID
select new { q.QText, q.Qid, a.answer1 };
return Json(result, JsonRequestBehavior.AllowGet);
}
> angular view code:
<html>
<head>
<meta name="viewport" content="width=device-width" />
<script src="~/Scripts/angular.min.js"></script>
<script>
var myApp = angular.module("QuestionDisplayModule", [])
.controller("QuestionDisplayController", function ($scope,$http,$log) {
$http.get("displayQuestion").then(function(response)
{
$log.info(response);
$scope.questionsData = response.data;
})
})
</script>
<title>dispaly</title>
</head>
<body ng-app="QuestionDisplayModule">
<div ng-controller="QuestionDisplayController">
<div ng-repeat="q in questionsData">
<h6>{{q.QText}}</h6>
<p><input type="radio" name="answers" ng-repeat = "a in q.answer1" />{{a.answer1}}</p>
</div>
</div>
</body>
json data result:
[
{"QText":"result of 2+2","Qid":2,"answer1":"2"},
{"QText":"result of 2+2","Qid":2,"answer1":"4"},
{"QText":"result of 2+2","Qid":2,"answer1":"6"},
{"QText":"result of 2+2","Qid":2,"answer1":"8"}
]
view result: Link
I am following the Using Kendo UI with MVC4 WebAPI OData and EF article. After installing KendoUI and making sure all references are set, I type in three characters, and get the following error:
Uncaught TypeError: Object # has no method 'slice'
Root of the Problem
To save reading through the updates: Through debugging I found that the issue is that JS is expecting to parse an array, where it isn't available in the data - at the root. In the data hierarchy, it's one level in.
Original Problem
I cleaned up kendo.web.min.js and the error is occuring around line 3498:
success: function (n) {
var i = this,
r = i.options;
return i.trigger(wt, {
response: n,
type: "read"
}), n = i.reader.parse(n), i._handleCustomErrors(n) ? (i._dequeueRequest(), t) : (i._pristine = et(n) ? e.extend(!0, {}, n) : n.slice ? n.slice(0) : n, i._total = i.reader.total(n), i._aggregate && r.serverAggregates && (i._aggregateResult = i.reader.aggregates(n)), n = i._readData(n), i._pristineData = n.slice(0), i._data = i._observe(n), i._addRange(i._data), i._process(i._data), i._dequeueRequest(), t)
The Kendo UI widgets are loading just fine as well as the css:
<link href="~/Content/kendo/kendo.common.min.css" rel="stylesheet" />
<link href="~/Content/kendo/kendo.default.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Scripts/kendo/kendo.web.min.js"></script>
<script src="~/Scripts/kendo/kendo.aspnetmvc.min.js"></script>
<script src="~/Scripts/appScripts.js"></script>
And I am seeing the same error both with using the Razor MVC helper/extension:
#(Html.Kendo().AutoComplete()
.Name("userAutoComplete") // specifies the "id" attribute of the widget
.DataTextField("USERNAME")
.DataSource(source =>
{
source.Read(read =>
{
read.Url("/api/user");
})
.ServerFiltering(true); // if true, the DataSource will not filter the data on the client
}
)
)
and through directly through JS:
/// <reference path="kendo/kendo.aspnetmvc.min.js" />
/// <reference path="kendo/kendo.core.min.js" />
/// <reference path="kendo/kendo.autocomplete.min.js" />
/// <reference path="kendo/kendo.web.min.js" />
$(document).ready(function () {
// load up KendoUI
// gets data from /api/user
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/user"
}
}
});
$("#userSearch").kendoAutoComplete({
dataSource: dataSource,
dataTextField: "USERNAME",
minLength: 3
});
$("#userSearch").on('input', function () {
console.log($("#userSearch").val());
});
}); // $(document).ready()
I'm sure this is something simple that I may be missing. I have tried both with the web and all js files.
Any assistance would be appreciated.
-- UPDATE --
The only real html missing from that content is the <input id="userAutoComplete" />
I created a brand new solution and a very simple view, based on one of the Kendo UI examples that gets JSON data from http://api.geonames.org, and getting the same error.
I thought that using the newest JS library (//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js may have been causing a problem so I tried the 1.7 lib. Same issue:
#using Kendo.Mvc.UI
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<link rel="stylesheet" href="#Url.Content("~/Content/kendo.common.min.css")">
<link rel="stylesheet" href="#Url.Content("~/Content/kendo.default.min.css")">
<link rel="stylesheet" href="#Url.Content("~/Content/kendo.dataviz.min.css")">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script src="#Url.Content("~/Scripts/kendo.web.min.js")"></script>
<script src="#Url.Content("~/Scripts/kendo.aspnetmvc.min.js")"></script>
<script src="#Url.Content("~/Scripts/kendo.dataviz.min.js")"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#autoComplete").kendoAutoComplete({
minLength: 6,
dataTextField: "title",
filter: "contains",
dataSource: new kendo.data.DataSource({
transport: {
read: {
url: "http://api.geonames.org/wikipediaSearchJSON",
data: {
q: function () {
return $("#autoComplete").data("kendoAutoComplete").value();
},
maxRows: 10,
username: "demo"
}
}
},
schema: {
data: "geonames"
}
}),
change: function () {
this.dataSource.read();
}
})
});
</script>
</head>
<body>
<div>
<input id="autoComplete"/>
</div>
</body>
</html>
-- UPDATE --
Using the code above, I went back and tried it again - it worked fine. After trying several more times, I experienced the same issue. This was due to the valid JSON data changing to the following:
{"status":{"message":"the daily limit of 30000 credits for demo has been exceeded. Please use an application specific account. Do not use the demo account for your application.","value":18}}
... which lead me to look at the formatting of the data coming from my API (looking at it in Fiddler:
Instead of:
JSON
---{... data...
it's
JSON
---$id=1
---$values
------{}
---------$id=2
---------CREATEDATETIME...
---------EMAIL=email#email.com
---------GROUPS
------------$id=...
------------$id=...
---------USERNAME=someusername
------{}
---------$id=4
.
.
.
So the error is caused by the array not being accessible where the it's expected - instead of the root, it's one level deep.
How do I get data binding to the one-level-deep rather than the root of the JSON object?
Thanks.
I had the same error with a ComboBox that I was using as an autocomplete. In my controller, the return statement was
return Json(model.ToDataSourceResult(dataSourceRequest), JsonRequestBehavior.AllowGet)
which I changed to
return Json(model, JsonRequestBehavior.AllowGet)
This provided the array at the root level instead of one level deep for me.
The solution for this was to traverse the data hierarchy by describing the result format.
Since the array is contained in $values, I used the following data source/schema definition:
// gets data from /api/user
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/user"
}
},
schema: { // describe the result format
data: function(data) { // the data which the data source will be bound to is in the values field
console.log(data.$values);
return data.$values;
}
}
});
One thing that would be nice is to be able to add a data schema type in the Razor helper - which doesn't seem to be supported at this time.
Thus, the following still would not work:
#(Html.Kendo().AutoComplete()
.Name("userAutoComplete") // specifies the "id" attribute of the widget
.Filter("startswith")
.Placeholder("Type user name...")
.DataTextField("USERNAME")
.DataSource(source =>
{
source:
source.Read(read =>
{
read.Url("/api/user");
})
.ServerFiltering(true); // if true, the DataSource will not filter the data on the client
}
)
)
This worked for me:
var dataSource = new kendo.data.DataSource({
transport: {
read:
{
url: "api/dashboard"
}
},
schema: {
**data: function (data)
{
return [data];
}**
}
});
My response wasn't an array, i was returning from the server a response object like this:
{"Field1":0,"Field2":0,"Field3":0}
thanks "brittongr"...that worked for me too. but in my case it is not right, I was building a chart, a chart need an array of course, so instead of altering the schema by converting my Json data to an array I just returned from my action a list having one element. Something like this below.
Random rand = new Random();
int numIterations = 0;
numIterations = rand.Next(1, 1200);
List aux = new List<graphicDataItem>();
aux.Add(new graphicDataItem { ColumnTotal = 1200, ColumnActives = numIterations, ColumnInactives = 1200 - numIterations, ColumnApprovedByMembers = 250, ColumnApprovedByAssoc = 300, XAxisData = DateTime.Now.Year });
return Json(aux, JsonRequestBehavior.AllowGet);
I have "graphicDataItem" type defined on my Entities folder, but is easy to get by looking at the way it is instantiated within the code.
i change for this, and this work for me:
#(Html.Kendo().AutoComplete()
.Name("productAutoComplete") //The name of the autocomplete is mandatory. It specifies the "id" attribute of the widget.
.DataTextField("myfield") //Specifies which property of the Product to be used by the autocomplete.
.DataSource(source =>
{
source.Custom()
.Type("aspnetmvc-ajax")
.Transport(transport=>
{
transport.Read("MyAction", "Control");
})
.Schema(schema=>schema.Data("Data").Total("Total"))
.ServerFiltering(true); //If true the DataSource will not filter the data on the client.
})
)
I'm working with SringMVC and I'm searching for an easy solution to load a JSP into a div box of another JSP file. I heard about using Tiles but I would prefer to use ajax/jquery. Can anyone help me with that? I'm trying to get this working for two days now...
My current approach is something like this:
$(document).ready(function() {
var html = '<jsp:include page="searchSites.jsp"/>';
$('#contentbox').load(html);
});
But this is throwing an "Uncaught SyntaxError: Unexpected token ILLEGAL" Error at the second line. I also tried c:import but this isn't working, too.
Thank you very much for your help!
Edit:
#Controller
#RequestMapping("/search")
public class SearchController {
#Autowired private SiteService siteService;
#Autowired private SystemService systemService;
#RequestMapping(value = "")
public String displaySearch(Model model) {
return "displaySearch";
}
#RequestMapping(value = "sites", method = RequestMethod.POST )
public String displaySites(Model model, #RequestParam String searchStr) {
List<RSCustomerSiteViewDTO> sites = siteService.getSitesByName(searchStr);
model.addAttribute("sites", sites);
return "searchSites";
}
#RequestMapping(value = "systems", method = RequestMethod.POST)
public String displaySystems(Model model, #RequestParam String searchStr) {
List<RSServicedSystemViewDTO> systems = systemService.getSystemsByName(searchStr);
model.addAttribute("systems", systems);
return "searchSystems";
}
}
displaySearch.jsp
<html>
<head>
<title>Site</title>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<link rel="stylesheet" href="<c:url value="resources/css/style.css" />" />
<script>
$(document).ready(function() {
var html = '/crsp/search/sites';
$('#contentbox').load(html);
});
</script>
</head>
<body>
<div id="content">
<div id="searchdiv">
<form method="POST" action="search/sites">
<input type=text name=searchStr placeholder="Search Site..."
id="searchSite" class="search" />
</form>
<form method="POST" action="search/systems">
<input type=text name=searchStr placeholder="Search System..."
id="searchSystem" class="search" />
</form>
</div>
<div id="contentbox">
</div>
</div>
</body>
</html>
searchSites.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# page session="false"%>
<table>
<tr id="header">
<td>Name</td>
<td>Customer</td>
<td>City</td>
<td>Region</td>
</tr>
<c:forEach var="site" items='${sites}' varStatus="loopStatus">
<tr class="${loopStatus.index % 2 == 0 ? 'even' : 'odd'}">
<td>${site.siteName}</td>
<td>${site.customerName}</td>
<td>${site.siteCity}</td>
<td>${site.regionName}</td>
</tr>
</c:forEach>
</table>
Edit:
I came closer. I have to fire something like this from the forms instead of the action which I got until now, then it will work: Suggestions?
function searchSites(searchStr) {
$.ajax({
type: "POST",
url: "sites?searchStr=",
success: function(data) {
$("#contentbox").html(data);
}
});
}
You should remove the JSP tag
var html = 'searchSites.jsp';
$('#contentbox').load(html);
The load method should be provided with a url that corresponds with a mapping to one of your controller methods.
Controller
#Controller
#RequestMapping("/site")
public class MyController{
#RequestMapping("/search")
public String getFragment(){
return "fragment";
}
}
Javascript
$(document).ready(function() {
var html = "/contextRoot/site/search"; //you may need to use jstl c:url for this
$('#contentbox').load(html);
});
Config
Please note this example, assumes you have a ViewResolver setup in your dispatcher configuration file as follows and there is a fragment.jsp file within the root of your WEB-INF directory:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
The basic concept of request handling in Spring MVC is that a request is "somehow" mapped to a controller method. Spring MVC provides various ways of doing this url, request type, parameter presence, parameter values, etc... But basically it boils down to which controller/method should handle this request. This is most often accomplished using #RequestMapping.
After the method is found data binding occurs, meaning that request parameters are supplied to the method as arguments. Once again there are various ways to match parameters to arguments, including path variables, modelattributes, etc...
Next the body of the method is executed, this is pretty much custom and you provide the implementation.
The next part is where you seem to be getting stuck. The controller method next tells Spring what view should be displayed. Once again there are many ways to do this, but one of the most common is to return a String at the end of your method that corresponds with a view (.jsp). Usually a view resolver is registered to avoid hardcoding the name of a view file in the returned String. The returned String is resolved by the ViewResolver and associated view is returned.
To answer your follow up question if you want to serve the displaySearch.jsp after processing a request for search/systems you simply return that viewName.
#RequestMapping(value = "systems", method = RequestMethod.POST)
public String displaySystems(Model model, #RequestParam String searchStr) {
List<RSServicedSystemViewDTO> systems = systemService.getSystemsByName(searchStr);
model.addAttribute("systems", systems);
return "displaySearch";
}