Twitter typeahead.js: Possible to use Angular JS as template engine? If not how do I replace "{{}}" for Hogan/Mustache js?
Asked Answered
A

3

7

I am working with twitter's typeahead.js and I was wondering if it was possible to modify hogan.js to use something other than {{}}?

I am looking at the minified code now and I have no idea what to change for something so simple. Doing a find and replace breaks it.

I am asking this mainly because I'm using Angular JS but twitter's typeahead requires a templating engine, causing hogan and angular's {{}} to clash. An even better solution would be simply modifying Angular JS (I know it's not a templating engine) and ditching Hogan to fit the following criteria:

Any template engine will work with typeahead.js as long as it adheres to the following API:

// engine has a compile function that returns a compiled template
var compiledTemplate = ENGINE.compile(template);

// compiled template has a render function that returns the rendered template
// render function expects the context to be first argument passed to it
var html = compiledTemplate.render(context);
Aglow answered 28/7, 2013 at 2:19 Comment(9)
If you want to change the curly brackets in Angular, just can just follow this : docs.angularjs.org/api/ng.$interpolate , no modification needed to the code ;)Marlenamarlene
@meiryo, how did you manage to use Typeahead.js in an angular application ? because I'm trying to include it but I don't know how to proceed (I have already used it but within jQuery). Thanks in advance for your help :)Meretricious
@user1651994 I changed Hogan.js delimiters to <% %>. All I did was a find and replace for "{{" and "}}". No more conflicts with angular! Let me know if you can use angular as the template engine... not very fond of including Hogan just for a simple typeahead box.Aglow
@Aglow Actually I'm not using Typeahead.js in my project yet. How are using it in your project ? is there a custom directive, or you're just using jQuery code ? (just to know because I can't use the current version since I'm relying on an existing API, and the data format doesn't match the required one for typeahead Datum... It seems that building a dataset in the client-side will be possible in the 0.10 release)Meretricious
@user1651994 I just include the typeahead.js file in my scripts, and call the typeahead() function on the input field I want. Nothing fancy, really easy to set up and I love it. Take a look at the source code for their examples, it help me figure out some of the stuff: twitter.github.io/typeahead.js/examplesAglow
@Aglow Well I see, I thought there was something specific to AngularJS. Do you mind sharing a snippet of the code you are using to do this ? Many thanksMeretricious
@user1651994 Sorry I'm under contract so I cannot show code. But the implementation is dead easy: pastebin.com/c4XSLpVL five lines of code pretty much. AngularJS conflicted with the templating engine Hogan because they both use {{ }} directives. Yeah, nasty.Aglow
@Aglow No worries, thanks for your help ! At least, now I know that someone has used Typeaheadjs with Angularjs :)Meretricious
@user1651994 you'll need jQuery loaded, then have to create a directive and put the typeahead inside: pastebin.com/ALQYdfrkMiscegenation
H
3

If you want to use Hogan.js with Angular, you can change the delimiters by doing something like:

var text = "my <%example%> template."
Hogan.compile(text, {delimiters: '<% %>'});
Hadji answered 29/7, 2013 at 19:46 Comment(0)
M
14

Ignore the documentation on this, just look at the source code:

function compileTemplate(template, engine, valueKey) {
    var renderFn, compiledTemplate;
    if (utils.isFunction(template)) {
        renderFn = template;
    } else if (utils.isString(template)) {
        compiledTemplate = engine.compile(template);
        renderFn = utils.bind(compiledTemplate.render, compiledTemplate);
    } else {
        renderFn = function(context) {
            return "<p>" + context[valueKey] + "</p>";
        };
    }
    return renderFn;
}

It happens you can just pass a function to template, callable with a context object which contains the data you passed in the datum objects at the time of instantiation, so:

$('#economists').typeahead({
  name: 'economists',
  local: [{
    value: 'mises',
    type: 'austrian economist',
    name: 'Ludwig von Mises'
  }, {
    value: 'keynes',
    type: 'keynesian economist',
    name: 'John Maynard Keynes'
  }],
  template: function (context) {
    return '<div>'+context.name+'<span>'+context.type.toUpperCase()+'</span></div>'
  }
})
Miscegenation answered 3/9, 2013 at 22:52 Comment(1)
As of 0.11.1, you would do templates: { suggestion: function(context) ... }Abbe
H
3

If you want to use Hogan.js with Angular, you can change the delimiters by doing something like:

var text = "my <%example%> template."
Hogan.compile(text, {delimiters: '<% %>'});
Hadji answered 29/7, 2013 at 19:46 Comment(0)
N
3

It appears that the template engine result that typeahead.js expects is an html string and not the dom element (in dropdown_view.js). So I am not sure there is a good solution for using an angular template. As a test I was able to get it binding the result to an angular template but it has to render to an element and then get the html value from the element after binding with the data. I don't like this approach but I figured someone might find it useful. I think I will go with a template function like in the previous post.

Jade template looks like

.result
  p {{datum.tokens}}
  p {{datum.value}}

Directive

angular.module('app').directive('typeahead', [
  '$rootScope', '$compile', '$templateCache',
  function ($rootScope, $compile, $templateCache) {
    // get template from cache or you can load it from the server
    var template = $templateCache.get('templates/app/typeahead.html');
    var compileFn = $compile(template);
    var templateFn = function (datum) {
      var newScope = $rootScope.$new();
      newScope.datum = datum;
      var element = compileFn(newScope);
      newScope.$apply();
      var html = element.html();
      newScope.$destroy();
      return html;
    };
    return {
      restrict: 'A',
      link: function (scope, element, attrs, ctrl) {
        element.typeahead({
          name: 'server',
          remote: '/api/search?q=%QUERY',
          template: templateFn
        });
        element.on('$destroy', function () {
          element.typeahead('destroy');
        });
        element.on('typeahead:selected', function () {
          element.typeahead('setQuery', '');
        });
      }
    };
  }
]);
Neutralize answered 26/9, 2013 at 22:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.