Hierarchical Tag Auto Complete

by paultyng

HTML

<ul id="tag-target"></ul>
<input id="tag" style="width: 300px">

JavaScript

var rawTagData = [{"event_id":3,"id":1,"name":"Sector","parent_id":null,"position":0},{"event_id":3,"id":2,"name":"Product","parent_id":null,"position":1},{"event_id":3,"id":3,"name":"Retail","parent_id":1,"position":0},{"event_id":3,"id":6,"name":"Handheld Cutting","parent_id":2,"position":0},{"event_id":3,"id":7,"name":"Automated Cutting","parent_id":2,"position":1},{"event_id":3,"id":8,"name":"Foo","parent_id":6,"position":0},{"event_id":3,"id":10,"name":"Baz","parent_id":6,"position":1},{"event_id":3,"id":11,"name":"Foo2","parent_id":7,"position":0}];

var tagData = [];
var tagLookup = {};

$.each(rawTagData, function(i, tag) {
    tagLookup[tag.id] = tag;
});

var fullTagName = function(tag, currentName) {
    if(tag) {
        currentName = tag.name + (currentName ? ' > ' + currentName : '');
    }
    else {
        return currentName;
    }
    return fullTagName(tagLookup[tag.parent_id], currentName);
};

$.each(rawTagData, function(i, tag) {
    tagData.push({ value: tag.id, label: tag.name, fullName: fullTagName(tag) });
});

$('#tag').autocomplete({
    focus: function() { return false; },
    minLength: 0,
    select: function(event, ui) {
        $('<li>').append($('<a>').text(ui.item.fullName).attr('data-id', ui.item.value)).appendTo('#tag-target');
        
        this.value = '';
        return false;
    }, 
    source: tagData
})
.data('ui-autocomplete')._renderItem = function(ul, item) {
    return $('<li>').append($('<a>').text(item.fullName)).appendTo(ul);
};