views:

597

answers:

3

Initial caveat: I am a newbie to jquery and javascript.

I started using the autocomplete jquery plugin recently from bassistance.de. Yesterday, I found the fcbkListSelection plugin (http://www.emposha.com/javascript/fcbklistselection-like-facebook-friends-selector.html) and am using it to include a selector in my application.

What I now want to do is to merge the 2 pieces of functionality since there are lots of items in my selector list. To be more specific, I want to put a "Filter by Name" text box above the facebook list selection object in my html. When the user types a few characters into the "Filter by Name" text box, I want the items in the Facebook list selector to only show the items that contain the typed characters -- kind of like what autocomplete does already, but rather than the results showing below the text input box, I want them to dynamically update the facebook list object.

Is this possible and relatively straightforward? If so, can somebody please describe how to do it? If not, is there an easier way to approach this? Thanks!

OK, to Spencer Ruport's comment, I guess I may have a more specific question already. Below is the current Javascript in my HTML file (angle brackets represent Django tags). #suggest1 and #fcbklist both do their separate pieces, but how do I get them to talk to each other? Do I need to further write javascript in my HTML file, or do I need to customize the guts of the plugins' .js? Does this help elaborate?

$(document).ready(function() { var names = []; var count = 0; {% for a, b, c in friends_for_picker %} names[count] = "{{ b }}"; count = count+1; {% endfor %}

function findValueCallback(event, data, formatted) {
 $("<li>").html( !data ? "No match!" : "Selected: " + formatted).appendTo("#result");
}

function formatItem(row) {
 return row[0] + " (<strong>id: " + row[1] + "</strong>)";
}
function formatResult(row) {
 return row[0].replace(/(<.+?>)/gi, '');
}

$("#suggest1").autocomplete(names, {
 multiple: true,
 mustMatch: false,
 autoFill: true,
 matchContains: true,
});

  //id(ul id),width,height(element height),row(elements in row)        
  $.fcbkListSelection("#fcbklist","575","50","4");
});
A: 

Definitely not straightforward. Entirely possible though. I suggest you familiarize yourself with Javascript syntax and give it a shot. When you have a more specific question come back here and you'll find lots of people eager to help.

Spencer Ruport
A: 

If all you want to do is filter the fcbkListSelection items, you don't need autocomplete at all, implementing a filter is simple enough.

Following is a sample I've put together. The basic functionality is there, but a more complete solution would involve editing the the fcbkListSelection code.
E.g. Although the list is filtered as expected, when you click on an item to select/de-select it, all the items are show again which is probably undesired behaviour.
It's not as daunting as it may seem though, the plugin code is easy to understand and making adding a simple feature like this should be painless.

Hosted demo: http://jsbin.com/ubeda (Editable via http://jsbin.com/ubeda/edit)

Pertinent code:

<input id="filter"/> 
<ul id="fcbklist"></ul> 

<script> 
  var $fcbklist = $('#fcbklist'); 

  var $listItems = $fcbklist.find('li'); 

  // id (ul id), width, height (element height), row (elements in row)         
  $.fcbkListSelection($fcbklist, 570, 50, 4); 

  $('#filter').keyup(function (){ 
    var $this = $(this); 

    var val = $this.val(); 

    /*** Show all the listItems when the filter is cleared ***/ 
    if (!val) { 
      $this.data('lastVal', val); 
      $listItems.show(); 
      return; 
    } 

    var lastVal = $this.data('lastVal'); 
    $this.data('lastVal', val); 
    /*** If the filter hasn't changed, do nothing ***/ 
    if(val === lastVal) { return; } 

    /*** Hide the results of the previous filter ***/ 
    $listItems.filter(':visible').hide(); 

    /*** 
      Show only the items of the current tab that match 
      the filter. 
    ***/ 
    var $tabItems; 
    switch($(".view_on").attr("id").replace("view_","")) { 
      case "all": 
        $tabItems = $listItems; 
        break; 
      case "selected": 
        $tabItems = $listItems.filter('[addedid]'); 
        break; 
      case "unselected": 
        $tabItems = $listItems.filter(':not([addedid])'); 
        break;   
    } 
    $tabItems.filter(':icontains(' + val + ')').show(); 
  }); 

  /*** 
    This is a custom pseudo-selector that selects 
    elements whose text contains the specified substring. 
    It is case-insensitive, unlike the built-in :contains selector. 
  ***/ 
  $.extend($.expr[':'], { 
    icontains: function(elem, i, match){ 
      return (new RegExp(match[3], 'im')).test($(elem).text()); 
    } 
  }); 
</script>
brianpeiris
A: 

This is a note about the issue mentioned in the above solution by brianpeiris (which otherwise seems to work great!).

brianpeiris: "Although the list is filtered as expected, when you click on an item to select/de-select it, all the items are show again which is probably undesired behaviour."

To easily fix this, simply remove the .show() portions of the hiddenCheck function in the fcbkListSelection.js.

Example:

var hiddenCheck = function(obj) {
    switch (curTab()) {
        case "all":
            //elem.children("li").show();
            break;

        case "selected":
            elem.children("li:not([addedid])").hide();
            //elem.children("li[addedid]").show();
            break;

        case "unselected":
            elem.children("li[addedid]").hide();
            //elem.children("li:not([addedid])").show();
            break;
    }
}

Also note an issue with the original code provided by brianpeiris. It will show ALL items whenever the filter is cleared; regardless of the current selected tab. See below to fix this issue.

Replace this

/*** Show all the listItems when the filter is cleared ***/ 
if (!val) { 
  $this.data('lastVal', val); 
  $listItems.show(); 
  return; 
} 

With this

/*** Show all the listItems when the filter is cleared ***/
/*** ADDED: switch to fix error of always showing all entries ***/
if (!val) {
    $this.data('lastVal', val);
    switch ($(".view_on").attr("id").replace("view_", "")) {
        case "all":
            $listItems.show();
            break;
        case "selected":
            $listItems.filter('[addedid]').show();
            break;
        case "unselected":
            $tabItems = $listItems.filter(':not([addedid])').show();
            break;
    }
    return;
}

Updated here: http://jsbin.com/ubeda/16

Marc M