2012-08-29 7 views
21

Extendí el booteo-typeahead para tomar un objeto en lugar de una cadena.
Funciona, pero me gustaría saber que esta es la manera correcta de hacer las cosas.Extienda el encabezado de bootstrap-type para tomar un objeto en lugar de una cadena

Gracias.

Referencia:
http://twitter.github.com/bootstrap/javascript.html#typeahead http://twitter.github.com/bootstrap/assets/js/bootstrap-typeahead.js

_.extend($.fn.typeahead.Constructor.prototype, { 
    render: function (items) { 
     var that = this; 

     items = $(items).map(function (i, item) { 
      i = $(that.options.item) 
       .attr('data-value', item[that.options.display]) 
       .attr('data-id', item.id); 
      i.find('a').html(that.highlighter(item)); 
      return i[0]; 
     }); 

     items.first().addClass('active'); 
     this.$menu.html(items); 
     return this; 
    }, 
    select: function() { 
     var val = this.$menu.find('.active').attr('data-value'), 
      id = this.$menu.find('.active').attr('data-id'); 
     this.$element 
      .val(this.updater(val, id)) 
      .change(); 
     return this.hide() 
    } 
}); 

return function (element, options) { 
    var getSource = function() { 
      return { 
       id: 2, 
       full_name: 'first_name last_name' 
      }; 
    }; 

    element.typeahead({ 
     minLength: 3, 
     source: getSource, 
     display: 'full_name', 
     sorter: function (items) { 

      var beginswith = [], 
       caseSensitive = [], 
       caseInsensitive = [], 
       item, 
       itemDisplayed; 

      while (item = items.shift()) { 
       itemDisplayed = item[this.options.display]; 
       if (!itemDisplayed.toLowerCase().indexOf(this.query.toLowerCase())) { 
        beginswith.push(item); 
       } else if (~itemDisplayed.indexOf(this.query)) { 
        caseSensitive.push(item); 
       } else { 
        caseInsensitive.push(item); 
       } 
      } 

      return beginswith.concat(caseSensitive, caseInsensitive); 
     }, 
     highlighter: function (item) { 
      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); 

      return item[this.options.display].replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { 
       return '<strong>' + match + '</strong>'; 
      }); 
     }, 
     matcher: function (item) { 
      var value = item[this.options.display]; 

      return { 
       value: ~value.toLowerCase().indexOf(this.query.toLowerCase()), 
       id: item.id 
      }; 
     }, 
     updater: function (item, userId) { 
      options.hiddenInputElement.val(userId); 
      return item; 
     } 
    }); 
}; 
+1

no veo cómo se están recibiendo incluso tan lejos. Cuando intento ejecutar su código, se lanza una excepción en el método 'sorter()' para intentar aplicar métodos de cadena en objetos. ¿Estabas alterando ese método? ¿O tal vez agregar funciones a los objetos? – merv

+1

sí, tienes razón porque hice otros cambios que aún no publiqué ... Lo haré más tarde. gracias –

+1

Sí, eso sería útil, ya que 'matcher()' y 'sorter()' alteran 'items' antes de pasarlo al método' render() '. Además, se admite la anulación de 'sorter()' en la API, por lo que no debería ser necesario editarla en la fuente ** bootstrap-typeahead.js **. (No dice que eso es lo que estaba haciendo, solo lo señala) – merv

Respuesta

18

recomiendo a no volver a escribir el prototipo (lo que afectará a todos los lugares donde se podría utilizar el Autocompleter, no sólo la función siguiente).
Este código debería funcionar:

var getSource = function() { 

    var users = new Backbone.Collection([ 
     { 
      first_name: 'primo', 
      last_name: 'ultimo', 
      id: 1 
     }, 
     { 
      first_name: 'altro_primo', 
      last_name: 'altro_ultimo', 
      id: 2 
     } 
    ]).models; 

    return _.map(users, function (user) { 
     return { 
      id: user.get('id'), 
      full_name: user.get('first_name') + ' ' + user.get('last_name'), 
      // these functions allows Bootstrap typehead to use this item in places where it was expecting a string 
      toString: function() { 
       return JSON.stringify(this); 
      }, 
      toLowerCase: function() { 
       return this.full_name.toLowerCase(); 
      }, 
      indexOf: function (string) { 
       return String.prototype.indexOf.apply(this.full_name, arguments); 
      }, 
      replace: function (string) { 
       return String.prototype.replace.apply(this.full_name, arguments); 
      } 
     }; 
    }); 
}; 

$('.full_name').typeahead({ 
      minLength: 3, 
      source: getSource(), 
      display: 'full_name', 
      updater: function (itemString) { 
       var item = JSON.parse(itemString); 
       $('.id').val(item.id); 
       return item.full_name; 
      } 
}); 

demo: http://jsfiddle.net/hyxMh/48/

+0

Hola, estoy tratando de usar su solución, y dado que estoy usando una llamada ajax para obtener datos de los usuarios, me resulta difícil integrarlo con su código.Si escribo el ajax en el getSource declarado afuera, no puedo encontrar la manera de pasarle mi consulta. ¿Tienes un trabajo para esto? Gracias :) –

0

Además de @AntoJs respuesta, aquí es una versión ajax (sólo una parte 'fuente'):

$('.full_name').typeahead({ 
    /* ... */ 
    source: function(query,process){ 
    $.ajax({ 
     url: 'your_url_here', 
     data: {term: query, additional_data: 'some_data'}, 
     success: function(data){ 
      process($.map(data, function(user){ 
       return { 
        id: user.id, 
        full_name: user.first_name + ' ' + user.last_name, 
        toString: function() { 
         return JSON.stringify(this); 
        }, 
        toLowerCase: function() { 
         return this.full_name.toLowerCase(); 
        }, 
        indexOf: function (string) { 
         return String.prototype.indexOf.apply(this.full_name, arguments); 
        }, 
        replace: function (string) { 
         return String.prototype.replace.apply(this.full_name, arguments); 
        } 
       } 
      })); 
     } 
    }); 
    }, 
/* ... */ 
}); 

BTW: @AntoJs - muchas gracias por su respuesta!

0

@ respuesta de antonjs no funcionaba para mí y yo estaba recibiendo el siguiente error

TypeError: item.substr no es una función

por lo que con jQuery y v2.1.3 bootstrap3-typeahead.js v3 .1.0 las siguientes obras para mí

var getSource = function() { 
 

 
    var users = new Backbone.Collection([ 
 
     { 
 
      first_name: 'primo', 
 
      last_name: 'ultimo', 
 
      id: 1 
 
     }, 
 
     { 
 
      first_name: 'altro_primo', 
 
      last_name: 'altro_ultimo', 
 
      id: 2 
 
     } 
 
    ]).models; 
 

 
    return _.map(users, function (user) { 
 
     return { 
 
      id: user.get('id'), 
 
      full_name: user.get('first_name') + ' ' + user.get('last_name'), 
 
      // these functions allows Bootstrap typehead to use this item in places where it was expecting a string 
 
      toString: function() { 
 
       return JSON.stringify(this); 
 
      }, 
 
      toLowerCase: function() { 
 
       return this.full_name.toLowerCase(); 
 
      }, 
 
      indexOf: function (string) { 
 
       return String.prototype.indexOf.apply(this.full_name, arguments); 
 
      }, 
 
      replace: function (string) { 
 
       return String.prototype.replace.apply(this.full_name, arguments); 
 
      }, 
 
      substr: function(start, len){ 
 
        return this.full_name.substr(start, len); 
 
      } 
 
     }; 
 
    }); 
 
}; 
 

 
$('.full_name').typeahead({ 
 
      minLength: 3, 
 
      source: getSource(), 
 
      display: 'full_name', 
 
      updater: function (itemString) { 
 
       var item = JSON.parse(itemString); 
 
       $('.id').val(item.id); 
 
       return item.full_name; 
 
      } 
 
});

Cuestiones relacionadas