Search code examples
javascriptdjangopreventdefaultdjango-autocomplete-light

javascript preventDefault() being ignored


so I have tried to find a solution to my issue, but it seems unique to the other preventDefault() questions I have seen on SO and Google. It also may be a bit too narrow, but if anyone has any debugging tips, those would be appreciated, too.

I have a site that shows different video "bookmarks" to users who can click on them and change the video / seekTo time playing in a div on the page. There are 3 places a user can do this. On the left is a menu showing the "top 10 most recently viewed videos", on the right is a D3.js based topology tree, and at the top there is a search box built off of django-autocomplete-light. All three methods use the same javascript function (playvid) to change the video and update metadata information on the webpage. For example, a user clicks a link and is taken go minute 4 of Video 1, then clicks another link and is taken to minute 9 of Video 45.

When I implemented this on my development machine, all three methods worked with FF 18 and Safari 6 (Django 1.4.3, Python 2.7.3, running Django's web server). Then I put it onto a production server (Django 1.4.3, Python 2.6.6, Apache / mod_wsgi). Now the method with django-autocomplete-light's search box doesn't work, but the other two, do! I assume the different Python versions shouldn't be the culprit...? The autocomplete code was the same as my development code, but now it seems like some sort of javascript problem with preventDefault()? After hours of debugging though, I cannot figure out where and why, since the code seems to just ignore my e.preventDefault(); call...here is my /navigation_autocomplete/script.html code that captures what a user clicks within the autocomplete search box (although I feel like the issue is javascript, not specifically this Django module):

{% load url from future %}

<script type="text/javascript">
$(document).ready(function() {
    $('#navigation_autocomplete').yourlabsAutocomplete({
        url: '{% url 'navigation_autocomplete' %}',
        choiceSelector: 'a',
    }).input.bind('selectChoice', function(e, choice, autocomplete) {
        e.preventDefault();
        e.stopImmediatePropagation();
        var URL = choice.attr('href');
        alert('this should not follow the link!!');
        playvid(URL);
        return false;
    });
});
</script>

The alert() pops up in FF and Safari, and using Firebug, I can see that the browser tries to load playvid() but then follows the link--e.preventDefault(); is completely ignored. As you can see, I tried to stop the bubbling, too (getting desparate), but no luck.

Does anyone have any ideas on why my preventDefault() code might be ignored in this one specific method, but it works fine in my other calls (especially when it worked fine in development for all 3 methods)? Or debugging tips on how to track this down?

Thanks!

===========

Update

I tried jpic's solution, but it doesn't work...here is the new block of code (maybe I fat fingered something...):

<script type="text/javascript">
$(document).ready(function() {
    $('#navigation_autocomplete a').on('click', function(e) {e.preventDefault(); });
    $('#navigation_autocomplete').yourlabsAutocomplete({
        url: '/video_search/navigation/',
        choiceSelector: 'a',
    }).input.bind('selectChoice', function(e, choice, autocomplete) {
        var URL = choice.attr('href');
        alert('this should not follow the link!!');
        playvid(URL);
        return false;
    });
});
</script>

Solution

  • A fuzzy implementation

    Your code prevents default for selectChoice, but not for click !

    Autocomplete objects trigger selectChoice on the input element when a choice is selected either via mouse or keyboard. It does not mess with the click event. If you don't want browser default click event, then why use <a> ?

    Alternative implementation suggestion

    You could make an autocomplete template like this:

    {% for video in video_qs %}
    <span class="div choice" data-href="{{ video.get_absolute_url }}">{{ video }}</span>
    {% endfor %}
    

    With such js:

    <script type="text/javascript">
    $(document).ready(function() {
        $('#navigation_autocomplete')
            .yourlabsAutocomplete({
                url: '{% url 'navigation_autocomplete' %}',
                choiceSelector: '.choice',
            }).input.bind('selectChoice', function(e, choice, autocomplete) {
                playvid(choice.data('href'));
            });
    });
    </script>
    

    This simplicity by design is my favorite feature in django-autocomplete-light.

    Fixing the fuzzy implementation anyway

    If you really need unclickable <a> tags, then you could use jQuery on(), ie:

    $('#navigation_autocomplete').on('click', 'a', function(e) { e.preventDefault(); });
    

    Example:

    <script type="text/javascript">
    $(document).ready(function() {
        $('#navigation_autocomplete')
            .on('click', 'a', function(e) { e.preventDefault(); })
            .yourlabsAutocomplete({
                url: '{% url 'navigation_autocomplete' %}',
                choiceSelector: 'a',
            }).input.bind('selectChoice', function(e, choice, autocomplete) {
                var URL = choice.attr('href');
                playvid(URL);
            });
    });
    </script>