0

I have 2 lists in my Sharepoint : speeches and schools.
In my speeches form, I have a school field. I want to autocomplete this field with values (name, adress, city) from schools list.
Here's my code :

$(School_fieldID).autocomplete({
    minLength: 2,
    source: function (request, response) {
        var term = request.term.replace(/ /g, "*\",\"*");
        var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='and(\"*" + term + "*\",path:\"" + _spPageContextInfo.webAbsoluteUrl + "/Lists/Schools\")'&enablefql=true";
        var executor = new SP.RequestExecutor(_spPageContextInfo.webAbsoluteUrl);

        executor.executeAsync({
            url: searchUrl,
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            success: function (data) {
                var jsonObject = JSON.parse(data.body);
                var results = jsonObject.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
                var clientContext = new SP.ClientContext();
                var schoolList = clientContext.get_web().get_lists().getByTitle('Schools');

                response($.map(results, function (result) {
                    school = schoolList.getItemById(result.Cells.results[6].Value.split('=').pop());
                    clientContext.load(school, 'Title', 'Adress', 'City');
                    clientContext.executeQueryAsync(Function.createDelegate(this, function (schoolName, schoolAdress, schoolCity) {
                        schoolName = school.get_item('Title');
                        schoolAdress = school.get_item('Adress');
                        schoolCity = school.get_item('City');
                    }), Function.createDelegate(this, function (sender, args) {
                        alert('Error occured: ' + args.get_message());
                    }));
                    return {
                        label: schoolName + " (" + schoolAdress + " " + /*schoolCity + */ ")",
                        value: schoolName
                    };
                }));
            }
        });
    }
});

When I test this code, schoolName, schoolAdress et schoolCity are undefined because of asynchronous function executeQueryAsync.
So I think solution is in Promise or Callback, but I tried different solutions for a week, without success :-(
Please note I read carefully this post How do I return the response from an asynchronous call?, but can't find a good solution anyway...
Can anyone help me ?
Thanks in advance,
Florent

  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Andreas Mar 02 '18 at 15:47

1 Answers1

0

Considering you have to pass an array of objects to the response callback function and each one of the result is calling the async function clientContext.executeQueryAsync we can turn each one of them into a promise and pass them to Promise.all() which will wait for all of them to be resolved and returned them. When they are all resolved, the objects will be inside the schoolObjectArray which then you can pass to the response function. Is should work.

$(School_fieldID).autocomplete({
minLength: 2,
source: function (request, response) {
    var term = request.term.replace(/ /g, "*\",\"*");
    var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='and(\"*" + term + "*\",path:\"" + _spPageContextInfo.webAbsoluteUrl + "/Lists/Schools\")'&enablefql=true";
    var executor = new SP.RequestExecutor(_spPageContextInfo.webAbsoluteUrl);

    executor.executeAsync({
        url: searchUrl,
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {
            var jsonObject = JSON.parse(data.body);
            var results = jsonObject.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
            var clientContext = new SP.ClientContext();
            var schoolList = clientContext.get_web().get_lists().getByTitle('Schools');

            Promise.all($.map(results, function (result) {
                school = schoolList.getItemById(result.Cells.results[6].Value.split('=').pop());
                clientContext.load(school, 'Title', 'Adress', 'City');
                return new Promise(function(resolve,reject) {
                    clientContext.executeQueryAsync(Function.createDelegate(this, function (schoolName, schoolAdress, schoolCity) {
                    schoolName = school.get_item('Title');
                    schoolAdress = school.get_item('Adress');
                    schoolCity = school.get_item('City');
                    resolve({
                            label: schoolName + " (" + schoolAdress + " " + /*schoolCity + */ ")",
                            value: schoolName
                        });
                    }), Function.createDelegate(this, function (sender, args) {
                        reject('Error occured: ' + args.get_message());
                    }));
                })
            }))
            .then(function(schoolObjectArray){
                response(schoolObjectArray)
            })
            .catch(console.error);
            }
        });
    }
});
Mass C
  • 41
  • 4
  • Thanks for your answer :-) I tried this code but it return only one value. Do you know why ? I don't understand... – Florent Bignier Mar 07 '18 at 16:18
  • it should return the array with the values in it, being in the $map function. I dont think it will change but you could turn snippet: `$.map(results,` into `results.map(`. With "only one value" you mean it returns an array with one value or only an object? – Mass C Mar 08 '18 at 20:07