For my final project (a website where people can write diaries and read others' diaries), I am trying to implementing a search box where the user may search usernames to read others' diaries, so I took what I learned from Problem Set 8 to write up this drop-down search box, but the drop-down part is not working.
Application.py
@app.route("/search", methods=["GET", "POST"])
@login_required
def search():
"""Search published diaries from others."""
# if user reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# ensure friends' usernames were submitted
if not request.form.get("search"):
return dumbo("No username entered")
# search user's friends from database
# append % to q so that user doesn't have to input city/state/postal code in the URL completely/accurately
# https://www.tutorialspoint.com/sqlite/sqlite_like_clause.htm
friend = request.form.get("search") + "%"
searches = db.execute("SELECT username FROM writers WHERE username LIKE :friend", friend=friend)
# output a JSON array of objects, each represents a row from TABLE writers that matches what the user looks for
return jsonify(searches)
# else if user reached route via GET (as by clicking a link or via redirect)
else:
return render_template("search.html")
scripts.js
$("#friend").keydown(function() {
// configure typeahead
$("#friend").typeahead({
// If true, when suggestions are rendered, pattern matches for the current query in text nodes
// will be wrapped in a strong element with its class set to {{classNames.highlight}}. Defaults to false.
highlight: false,
// The minimum character length needed before suggestions start getting rendered. Defaults to 1.
minLength: 1
},
{
display: function(suggestion) { return null; },
limit: 5,
source: search,
templates: {
suggestion: Handlebars.compile(
"<div>" +
"<div>{{username}}</div>" +
"</div>"
)
}
});
// action after friend is selected from drop-down
$("#friend").on("typeahead:selected", function(eventObject, suggestion, name) {
// visit friend's diaries (to be continued)
});
});
/**
* Searches database for typeahead's suggestions.
*/
// search calls asyncResults after searching is done (asynchronously)
function search(query, syncResults, asyncResults)
{
// get usernames matching query (asynchronously)
var parameters = {
friend: $("#friend").val()
};
$.getJSON(Flask.url_for("search"), parameters)
.done(function(data, textStatus, jqXHR) {
// call typeahead's callback with search results (i.e., friends)
asyncResults(data);
})
.fail(function(jqXHR, textStatus, errorThrown) {
// log error to browser's console
console.log(errorThrown.toString());
// call typeahead's callback with no results
asyncResults([]);
});
}
search.html
{% extends "layout.html" %}
{% block title %}
Search
{% endblock %}
{% block main %}
<form action="{{ url_for('search') }}" method="post">
<fieldset>
<div class="form-group">
<input autocomplete="off" autofocus class="typeahead" id="friend" name="search" placeholder="Search friends" type="text"/>
</div>
<div class="form-group">
<button class="btn btn-default" type="submit">Search</button>
</div>
<!-- https://www.mkyong.com/javascript/how-to-link-an-external-javascript-file/ -->
<script type="text/javascript" src="static/scripts.js"></script>
</fieldset>
</form>
{% endblock %}
I looked at Link1 and Link2, but those do not seem fit here given that I have to access the database in the server to complete the entire search action.
Here is my layout.html:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta -->
<meta charset="utf-8"/>
<meta content="initial-scale=1, width=device-width" name="viewport"/>
<!-- http://getbootstrap.com/ -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<!-- app's own CSS -->
<link href="{{ url_for('static', filename='styles.css') }}" rel="stylesheet"/>
<!-- http://jquery.com/ -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<!-- http://getbootstrap.com/ -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- https://github.com/corejavascript/typeahead.js/blob/master/doc/jquery_typeahead.md -->
<script src="https://cdn.rawgit.com/corejavascript/typeahead.js/master/dist/typeahead.jquery.js"></script>
<!-- http://handlebarsjs.com/ -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>
<!-- http://stewartjpark.com/Flask-JSGlue/ -->
{{ JSGlue.include() }}
<!-- app's own JavaScript -->
<script src="{{ url_for('static', filename='scripts.js') }}"></script>
<title>FoToM: {% block title %}{% endblock %}</title>
</head>
<body>
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button aria-expanded="false" class="navbar-toggle collapsed" data-target="#navbar" data-toggle="collapse" type="button">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ url_for('.index', username=session.get('user_username')) }}"><span class="blue">F</span><span class="yellow">o</span><span class="blue">T</span><span class="yellow">o</span><span class="blue">M</span>
</div>
<div class="collapse navbar-collapse" id="navbar">
{% if session.user_id %}
<ul class="nav navbar-nav">
<li><a href="{{ url_for('.news', username=session.get('user_username')) }}">News</a></li>
<li><a href="{{ url_for('.write', username=session.get('user_username')) }}">Write</a></li>
<li><a href="{{ url_for('.search', username=session.get('user_username')) }}">Search</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="{{ url_for('.reenter', username=session.get('user_username')) }}">Reset Password</a></li>
<li><a href="{{ url_for('logout') }}">Log Out</a></li>
</ul>
{% else %}
<ul class="nav navbar-nav navbar-right">
<li><a href="{{ url_for('register') }}">Register</a></li>
<li><a href="{{ url_for('login') }}">Log In</a></li>
</ul>
{% endif %}
</div>
</div>
</nav>
{% if get_flashed_messages() %}
<header>
<div class="alert alert-info" role="alert">
{{ get_flashed_messages() | join(" ") }}
</div>
</header>
{% endif %}
<main>
{% block main %}{% endblock %}
</main>
</div>
</body>
</html>
Please advise, thank you!