title: jquery select2 (4.0) ajax with templateResult and templateSelection
body: <p>My Select2 was working on 3.5 correctly..</p>
  
  <p>Since upgrading to v4.0 (not "full" - and changing keywords/functions as needed), I have a weird problem where there are extra AJAX calls being made.  However, the URL is not defined, so they generate 404 Not Found errors.   The URL is <a href="https://localhost:8443/myapp/undefined" rel="nofollow">https://localhost:8443/myapp/undefined</a></p>
  
  <p>They seem to be related to the templateResult and templateSelection being present.  If I comment them out, the select2 works correctly (but my data is not formatted).</p>
  
  <p>With them not commented out, I get the mysterious/undefined AJAX call once at initialization, then one call is made when I click on the select  box, then once for <em>every</em> character I type (even if I set minimumInputLength).   However, even with these bogus AJAX calls, my "real" ajax call will fire and return results (which are properly formatted by templateResult/templateSelection.  I have tried with and without "escapeMarkup" with no difference in behavior.</p>
  
  <p>What is triggering these bad AJAX calls and how can I stop them?  (Because otherwise, it is working just fine) </p>
  
  <p>Thanks in advance!</p>
  
  <p><em>Edit</em>
  Here is a full page that demonstrates the issue.   The extra network calls are generated by the  tag that I use in the formatResult function.   But why is it returning the html when it should be in a "loading" state?</p>
  
  <p>Well, it turns out that setting the "placeholder" causes the loading variable to not be set, thus the html is returned (with its ill-formed  tag)</p>
  
  <p>So if a placeholder is set, the templateResult and templateSelection should also check for an empty id..</p>
  
  <pre><code>if (result.id == "" || result.loading) return result.text;
  
  &lt;!DOCTYPE html&gt;
  &lt;html lang="en"&gt;
  &lt;head&gt;
  &lt;meta charset="utf-8" /&gt;
  &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /&gt;
  &lt;title&gt;&lt;/title&gt;
  
  &lt;link rel="stylesheet" href="${pageContext.request.contextPath}/lib/select2/dist/css/select2.css" /&gt;
  &lt;/head&gt;
  &lt;body&gt;
  
  &lt;form id="organization_lookup_form" class="form-horizontal" &gt;
  &lt;div&gt;
      Select2 using placeholder &lt;select id="search1" style="width:300px"&gt;&lt;/select&gt;
  &lt;/div&gt;
  &lt;div style="padding-top:250px"&gt;
      Select2 WITHOUT placeholder &lt;select id="search2" style="width:300px"&gt;&lt;/select&gt;  
  &lt;/div&gt;
  &lt;/form&gt;
  
  &lt;script src="${pageContext.request.contextPath}/lib/jquery/dist/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script src="${pageContext.request.contextPath}/lib/select2/dist/js/select2.min.js"&gt;&lt;/script&gt;
  &lt;script&gt;
  $(document).ready(function () {
        function formatResult (result){
            console.log('%o', result);
            if (result.loading) return result.text;
            var html = '&lt;div&gt;'+
                  '&lt;img src="' + result.image + '"&gt;' +
                  '&lt;h4&gt;'+result.label+'&lt;/h4&gt;&lt;/div&gt;';
            return html;
        };
  
        $('#search1').select2({
            placeholder: "Search...",
            ajax: {
                url: '/search',
                dataType: 'json',
                data: function (params, page) {
                    return {
                        term: params.term, // search term
                        page: page
                    };
                },
                processResults: function (data, page) {
                    return {results: data.results};
                },
                cache: true
            },
            templateResult : formatResult,
            templateSelection : formatResult,
            escapeMarkup: function(m) {
                // Do not escape HTML in the select options text
                return m;
             },
            minimumInputLength: 3
        });
        $('#search2').select2({
  //        placeholder: "Search...",
            ajax: {
                url: '/search',
                dataType: 'json',
                data: function (params, page) {
                    return {
                        term: params.term, // search term
                        page: page
                    };
                },
                processResults: function (data, page) {
                    return {results: data.results};
                },
                cache: true
            },
            templateResult : formatResult,
            templateSelection : formatResult,
            escapeMarkup: function(m) {
                // Do not escape HTML in the select options text
                return m;
             },
            minimumInputLength: 3
        });
  });
  &lt;/script&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>