3

This question has been asked before, and I think I've done what I've seen there, but I don't really know what I'm doing wrong. I don't know a lot about jQuery, but I'll do my best to explain what I'm trying to do.

I want to autocomplete based on a query from a database, so I have this in my template:

<script type="text/javascript">
    $(function() {
        $( "#function_name" ).autocomplete({
            source: '{{url_for("autocomplete")}}',
            minLength: 2,
        });
    });
</script>

<form id="function_search_form" method="post" action="">
    {{form.function_name}}
</form>

The form is generated by this Flask form class:

class SearchForm(Form):
    function_name = TextField('function_name', validators = [Required()])

And here is the autocomplete function:

@app.route('/autocomplete')
def autocomplete():
    results = []
    search = request.args.get('term')
    results.append(db.session.query(Table.Name).filter(Table.Name.like('%' + search + '%')).all())
    return dumps(results)

So the jQuery should go to the autocomplete function and get some JSON back to autocomplete with. At least I think that's what's going on. What am I doing wrong here?

miscsubbin
  • 511
  • 1
  • 5
  • 16
  • @morphyn Yeah. It's called function_name. I even checked the HTML generated by Flask and it's correct. EDIT: It seems that comment has disappeared. Oh well. – miscsubbin Jun 28 '13 at 13:44
  • Hi miscsubbin, I am trying implement this autocomplete feature but I am not able to do so. I tried your method as well and tried the solution provided below. but I am facing problem in getting value in request.args.get('term'). Its always null for me. Dont know whats happening. It would be great if you can provide your working code snippet. Thanks in advance. – Pradeepb Dec 30 '15 at 20:08

2 Answers2

3

Update:

autocomplete doesn't handle the Ajax request automatically if you give it a URL, you must do it manually:

$(document).ready(function() {
    $.ajax({
        url: '{{ url_for("autocomplete") }}'
    }).done(function (data) {
        $('#function_name').autocomplete({
            source: data,
            minLength: 2
        });
    });
}

You might have to modify the way you handle the returned data, depending on what your API returns.

Update 2:

The result of your query on the server side looks like this:

[[["string1"], ["string2"], ... ["stringn"]]]

You can flatten it before sending it:

import itertools
flattened = list(itertools.chain.from_iterable(result[0]))

But you could probably improve your query to return a list of strings directly. You will need to post the whole code if you want help with that.

Martin Maillard
  • 2,751
  • 19
  • 24
  • The autocomplete function actually works fine. If I go to 127.0.0.1:5000/autocomplete?term=something, I will receive the appropriate JSON. My table is called something else, but for the purpose of the question, it's not really needed. Also, the reason I used `results.append` and `results = []`, is that I use a slightly more complex query that involves a loop, but that's not the problem I'm having. – miscsubbin Jun 28 '13 at 13:58
  • OK, my next guess is that you probably cannot give the URL directly in the `source` parameter of the `autocomplete` function. You probably have to do the Ajax request manually. I will update my answer to give an example. – Martin Maillard Jun 28 '13 at 14:09
  • So it's currently actually GET'ing from my function. I've changed my function a bit to just return every name in JSON. I'm still not getting any autocomplete though. Is there a way I should format the response made by Flask? How should I go about doing that? – miscsubbin Jun 28 '13 at 14:47
  • Did you use my code ? If yes, could you try to `console.debug(data)` in the handling js function to see what the JSON looks like ? I think `autocomplete` just wants a list (array) of strings. – Martin Maillard Jun 28 '13 at 14:55
  • Hmm, data is of the form `[[["string1"], ["string2"], ... ["stringn"]]]` which I am assuming is the incorrect type. What would be a good way to format this correctly? – miscsubbin Jun 28 '13 at 15:27
  • The best way would be to format it on the server side. That's why I told you not to do `result.append` in my first answer. It would also be possible on the client though. I will update my answer to add a way to do it. – Martin Maillard Jun 28 '13 at 16:37
  • That did it. I actually don't know js or jQuery, so thanks a lot. I'm going to probably learn them in the near future and fix this up to be a little nicer, but for now this worked. Thanks again! – miscsubbin Jun 28 '13 at 17:03
2

You actually don't even need a request to make this work! Using standard jquery-ui autocomplete, you can throw your possible items into a jinja variable and then:

<script type="text/javascript">
$('#search_form').autocomplete({
    source: JSON.parse('{{jinja_list_of_strings | tojson | safe}}'),
    minLength: 2,
    delay: 10,
});
</script>

This is really handy if the items are tied to current_user, as in Flask-Login.

<script type="text/javascript">
$('#search_form').autocomplete({
    source: JSON.parse('{{current_user.friends | map(attribute="name") | list | tojson | safe}}'),
    minLength: 2,
    delay: 10,
});
</script>
Nolan Conaway
  • 2,639
  • 1
  • 26
  • 42