atfornes atfornes - 1 year ago 284
AngularJS Question

Render angular directives in Selectize.js items

I am using angular-selectize to use Selectize.js in my angular project.

To use custom items in Selectize.js selector, I am using Selectize.js' render option:

render: {
item: function(item, escape) {
var avatar = '<div>' +
'<span avatars="\'' + escape(item._id) +'\'" class="avatars">' +
'</span>' +
escape(item.nick) +
var compiledAvatar = $compile(avatar)($rootScope);
return compiledAvatar.html();

where avatars is a custom directive with asychronous behaviour

The problem is that the
function expects an HTML string as an output but:

  • There is no way of returning a rendered or "
    ed" HTML string in a synchronous way as expected by

  • I do not know how to render that item's elements afterwards when they have already been added to the DOM.

Note that although $compile is called, returned string would not be the expected compiled result but the string before compilation due to the asynchronous nature of $compile.

Answer Source

This answer is based in the helpful answer by @gregori with the following differences:

  1. Take into account Selectize.js' Render Cache. The standard behaviour of Selectize.js is that the items are cached as returned by the render function, and not with the modifications we have done to them. After adding and deleting some elements, the cached and not the modified version would be displayed if we do not update the render cache acordingly.
  2. Using random id's to identify the elements to select to be manipulated from DOM.
  3. Using watchers to know when the compilation has been done

First, we define a method to modify the selectize.js render cache:

scope.selectorCacheUpdate = function(key, value, type){

  var cached = selectize.renderCache[type][key];

  // update cached element
  var newValue = angular.element(cached).html(value);

  selectize.renderCache[type][key] = newValue[0].outerHTML;

  return newValue.html();

Then, the render function is defined as follows:

function renderAvatar(item, escape, type){

  // Random id used to identify the element
  var randomId = Math.floor(Math.random() * 0x10000000).toString(16);

  var avatar = 
    '<div id="' + randomId + '">' +
      '<span customAvatarTemplate ...></span>' +

  var compiled = $compile(avatar)($rootScope);

  // watcher to see when the element has been compiled
  var destroyWatch = $rootScope.$watch(
    function (){
      return compiled[0].outerHTML;
    function (newValue, oldValue){
      if(newValue !== oldValue){

        var elem = angular.element(document.getElementById(randomId));

        var rendered = elem.scope().selectorCacheUpdate(item._id, compiled.html(), type);

        // Update DOM element


return avatar;


Note: The key for the render cache is the valueField of the selectize items, in this case, _id

Finally, we add this function as a selectize render function in the selectize configuration object:

config = {
  render: {
    item: function(i,e){
      return renderAvatar(i, e, 'item');
    option: function(i,e){
      return renderAvatar(i, e, 'option');

For more details, see how this solution has been added to the application that motivated this question: