简体   繁体   中英

CakePHP 3 autocomplete AJAX responses

I have been trying to get cakephp to suggest input from data that is from my tables like autocomplete. I've done some reading about how some other people have done this but still can't figure it out. Currently it seems that every time my controller is waiting for an ajax request and it is always false. No errors come up from the console some i'm not sure what i'm doing wrong. I tried removing the if ($this->request->is('ajax')) statement but then I get a error about it cannot emit headers. Here is my search function in InvoicesController which I have taken code from someone else example but failed to implement it.

     public function search()
{
    if ($this->request->is('ajax')) {
        $this->autoRender = false;
        pr('b');
        $name = $this->request->query['term'];
        $results = $this->Invoices->find('all', [
            'conditions' => [ 'OR' => [
                'id LIKE' => $id . '%',
            ]]
        ]);
        $resultsArr = [];
        foreach ($results as $result) {
             $resultsArr[] =['label' => $result['full_name'], 'value' => $result['id']];
        }
        echo json_encode($resultsArr);
    }
}

And here is my search.ctp

    <?php use Cake\Routing\Router; ?>

    <?php echo $this->Form->input('id', ['type' => 'text']);?>
<script>
    jQuery('#id').autocomplete({
        source:'<?php echo Router::url(array('controller' => 'Invoices', 'action' => 'search')); ?>',
        minLength: 1
    });
</script>

This is my invoice table and the ids are what I want to be suggested from what users type in. 发票表

I may not be seeing your exact problem but let me point out a few things I see that might help this issue.

Remove this line. It is not necessary

$this->autoRender = false;

Instead you should be doing this at the end. See using the RequestHandler

$this->set('resultsArr', $resultsArr);
// This line is what handles converting your array into json
// To get this to work you must load the request handler
$this->set('_serialize', 'resultsArr');

This will return the data without a root key

 [
   {"label":"Label Value"}, 
   {"label":"Another Label Value"}
 ]

Or you can do it like this

$this->set('_serialize', ['resultsArr']);

This will return data like

{"resultArr":[
   {"label":"Label Value"}, 
   {"label":"Another Value"}
]}

Replace your finder query with this.

$resultArr = $this->Invoices->find('all')
    ->where(['id LIKE' => $id . '%'])
    // If you want to remap your data use map
    // All queries are collections
    ->map(function ($invoice) {
        return ['label' => $invoice->full_name, 'id' => $invoice->id];
    });

It seems to me you might want to review the new cakephp 3 orm. A lot of hard work went into writing these docs so that they could be easily read and relevant. I'm not one to push docs on people but it will save you hours of frustration.

Cakephp 3 ORM documentation

A few minor things I noticed that are also problems.

  • You never define $id.
  • You define $name but never use it.
  • pr is a debug statement and I am not sure why you have it.

Based on your comment, here is an update on ajax detection.

// By default the ajax detection is limited to the x-request-with header
// I didn't want to have to set that for every ajax request
// So I overrode that with the accepts header.
// Any request where Accept is application/json the system will assume it is an ajax request
$this->request->addDetector('ajax', function ($request) {
    $acceptHeaders = explode(',', $request->env('HTTP_ACCEPT'));

    return in_array('application/json', $acceptHeaders);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM