Git Product home page Git Product logo

typeahead-bundle's Introduction

Introduction

This is a Symfony v2.2+ Bundle that provides a Bootstrap (v2.x or v3.x) Typeahead widget for use in forms. The Typeahead component used in this bundle is the original Bootstrap v2.3 Typeahead library with a few enhancements.

Update: If you were pointing to dev-master in your composer.json and this bundle stopped working change your version to "^1.*" and run composer update lifo/typeahead to update your project.

  • If you are using Bootstrap v2.x then you must use version 1.* of this bundle.
  • If you are using Bootstrap v3.x then you must use version 2.* of this bundle.

Note: This bundle does not use the newer Twitter/Typeahead.js javascript library.

Enhanced Typeahead Features

This bundle adds a few enhancements to the original bootstrap typeahead javascript library:

  • Supports JSON objects
  • Caches results
  • Delays AJAX request to reduce server requests
  • Properly handles pasting via mouse
  • Includes an AJAX Loader icon
  • Supports Non-Entity lookup
  • Supports non AJAX loading via a custom callback function

Screenshots

This example shows a form field that allows a single name to be entered.

Typeahead (single) Example

This example shows a form field that allows multiple names to be entered. Clicking on a name link removes the entity. The entity in the backend is actually an ArrayCollection and automatically allows adding/removing entities from the list.

Typeahead (multiple) Example

How to install

Note: This bundle requires jQuery and Bootstrap to be installed in your environment but does not include them directly. I suggest using the mopa/bootstrap-bundle which can help with this for you.

  • Add lifo/typeahead-bundle to the "requires" section of your project's composer.json file, which can be done automatically by running the composer command from within your project directory:

    composer require lifo/typeahead-bundle
    

    or manually by editing the composer.json file:

    {
        // ...
        "require": {
            // ...
            "lifo/typeahead-bundle": "^2.0"
        }
    }
  • Run composer update in your project root.

  • Update your project app/AppKernel.php file and add this bundle to the $bundles array:

    $bundles = array(
        // ...
        new Lifo\TypeaheadBundle\LifoTypeaheadBundle(),
    );
  • Add @lifo_typeahead_js to your Assetic javascripts block. Similar to the block below. Your actual setup may differ. Be sure to include it AFTER your jquery and bootstrap libraries.

    {% javascripts filter='?yui_js' output='js/site.js'
        '@lifo_typeahead_js'
    %}
        <script src="{{ asset_url }}"></script>
    {% endjavascripts %}
  • Add @lifo_typeahead_css to your Assetic stylesheets block. Similar to the block below. Your actual setup may differ.

    {% stylesheets filter='cssrewrite,?yui_css' output='css/site.css'
        '@lifo_typeahead_css'
    -%}
        <link href="{{ asset_url }}" type="text/css" rel="stylesheet" />
    {% endstylesheets %}
  • If you're not using Assetic then you will have to manually include the javascript and css files into your project.

    <link href="{{ asset('bundles/lifotypeahead/css/typeaheadbundle.css') }}" type="text/css" rel="stylesheet" />
    <script src="{{ asset('bundles/lifotypeahead/js/bootstrap-typeahead.js') }}"></script>
    <script src="{{ asset('bundles/lifotypeahead/js/typeaheadbundle.js') }}"></script>

How to use

Using the typeahead control is extremely simple. The available options are outlined below:

$builder->add('user', 'entity_typeahead', array(
    'class'  => 'MyBundle:User',
    'render' => 'fullname',
    'route'  => 'user_list',
));

Options

  • class is your entity class. If null (or not specified), the items returned from your controller AJAX response do not have to be Entities. If not blank, the class is used to map the items to your DB Entities.
  • source is the name of a function to call that will collect items to display. This or route must be specified. The prototype is: function(query, process) where process is the callback your function should call after you've fetched your list of matching items. It expects a FLAT array of strings to render into the pull down menu (Not {id:'...', value:'...'} objects!). See the example below for more information.
  • route is the name of the route to fetch entities from. The controller matching the route will receive the following parameters via POST:
    • query The query string to filter results by.
    • limit The maximum number of results to return.
    • render The configured render name. This is what you should use to set the value attribute in the AJAX response.
    • property The configured property name. Normally this is id. This is what you should use to set the id attribute in the AJAX response.
  • route_params Extra parameters to pass to the route.
  • minLength Minimum characters needed before firing AJAX request.
  • items Maximum items to display at once (default: 8)
  • delay Delay in milliseconds before firing AJAX (default: 250)
  • spinner Class string to use for loading spinner (default: "glyphicon glyphicon-refresh spin") Font-Awesome example: "fa fa-refresh fa-spin fa-fw"
  • multiple If true the widget will allow multiple entities to be selected. One at a time. This special mode creates an unordered list below the typeahead widget to display the selected entities.
  • callback Callback function (or string) that is called when an item is selected. Prototype: function(text, data) where text is the label of the selected item and data is the JSON object returned by the server.
  • render is the property of your entity to display in the typeahead input. This is used to render the initial value(s) into the widget. Once a user starts typing, the rendered responses are dependent on the route or source used.

AJAX Response

The controller should return a JSON array in the following format. Note: id and value properties are required but you may include other properties as well.

[
  { id: 1, value: 'Displayed Text 1' },
  { id: 2, value: 'Displayed Text 2' }
]

Note: If you are using a null class option then your JavaScript array should return an id and value that are the same thing. e.g:

[
  { id: 'Result 1', value: 'Result 1' },
  { id: 'Result 2', value: 'Result 2' }
]

If you do not return the same string for the id and value you will get confusing results in your UI.

Custom Source Callback

Here is an example of a custom source callback. This example mimics the same result if you had used the route option.

function get_users(query, process) {
    $.post('/mysite/lookup/users', {query: query}, 'json')
        .success(function (data) {
            // must convert the data array into a flat list of strings. 
            // If your lookup function already returns a flat list, then $.map() is not needed.
            process($.map(data, function(a){
                return a.value;
            }));
        });
}
$builder->add('user', 'entity_typeahead', array(
    'class'  => 'MyBundle:User',
    'render' => 'fullname',
    'source' => 'get_users', // a function name in the global javascript "window" object 
));

Template

Your form template might look something like this (The screenshots above used this template bit). Note: The widget_addon attribute is a mopa/bootstrap-bundle attribute.

{{ form_row(form.name) }}
{{ form_row(form.owner, { attr: { placeholder: 'Search for user ...'}, widget_addon: {type: 'append', 'icon': 'user'}}) }}
{{ form_row(form.users, { attr: { placeholder: 'Add another user ...'}, widget_addon: {type: 'append', 'icon': 'user'}}) }}

Notes

This bundle renders its form elements in standard Symfony style. You will have to override the form blocks to get the proper Bootstrap styles applied. I strongly suggest something like mopa/bootstrap-bundle that will override the Symfony form templates with proper Bootstrap versions automatically for you.

typeahead-bundle's People

Contributors

lifo101 avatar mikeyudin avatar t-veron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

typeahead-bundle's Issues

License

Can you add license file? Is it MIT like braincrafted/bootstrap-bundle?

Undefined index.

Hey, running into a bit of a snag.

I have the controller setup to return the JSON object, that bit is working.

I have the following code in my form object:

->add('localAccountExecs', 'entity_typeahead', [
    'label'  => 'Local Account Executive(s)',
    'class'  => 'AssociateBundle:Associate',
    'render' => 'name',
    'route'  => 'associate_list',
            ])

My template looks like:

{{ form_row(form.localAccountExecs, {attr: {placeholder: 'Search for an associate...'}}) }}

When loading the form I get the following error:

Notice: Undefined index: 0000000063caf225000000000ef8ef71

Error including JS library

Hello, when in PROD mode (strangely it works in DEV mode) I get this error in prod.log:

request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "No route found for "GET /js/lifo_typeahead.js" (from "http://example.com/example/new")" at /var/www/html/example/app/cache/prod/classes.php line 2512 {"exception":"[object] (Symfony\Component\HttpKernel\Exception\NotFoundHttpException(code: 0): No route found for "GET /js/lifo_typeahead.js"

I guess it's related to this part of my code, that I copied from README.md without really understanding it:

    <script src="{{asset( '/js/bootstrap.min.js') }}" type="text/javascript"></script>
    {% javascripts filter='?yui_js' output='js/lifo_typeahead.js'
    '@lifo_typeahead_js'
    %}
    <script src="{{ asset_url }}"></script>

As a maybe related issue, I stripped out de yui_css part in next code due to another exception:

    {% stylesheets filter='cssrewrite' output='css/lifo_typeahead.css'
    '@lifo_typeahead_css'
    -%}
    <link href="{{ asset_url }}" type="text/css" rel="stylesheet" />
    {% endstylesheets %}

Can't add new items with multiple = true

Hello

I'm trying this for a multiple (ManyToMany) relationship.

Existing items appear correctly in the unordered list.
I can delete an item, submit the form and it is deleted correctly.
I can add new items and they appear correctly in the unordered list but ...
When I submit the form, the new items are not posted.

I'm not sure where to begin to help debug but the $array parameter in
EntitiesToPropertyTransformer::reverseTransform does not contain newly added items.

The same code works if I replace the typeahead with a standard entity form component with multiple = true.

Thanks

Variable "loadingIconUrl" does not exist

Hi,

I have tried to use this bundle with symfony2.2, but I have the following error :

Variable "loadingIconUrl" does not exist in /var/www/myproject/vendor/lifo/typeahead-bundle/Lifo/TypeaheadBundle/Resources/views/Form/fields.html.twig at line 9

I have tried to define this property with empty string in fields.html.twig, the error disappears and my action works... but typeahead does'nt work :( . In my browser console I have the following error :

Uncaught TypeError: Cannot read property 'defaults' of undefined

Any idea ?

The bundle seem configured well :/

Callback example

Can you give an example of using callback parameter? I tryed all these and nothing happens when I click an item:

    $builder
        ->add('the_list', 'entity_typeahead', array('label'  => 'A list',
                                                               'class'  => 'AppBundle:TheList',
                                                               'render' => 'name',
                                                               'route'  => 'the_list',
                                                               'mapped' => false,
                                                               'callback' => 'alert(text)'
                                                               ))

Also
'callback' => 'function(text, data) {alert(text);}'

Nothing happens, no error, no action. I can see the attribute data-callback="function(text, data) {alert(text);}" is correctly set.

Also, I can't see the spinner when waiting response, maybe these problems are related

spinner is not showing

Hello, everything is working ok, but spinner is never showing up, I tried to leave it as default or adding my own value like this one:

        ->add('code', 'entity_typeahead', array('required'  => false,
                                                'label'     => Your code',
                                                'class'     => 'AppBundle:TheCode',
                                                'render'    => 'code',
                                                'route'     => 'list_codes',
                                                'callback'  => 'getCodeInfo',
                                                'minLength' => 3,
                                                'spinner'   => "fa fa-spinner"
                                                ))

I'm running in dev mode so I don't think is an assets thing, and the rest of things are properly styled (I have font awesome library also)

Thank you

allow simple autocomplete (not only entity oriented)

Hi!
I Just wanted to say thank you for yor bundle first! it is really helpful!

However I found myself stucked with a small issue (not a bug).

The plugin works really well with entity type field but won't work with simple string.
What if I wanted to store a user name without storing the whole user entity?

With a __toString it will be stored but then in my edit form I will get an error saying:
"Expected argument of type "object or array", "string" given"

After investigation, the issue comes from the data transformers strongly coupled with the form Type. Maybe you could inject them via the service container or create a second formType called 'simple_typeahead' which would allow autocomplete based on entities (reverse transformation) but wouldn't try to reload the field based on an object but a string/int.

Another option is just to test if the initial data to transform is an entity in the transformer and if it's not, do nothing.

I'll see if I can contribute and submit you a pull request soon ^^.

Thanks again!

Instalation failed with Symfony v.2.2.1

After executing:
composer require lifo/typeahead-bundle dev-master

I'm getting following errors:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package lifo/typeahead-bundle dev-master dev-master could not be found
.
  Problem 2
    - Installation request for symfony/framework-standard-edition 2.2.x-dev -> satisfiable
 by symfony/framework-standard-edition[2.2.x-dev].
    - symfony/framework-standard-edition 2.2.x-dev requires lifo/typeahead-bundle dev-mast
er dev-master -> no matching package found.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stabi
lity setting
   see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more de
tails.

Read <http://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.


Installation failed, reverting composer.json to its original content.

Any ideas what might went wrong?

Entered data disappear on blur event

Hi,

When we type somethink new to input and go to the next form element (the blur event is fired on the typehead) the entered data disappear.

Documentation error.

Hi

Thanks for this. It's exactly what I was looking for and it works great!

A minor error but it caught me for a while as I blindly copied and pasted. The instructions say to add this to composer.json

"lifo/symfony-typeahead-bundle": "dev-master"

but it should be

"lifo/typeahead-bundle": "dev-master"

id null in form

hey,
i integrate your bundle in my project for using it as tag input.
but i get this error
**

"Impossible to access an attribute ("id") on a null variable in LifoTypeaheadBundle:Form:typeahead.html.twig at line 62."

**
i use symfony 2.7, this is my form code:

->add('tags', 'entity_typeahead', array(
                'class'  => 'WF\TagBundle\Entity\Tag',
                'render' => 'name',
                'route'  => 'wf_advert_tags',
                'multiple' => true
            ));

Default options in config file

Hello,

Instead of setting the default options into TypeaheadType's class, could you create a configuration file please ( for options delay, minLength, items, spinner)?

Error when counting the response data from controller

I got the parsing error from javascript source of your code.

my json output was like :
[{"id":1,"value":"test"},{"id":2,"value":"test2"}]

and the success method of $.ajax acts like its string and it parsed all string like an array ( which is count of string )

I guess there were problem in intelligient guess method of jquery but just we can simply add

dataType: "json",

into typeheadjs which under the $.ajax. This will fix the problem.

Variable "url" does not exist.

When using the source option to call a javascript function I get the above error. I declare the field like so

        $builder->add('street', 'entity_typeahead', array(
            'class'  => 'AppBundle:Street',
            'render' => 'name',
            'source' => 'test',
            'minLength' => 1,
            'callback' => 'test2'

        ))

If I simply include the 'route' option it seems to resolve the issue and still calls the JS function but not sure why it would be required. Documentation says just one or the other.

Invalid input name when form name contains underscores

When multiple select is enabled and the form name contains underscores (e.g. my_form_name) selected input elements have the wrong name values.

I have traced the issue to the following code in the js:

var name = id.split(//);
name = (name.length > 1 ? name.shift() + '[' + name.join('][') + ']' : name.join()) + '[]';

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.