Make <a> inside jQuery autocomplete clickable

6.4k views Asked by At

I managed to add a link to the right of the jQuery autocomplete items, using the following code:

function onClientSelect(event, ui) {
    // My handling code goes here
    event.preventDefault();
}

$("#mypage input[name='client']").autocomplete({
    minLength: 1,
    appendTo: $(this).parent(),
    source: '/filter_client/',
    select: onClientSelect,
    focus: function (event, ui) {
        event.preventDefault();
    },
}).data("ui-autocomplete")._renderItem = function (ul, item) {
    return $("<li></li>")
        .data("item.autocomplete", item)
        .append("<a>" + item.label + "</a>")
        .appendTo(ul);
};

My server returns element label in this format:

<div class="ac-item-lb">My Item Label</div>
<a class="ac-item-a" href="/url_to_go_to/" target="_blank">View Detail</a>

What I want to do is to open the link in a new tab when I click on 'View Detail', which clicking any other area executes onClientSelect just like normal. However, currently left-clicking on the link also executes onClientSelect. The only way to open the link is to click the middle wheel or right mouse button and select 'open in new tab'.

I tried attaching a click event handler on the link with event.stopImmediatePropagation() but that doesn't seem to work. Does anyone have any idea how to fix this?

5

There are 5 answers

4
Amir Popovich On BEST ANSWER

One way to do it is by defining a custom select function and by not using an <a> for the links

HTML:

<div class="ui-widget">
    <label for="tags">Tags:</label>
    <input id="tags">
</div>

JS:

 var availableTags = [
    "ActionScript",
    "AppleScript",
    "Asp",
    "BASIC",
    "C",
    "C++",
    "Clojure",
    "COBOL",
    "ColdFusion",
    "Erlang",
    "Fortran",
    "Groovy",
    "Haskell",
    "Java",
    "JavaScript",
    "Lisp",
    "Perl",
    "PHP",
    "Python",
    "Ruby",
    "Scala",
    "Scheme"];

$("#tags").autocomplete({
    source: availableTags,
    select: function (event, ui) {
        var elem = $(event.originalEvent.toElement);
        if (elem.hasClass('ac-item-a')) {
            var url = elem.attr('data-url');
            event.preventDefault();
            window.open(url, '_blank ');
        }
    }
}).data("ui-autocomplete")._renderItem = function (ul, item) {
    return $("<li></li>")
        .data("item.autocomplete", item)
        .append('<a>' + item.label + '<span class="ac-item-a" data-url="http://www.nba.com"> View Details</span></a>')
        .appendTo(ul);
};

JSFIDDLE.

0
mshipov On

Try to do even.stopImmediatePropagation in onclick binding to link. Page is opening and select handler not executed.

var li = $("<li></li>")
    .data("item.autocomplete", item)
    .append('<a class="ac-item-a" href="http://www.nba.com">' + item.label + '</a>')
    .appendTo(ul);

li.find('a').bind('click', function(event){ event.stopImmediatePropagation() });

return li;
0
pseudosavant On

Have you thought about putting a conditional in your click handler to not preventDefault when it is that link? If you test if the element should function as normal then you can return early before the preventDefault and then the link should function as normal.

Here is an example (JSBin):

function clickHandler(e) {
  // If the target element has the class `test-clickable` then the
  // function will return early, before `preventDefault`.
  if (this.className.indexOf('test-clickable') !== -1) {
    return;
  }

  alert('That link is not clickable because of `preventDefault`');
  
  e.preventDefault();
}

$('a').click(clickHandler);
a {
  display: block;
}
a:after {
  content: ' [class=' attr(class)']';
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Title</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>

<body>
  <a class='test-clickable' href='http://www.google.com' target='_blank'>Link</a>
  <a class='test-not-clickable' href='http://www.google.com' target='_blank'>Link</a>
</body>

</html>

0
Elisheva Wasserman On

Amir, regarding to your answer, I think that opening window inside javascript function from select event can be blocked by PopupBlocker

pinghsien422 , your server side should return Json and not complete html , if you must return complete html, make the following changes:

1.Remove the clientSelect function

2.No 'a' tag is needed in renderData function

 $("#mypage input[name='client']").autocomplete({
   minLength: 1,
  appendTo: $(this).parent(),
   source: '/filter_client/',
  focus: function (event, ui) {
    event.preventDefault();
  },
}).data("ui-autocomplete")._renderItem = function (ul, item) {
return $("<li></li>")
    .data("item.autocomplete", item)
    .append( item.label )
    .appendTo(ul);
};
0
Ryszard Fiński On

Okay, jquery's event takes precedence over your select event - no matter what you do, you can't stop anything there. But you can proxify menuselect event and then decide if it should be invoked (jsfiddle).

var ac = $("#mypage input[name='client']").autocomplete({
    minLength: 1,
    appendTo: document.body,
    source: availableTags,
    focus: function (event, ui) {
        event.preventDefault();
    },
}).data("ui-autocomplete");
ac._renderItem = function (ul, item) {
    return $("<li></li>")
        .data("item.autocomplete", item)
    .append("<div>"+item.label+"<a class='link' href='http://test'>(http://test)</a></div>")
        .appendTo(ul);
};
var ms = $._data(ac.menu.element.get(0), 'events').menuselect[0].handler;
ac.menu.element.off("menuselect");
ac.menu.element.on("menuselect", function (ev) {
    if($(ev.originalEvent.target).hasClass("link"))
        return;
    ms.apply(this,arguments);
});