jQuery UI AutoComplete in CakePHP

Demo : http://cbunny.rudylee.com/autocomplete

Demo source code : https://github.com/rudylee/cbunny

The post to add auto redirect feature into the AutoComplete : http://blog.rudylee.com/2011/12/12/auto-redirect-in-cakephp-jquery-autocomplete/ You can copy the modified Ajax and Javascript helpers from here https://github.com/rudylee/topping

Last week I was trying to use jQuery UI Autocomplete in my CakePHP apps. However, CakePHP Ajax and Javascript helpers don’t support jQuery by default. After googling a little bit, I found that this guy ( http://www.cakephp.bee.pl/ ) already made Ajax and Javascript helpers for jQuery.

So I just copied these helpers from his site and put it into my apps. It’s done ? obviously not. It turned out that the autocomplete script that he using in his helper is the old one ( http://docs.jquery.com/Plugins/autocomplete ).

Thus, I had to add a method inside that helper to use jQuery UI autocomplete. Here are the sample codes ( you can copy from my github for the complete file, this one is just snippet ) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
 * Options for auto-complete editor.
 *
 * @var array
 */
var $autoCompleteOptions = array(
    'select', 'source'
);

/**
 * Create a text field with Jquery UI Autocomplete.
 *
 * Creates an autocomplete field with the given ID and options.
 * needs include jQuery UI Autocomplete file
 *
 * @param string $field DOM ID of field to observe
 * @param array $options Ajax options
 * @return string Ajax script
 * check out http://jqueryui.com/demos/autocomplete/
 */
function autoComplete($field, $options = array()) {
    $var = '';
    if (isset($options['var'])) {
        $var = 'var ' . $options['var'] . ' = ';
        unset($options['var']);
    }

    if(isset($options['source'])) {
        $options['source'] = "'".Router::url($options['source'])."'";
    }

    if (!isset($options['id'])) {
        $options['id'] = Inflector::camelize(str_replace(".", "_", $field));
    }

    $htmlOptions = $this->__getHtmlOptions($options);
    $htmlOptions['autocomplete'] = "off";

    foreach ($this->autoCompleteOptions as $opt) {
        unset($htmlOptions[$opt]);
    }

    $options = $this->_optionsToString($options, array('multipleSeparator'));
    $callbacks = array('formatItem', 'formatMatch', 'formatResult', 'highlight');

    foreach ($callbacks as $callback) {
        if (isset($options[$callback])) {
            $name = $callback;
            $code = $options[$callback];
            switch ($name) {
                case 'formatResult':
                    $options[$name] = "function(data, i, max) {" . $code . "}";
                    break;
                case 'highlight':
                    $options[$name] = "function(data, search) {" . $code . "}";
                    break;
                default:
                    $options[$name] = "function(row, i, max, term) {" . $code . "}";
                    break;
            }
        }
    }
    $options = $this->_buildOptions($options, $this->autoCompleteOptions);

    $text = $this->Form->text($field, $htmlOptions);
    $script = "{$var} $('#{$htmlOptions['id']}').autocomplete(";
    $script .= "{$options});";

    return "{$text}\n" . $this->Javascript->codeBlock($script);
}

And here are the sample to use it in our application

1
2
3
4
5
6
7
echo $this->Ajax->autoComplete('Guest.search', array(
    'source' => array(
        'controller' => 'users',
        'action' => 'autoComplete',
        'prefix' => 'host'
    ),
));

Action code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * Auto Complete Action for Host
 *
 * Auto Complete action for host list of guests
 * also process the search
 */
function host_autoComplete() {
    if (!empty($this->data)) {
        $this->redirect(array(
            'controller' => 'users',
            'action' => 'view', $this->data['Guest']['id']
        ));
    }
    $this->autoRender = false;
    $guests = $this->User->getGuests(array(
        'host_id' => Configure::read('User.id'),
            'conditions' => array(
                'OR' => array(
                'User.name LIKE' => '%' . $_GET['term'] . '%',
                'User.surname LIKE' => '%' . $_GET['term'] . '%'
            )
        )
    ));
    echo json_encode($this->User->autoComplete_encode($guests));
}

Model method ( encode the data array to display fields that we want, in this example I am just showing firstname and surname )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * autoComplete encode
 *
 * Parsing passed array and change it to consume-able
 * by autocomplete jQuery UI
 * @param array $data
 * @return json $data
 */
function autoComplete_encode($postData = array()) {
    $temp = array();
    foreach ($postData as $user) {
        array_push($temp, array(
            'id' => $user['User']['id'],
            'label' => $user['User']['name'].' '.$user['User']['surname'],
            'value' => $user['User']['name'],
        ));
    }
    return $temp;
}

Don’t forget to use $_GET[‘term’] to get data from autocomplete field and also encode the data to JSON so it can be displayed by jQuery UI.

Comments