you have not forget a entry in route.json files ?

And not library to include ? This use existing library in espocrm ?
{ "fields": { "autocompleteInput": { "type": "varchar", "maxLength": 150, "options": [], "isCustom": true, "view": "custom:views/fields/varchar-autocomplete-from-api", "autocompleteMinChars": "1", "autocompleteSourceUrl": "http://api-adresse.data.gouv.fr/search/", "autocompleteQmodifier": "+bd+du+port", "autocompleteQueryFilters": [ {"limit":"20"}, {"postcode": "autocompleteFilter.val()"} ] }, "autocompleteFilter": { "type": "varchar", "maxLength": 150, "options": [], "isCustom": true } } }
define('custom:views/fields/varchar-autocomplete-from-api', 'views/fields/varchar', function (Dep) { return Dep.extend({ autocompleteUrl: null, autocompleteGatewayUrl: "AutocompleteFromApi", autocompleteOptions: {}, setup: function () { Dep.prototype.setup.call(this); // direct the autocomplete Ajax call to the gateway url this.autocompleteUrl = this.autocompleteGatewayUrl+'/action/fetchJson?s='+this.entityType+'&id='+this.model.id+'&a='+this.name; }, afterRender: function () { Dep.prototype.afterRender.call(this); // define autocomplete options for details on the autocomplete plug in options and methods visit: https://github.com/devbridge/jQuery-Autocomplete this.autocompleteOptions = { noCache: true, serviceUrl: this.autocompleteUrl, paramName: 'q', minChars: this.getMetadata().get(['entityDefs',this.entityType,'fields',this.name,'autocompleteMinChars']), beforeRender: ($c) => { if (this.$element.hasClass('input-sm')) { $c.addClass('small'); } }, formatResult: (suggestion) => { return this.getHelper().escapeString(suggestion.value); }, maxHeight: 200, onSearchStart: (q) => { // called before the Ajax request is made - could be used to pre-filter the search string } }; this.autocompleteOptions.transformResult = response => this.transformAutocompleteResult(response); if(this.isEditMode()) { this.$element.on('focus', () => { // trigger autocomplete this.$element.autocomplete(this.autocompleteOptions); this.$element.attr('autocomplete', 'espo-' + this.name); }); // define actions to take, if any, when the field value is being updated this.$element.on("input", () => { // define actions here }); // remove the autocomplete functionality after a field is saved and rendered again in detail mode this.once('render', () => { this.$element.autocomplete('dispose'); }); // remove the autocomplete functoinality if a field element is removed this.once('remove', () => { this.$element.autocomplete('dispose'); }); } }, // This function will need to be customized according to the structure of the JSON response from the external server transformAutocompleteResult: function (response) { let parsedResponse = JSON.parse(response); let list = []; // API RESPONSE SPECIFIC VALUES const jsonResponseDataContainer = 'features'; const jsonResponseItemAttribute = 'properties'; parsedResponse[jsonResponseDataContainer].forEach(item => { list.push({ id: item[jsonResponseItemAttribute].id, name: item[jsonResponseItemAttribute].name || item[jsonResponseItemAttribute].id, data: item[jsonResponseItemAttribute].id, value: item[jsonResponseItemAttribute].name || item[jsonResponseItemAttribute].id, attributes: item[jsonResponseItemAttribute] }); }); return { suggestions: list }; } }); });
<?php
namespace Espo\Custom\Controllers;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Api\Request;
use Espo\Core\Exceptions\NotFound;
use Espo\Custom\Services\AutocompleteFromApi as Service;
class AutocompleteFromApi
{
private Service $service;
public function __construct(Service $service)
{
$this->service = $service;
}
public function actionFetchJson(Request $request): string
{
$q = $request->getQueryParam('q') ?? null;
$scope = $request->getQueryParam('s') ?? null;
$recordId = $request->getQueryParam('id') ?? null;
$attribute = $request->getQueryParam('a') ?? null;
// verify input completeness
if (!$q) {
throw new BadRequest("No 'q' parameter.");
}
if (!$scope) {
throw new BadRequest("No 's' parameter.");
}
if (!$recordId) {
throw new BadRequest("No 'id' parameter.");
}
if (!$attribute) {
throw new BadRequest("No 'a' parameter.");
}
// remove all non-alphanumeric characters, allowing spaces to remain, and make the input string url safe
$cleanQ = urlencode(preg_replace("/[^A-Za-z0-9 ]/", "", $q));
$payload = [];
$payload['q'] = $cleanQ;
$payload['scope'] = $scope;
$payload['recordId'] = $recordId;
$payload['attribute'] = $attribute;
$payload['scope'] = $scope;
// invoke the method fetchJsonFromApi at AutocompleteFromApi service class
$autocompleteResponse = $this->service->fetchJsonFromApi($payload);
return $autocompleteResponse;
}
}
<?php
namespace Espo\Custom\Services;
use Espo\Core\Exceptions\Error;
class AutocompleteFromApi extends \Espo\Core\Templates\Services\Base
{
public function fetchJsonFromApi ($payload) {
// get the exernal api url from the scope's entityDefs
$autocompleteUrl = $this->metadata->get(['entityDefs', $payload['scope'], 'fields', $payload['attribute'], 'autocompleteSourceUrl']).'?q='.$payload['q'];
// get the API query paramteres from metadata
$qUrlModifier = $this->metadata->get(['entityDefs', $payload['scope'], 'fields', $payload['attribute'], 'autocompleteQmodifier']);
if(empty($qUrlModifier)) {
$qUrlModifier = '';
}
$urlFilters = $this->metadata->get(['entityDefs', $payload['scope'], 'fields', $payload['attribute'], 'autocompleteQueryFilters']);
$urlFilterModifier = '';
if(!empty($urlFilters)) {
$entity = $this->entityManager->getEntityById($payload['scope'], $payload['recordId']);
foreach($urlFilters as $filter) {
foreach($filter as $key => $val) {
if(str_contains($val, '.val()')) {
$filterParts = explode('.',$val);
$value = $entity->get($filterParts[0]);
if(!empty($value)) {
$urlFilterModifier.='&'.$key.'='.$value;
}
} else {
$urlFilterModifier.='&'.$key.'='.$val;
}
}
}
}
$url = $autocompleteUrl.$qUrlModifier.$urlFilterModifier;
$json = $this->callAPI('GET',$url);
return $json;
}
private function callAPI($method, $url, $data=false){
$curl = curl_init();
switch ($method){
case "POST":
curl_setopt($curl, CURLOPT_POST, 1);
if ($data)
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
break;
case "PUT":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
if ($data)
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
break;
default:
if ($data)
$url = sprintf("%s?%s", $url, http_build_query($data));
}
// set curl options:
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'APIKEY: 111111111111111111111',
'Content-Type: application/json',
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
// execute curl:
$result = curl_exec($curl);
if(!$result){die("Connection Failure");}
curl_close($curl);
return $result;
}
private function buildUrl($action, $params = [])
{
$params['private_token'] = self::PRIVATE_TOKEN;
$url = self::API_URL . $action . '?';
$count = count($params);
$i = 0;
foreach ($params as $key => $value) {
if (!empty($value)) {
$url .= $key . '=' . $value;
}
$i++;
if ($i < ($count)) {
$url .= '&';
}
}
return $url;
}
}
Leave a comment: