Yii2: Typeahead widget

In Yii V1, you use CJuiAutoComplete widget which displays an autocomplete field. There’s equivalent widget in Yii2 but I’ve not tried it yet because I tried something developed by external parties before I knew it exists. I’ve had successful use with the Typeahead widget, which is a wrapper class for Twitter Typeahead jQuery plugin.

Say the field stores user’s ID, but no one will ever remember user’s ID. You need to type in matching names to find user’s ID. This example submits AJAX call to find user with matching name.

Note that once a name is selected, ID is displayed in the field. It’d be nice to show user’s name instead, but I don’t know how to display the name yet to save the ID back into the database. If you know the answer, please leave a comment!

The View

use yii\helpers\Url;
use kartik\widgets\Typeahead;
use yii\web\JsExpression;
echo $form->field($model, 'username')->widget(Typeahead::classname(), [
    'options'   => [
        'placeholder'   => 'Enter name to match...',
    ],
    'scrollable'    => true,
    'pluginOptions' => [
        'highlight' => true,
        'minlength' => 2,
    ],
    'dataset'       => [
        [
            'display'   => 'value',
            'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('value')",
            'remote'    => [
                'url'       => Url::to(['/path-to/controller/match-user']) . '?field=id&q=%QUERY',
                'wildcard'  => '%QUERY',
            ],
            'templates' =>[
                'empty'         => 'Unable to find user',
                'suggestion'    => new JsExpression("Handlebars.compile('<li>{{name}} ({{id}})</li>')"),
                ],
            'limit'     => 20,
        ],
    ],
]); 

Note:

  • Line 11 – I’d suggest setting a minimum length of input before it starts to submit an AJAX request to match.
  • Line 13 – ‘dataset’ attribute, remember the values is in array format.
  • Line 15 – data to be displayed in the field when returned from the controller via AJAX call. See next section.
  • Line 18 – url for ajax call and the partial query to match.
  • Line 23 – the display format based on data returned from controller via AJAX call. See next section.

The Controller

In the action function, it needs to return Json encoded array of data back to the Typeahead widget to display in its drop down list. The array keys must be those matching values used in the ‘display’ and ‘template’ attributes.

public function actionMatchUser($q = null) {
    if (Yii::$app->request->isAjax) {
        $get = Yii::$app->request->queryParams;
        $query = User::find()->andWhere(['like', 'name', $q]);
        $data = [];
        foreach ($query->all() as $user) {
            $data[] = [
                'id'    => $user->id,
                'name'  => $user->name,
                'email' => $user->email,
                'value' => $user->id,
            ];
        }
        echo Json::encode($data);
    }
    exit();
}

Note:

  • Line 2: process as AJAX request only.
  • Lines 8-12: note the array keys. For this example ’email’ is not required, but shown as an option if you want to include email in Typeahead template.
  • Line 8 and 11: you must include ‘id’ – data to be saved back to db and ‘value’ via above widget for display.
  • Line 14: you must return array in Json format. Alternatively, you can set response format to Json and return the array directly.

Leave a Reply

Your email address will not be published. Required fields are marked *