由于变量范围

时间:2018-01-27 14:03:02

标签: javascript jquery jquery-ui jquery-ui-autocomplete

我遇到的问题是由于变量范围,我无法从jQuery UI自动完成表单中获得任何结果。让我告诉你。

// TAKE A CLOSE LOOK AT THIS METHOD
select: function(e, ui) {

$('#instant-search').text(ui.item.label);
$("#search").autocomplete("option", "source",
  function(request, response) {
    getAutocompleteResults(function(d) {
      // DOESN'T WORK response(d);
    });
    // WORKS BUT IT SHOULD BE A DYNAMIC ARRAY FROM THE "D" OBJECT
    // response(["anarchism", "anarchist black cross", "black rose (symbolism)", "communist symbolism", "political symbolism"]);
  });

$("#search").autocomplete("search", ui.item.label);

为了返回结果,我必须在response([...]);函数之外使用函数getAutocompleteResults(function(d) { ... });

但是,源应该是动态的,而不是静态数组。换句话说:

函数response(d);应返回一个对象,该对象包含一些属性(标题,值,提取)。我必须使用response(d);访问它们,但是,此函数在getAutocompleteResults(function(d) { ... });函数内不起作用。我怎样才能做到这一点?

有一小段代码,但主要问题是select方法。您可以在整个代码块的中间找到它。我评论了它。

$(function() {
  $("html").removeClass("no-js");
  var autocompleteResults = [{
    title: [],
    extract: [],
    pageId: []
  }];

  var capitalizeFirstLetter = function(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };

  var changeText2 = function(e) {
    var request = $("input").val() + String.fromCharCode(e.which);
    $("#instant-search").text(request);

    var getAutocompleteResults = function(callback) {
      $.ajax({
        url: "https://en.wikipedia.org/w/api.php?format=json&action=query&generator=search&gsrlimit=6&prop=extracts&origin=*&pilimit=max&exintro&explaintext&exsentences=1&gsrsearch=" +
          $("#instant-search").text(),
        beforeSend: function() {
          $(".loading").show();
        },
        success: function(d) {
          $(".loading").hide();
          autocompleteResults[0].title = [];
          autocompleteResults[0].extract = [];
          autocompleteResults[0].pageId = [];

          if (d.hasOwnProperty("query")) {
            if (d.query.hasOwnProperty("pages")) {
              $.each(d.query.pages, function(i) {
                autocompleteResults[0].title.push(d.query.pages[i].title);

                autocompleteResults[0].extract.push(d.query.pages[i].extract);
                autocompleteResults[0].pageId.push(d.query.pages[i].pageid);
              });
            }
          }

          if (!autocompleteResults[0].length) {
            $(".ui-autocomplete").hide();
          }


          autocompleteResults[0].title.sort(function(a, b) {
            var nameA = a.toUpperCase();
            var nameB = b.toUpperCase();
            if (nameA < nameB) {
              return -1;
            }
            if (nameA > nameB) {
              return 1;
            }

            return 0;
          });

          autocompleteResults[0].title = autocompleteResults[0].title.map(
            function(i) {
              return i.toLowerCase();
            }
          );

          callback(autocompleteResults[0]);
        },
        datatype: "json",
        cache: false
      });
    };

    $("#search").autocomplete({
      source: function(request, response) {
        getAutocompleteResults(function(d) {
          var results = [],
            filteredAutocompleteResults = [];

          filteredAutocompleteResults = d.title.filter(function(i) {
            return (
              i !=
              $("#instant-search")
              .text()
              .toLowerCase()
            );
          });

          for (var i = 0; i < d.title.length; i++) {
            results[i] = {
              label: filteredAutocompleteResults[i],
              extract: d.extract[i],
              pageId: d.pageId[i]
            };
          }

          if (results.length == 5) {
            response(results);
          } else {
            response(results.slice(0, 5));
          }
        });
      },
      response: function() {
        if ($("#instant-search").text()) {
          $("table").css("display", "table");
          $(".wikisearch-container").css("margin-top", 100);
        }
      },
      close: function() {
        if (!$(".ui-autocomplete").is(":visible")) {
          $(".ui-autocomplete").show();
        }
      },
      appendTo: ".input",
      focus: function(e) {
        e.preventDefault();
      },
      delay: 0,












      // TAKE A CLOSE LOOK AT THIS METHOD
      select: function(e, ui) {

        $('#instant-search').text(ui.item.label);
        $("#search").autocomplete("option", "source",
          function(request, response) {
            getAutocompleteResults(function(d) {
              // DOESN'T WORK response(d);
            });
            // WORKS BUT IT SHOULD BE A DYNAMIC ARRAY FROM THE "D" OBJECT
            // response(["anarchism", "anarchist black cross", "black rose (symbolism)", "communist symbolism", "political symbolism"]);
          });

        $("#search").autocomplete("search", ui.item.label);










        // EVERYTHING SHOULD BE FINE BELOW THIS LINE

        if ($(".search-results").css("opacity") != 1) {
          $(".search-results h4").text(capitalizeFirstLetter(ui.item.label));
          $(".search-results p").text(ui.item.extract);
          $(".search-results a").prop(
            "href",
            "https://en.wikipedia.org/?curid=" + ui.item.pageId
          );
          $(".search-results").css("opacity", 1);
        } else if (
          $(".search-results h4")
          .text()
          .toLowerCase() != ui.item.label
        ) {
          $(".search-results").css("opacity", 0);
          setTimeout(function() {
            $(".search-results h4").text(capitalizeFirstLetter(ui.item.label));
            $(".search-results p").text(ui.item.extract);
            $(".search-results a").prop(
              "href",
              "https://en.wikipedia.org/?curid=" + ui.item.pageId
            );
            $(".search-results").css("opacity", 1);
          }, 500);
        }
      },
      create: function() {
        $(this).data("ui-autocomplete")._renderItem = function(ul, item) {
          return $("<li>")
            .append(
              '<div class="ui-menu-item-wrapper"><div class="autocomplete-first-field"><i class="fa fa-search" aria-hidden="true"></i></div><div class="autocomplete-second-field three-dots">' +
              item.label +
              "</div></div>"
            )
            .appendTo(ul);
        };
      }
    });
  };


  var changeText1 = function(e) {
    if (
      /[-a-z0-90áãâäàéêëèíîïìóõôöòúûüùçñ!@#$%^&*()_+|~=`{}\[\]:";'<>?,.\s\/]+/gi.test(
        String.fromCharCode(e.which)
      )
    ) {
      $("input").on("keypress", changeText2);
    }


    // DONT TOUCH THIS AREA, IT HAS NOTHING TO DO WITH THE PROBLEM
    var getInputSelection = function(input) {
      var start = 0,
        end = 0;
      input.focus();
      if (
        typeof input.selectionStart == "number" &&
        typeof input.selectionEnd == "number"
      ) {
        start = input.selectionStart;
        end = input.selectionEnd;
      } else if (document.selection && document.selection.createRange) {
        var range = document.selection.createRange();
        if (range) {
          var inputRange = input.createTextRange();
          var workingRange = inputRange.duplicate();
          var bookmark = range.getBookmark();
          inputRange.moveToBookmark(bookmark);
          workingRange.setEndPoint("EndToEnd", inputRange);
          end = workingRange.text.length;
          workingRange.setEndPoint("EndToStart", inputRange);
          start = workingRange.text.length;
        }
      }
      return {
        start: start,
        end: end,
        length: end - start
      };
    };

    switch (e.key) {
      case "Backspace":
      case "Delete":
        e = e || window.event;
        var keyCode = e.keyCode;
        var deleteKey = keyCode == 46;
        var sel, deletedText, val;
        val = this.value;
        sel = getInputSelection(this);
        if (sel.length) {
          // 0 kai paprastai trini po viena o 1 ar daugiau kai select su pele trini
          $("#instant-search").text(
            val.substr(0, sel.start) + val.substr(sel.end)
          );
        } else {
          $("#instant-search").text(
            val.substr(0, deleteKey ? sel.start : sel.start - 1) +
            val.substr(deleteKey ? sel.end + 1 : sel.end)
          );
        }
        break;
      case "Enter":
        if ($("#instant-search").text()) {
          console.log("Redirecting...");
        }
        break;
    }

    if (!$("#instant-search").text()) {
      $("table, .ui-autocomplete").hide();
      $(".wikisearch-container").css("margin-top", "");
    }

    if (
      $(".ui-menu-item-wrapper").hasClass("ui-state-active") &&
      (e.key == "ArrowRight" || e.key == "ArrowLeft")
    ) {
      $(".ui-autocomplete").autocomplete(""); // Error metas console ir taip neturėtų būti bet nežinau kaip padaryti kad pasirinkus elementą su <-- ar --> nepadarytų tik vieno rezultato todėl paliekam laikinai ;)
    }
  };

  $("input").on("keydown", changeText1);

  $("input").on("input", function(e) {
    $("#instant-search").text($("#search").val());
  });

});
html,
body {
  height: 100%;
  width: 100%;
}

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  background-image: url("http://www.part.lt/img/96816a00ec1fb87adc4ca8a04365b2b5719.jpg");
  background-size: cover;
  background-position: 100%;
}

.v-container {
  display: table;
  height: 100%;
  width: 100%;
}

.v-content {
  display: table-cell;
  vertical-align: middle;
}

.text-center {
  text-align: center;
}

.input {
  overflow: hidden;
  white-space: nowrap;
}

.input input#search {
  width: calc(100% - 30px);
  height: 50px;
  border: none;
  font-size: 10pt;
  float: left;
  color: #4f5b66;
  padding: 0 15px;
  outline: none;
}

.ui-autocomplete {
  list-style: none;
  background-color: #fff;
  -webkit-user-select: none;
  user-select: none;
  padding: 0;
  margin: 0;
  width: 100% !important;
  top: auto !important;
  display: table;
  table-layout: fixed;
}

.ui-helper-hidden-accessible {
  display: none;
}

.autocomplete-first-field {
  width: 15%;
  display: inline-block;
}

.autocomplete-second-field {
  width: 85%;
  display: inline-block;
  text-align: left;
  vertical-align: middle;
}

.three-dots {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

table {
  width: 100%;
  border-spacing: 0;
  border-collapse: collapse;
  display: none;
  table-layout: fixed;
}

table tr {
  background-color: #fff;
  -webkit-user-select: none;
  user-select: none;
}

tr:first-child {
  background-color: #ffc800;
  color: #fff;
}

table td,
.ui-menu-item-wrapper {
  padding: 10px 0;
}

td:nth-child(2) {
  width: 85%;
  text-align: left;
}

.ui-menu-item,
table {
  cursor: pointer;
}

:focus {
  outline: 0;
}

a {
  text-decoration: none;
  color: #fff;
  position: relative;
}

a:before {
  content: "";
  position: absolute;
  width: 100%;
  height: 0.0625rem;
  bottom: 0;
  left: 0;
  background-color: #fff;
  visibility: hidden;
  -webkit-transform: scaleX(0);
  transform: scaleX(0);
  -webkit-transition: all 0.3s ease-in-out 0s;
  transition: all 0.3s ease-in-out 0s;
}

a:hover:before {
  visibility: visible;
  -webkit-transform: scaleX(1);
  transform: scaleX(1);
}

.search-results {
  background: #fff;
  margin-top: 50px;
  border-left: 5px solid #0ebeff;
  opacity: 0;
  -webkit-transition: opacity 1s;
  transition: opacity 1s;
}

.search-results h4,
.search-results p {
  margin: 0;
  padding: 10px;
  text-align: left;
}

.search-results a {
  color: #0ebeff;
  display: inline-block;
  margin: 1rem 0;
}

.search-results a:before {
  background-color: #0ebeff;
}

.wikisearch-container {
  width: 65%;
  margin: 0 auto;
}


/* Loading animation */

@keyframes lds-eclipse {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  50% {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

@-webkit-keyframes lds-eclipse {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  50% {
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

.loading {
  position: relative;
  top: 9.5px;
  right: 15px;
  pointer-events: none;
  display: none;
}

.lds-eclipse {
  -webkit-animation: lds-eclipse 1s linear infinite;
  animation: lds-eclipse 1s linear infinite;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  margin-left: auto;
  box-shadow: 0.08rem 0 0 #0ebeff;
}

@media (max-width: 71.875em) {
  .wikisearch-container {
    width: 75%;
  }
}

@media (max-width: 50em) {
  .wikisearch-container {
    width: 85%;
  }
}

@media (max-width: 17.96875em) {
  .wikisearch-container {
    width: 100%;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<html class="no-js">
<div class="v-container">
  <div class="v-content text-center">
    <div class="wikisearch-container">
      <div class="input">
        <input type="text" id="search" placeholder="Search...">
        <div class="loading">
          <div class="lds-eclipse"></div>
        </div>
        <button class="icon"><i class="fa fa-search"></i></button>
        <table>
          <tr>
            <td class="fa fa-search">
              <td id="instant-search" class="three-dots"></td>
          </tr>
        </table>
      </div>
      <div class="search-results">
        <h4></h4>
        <p></p>
        <a target="_blank">Click here for more</a>
      </div>
    </div>
  </div>
</div>

编辑1 经过一些更改后,会在ajax调用之前显示结果。如何在成功完成ajax之后使用response()(尝试使用success回调,不起作用:()?

完整的项目代码:https://codepen.io/Kestis500/pen/zRONyw?editors=0010

在这里,您可以逐步了解它的外观:

  1. 刚重新加载页面时的样子: enter image description here
  2. 让我们尝试输入“a”: enter image description here
  3. 我们有一些结果。好的,让我们尝试点击“无政府主义象征主义”元素: enter image description here
  4. 结果应该看起来像“无政府主义象征主义”搜索。但是,它返回“a”搜索的结果。如果我们按下“fraktur”元素怎么办? enter image description here
  5. 现在它显示了我们之前搜索的“无政府主义象征主义”结果。但是,它应该返回“fraktur”搜索的元素。
  6. 编辑2 我修复了很多东西,并从我的代码中删除了一些非常无意义的东西。但是,ajax调用的情况仍然相同。

    https://codepen.io/Kestis500/pen/pazppP?editors=0110

    有什么想法吗?

    编辑3 修复了ajax滞后(现在只有在前一个ajax调用之后才会发送ajax请求)。

    https://codepen.io/Kestis500/pen/JpPLON?editors=0110

1 个答案:

答案 0 :(得分:1)

我必须首先修复Ajax调用中的一些内容。然后,我们收集结果并构建一个应返回response()的数组。这将填充AutoComplete。

首先,我们将检查HTML。有一些结束标签丢失。

<强> HTML

<div class="v-container">
  <div class="v-content text-center">
    <div class="wikisearch-container">
      <div class="input ui-front">
        <input type="text" id="search" placeholder="Search...">
        <div class="loading">
          <div class="lds-eclipse"></div>
        </div>
        <button class="icon">
          <i class="fa fa-search"></i>
        </button>
        <table>
          <tr>
            <td class="fa fa-search"></td>
            <td id="instant-search" class="three-dots"></td>
          </tr>
        </table>
      </div>
      <div class="search-results">
        <h4></h4>
        <p></p>
        <a target="_blank">Click here for more</a>
      </div>
    </div>
  </div>
</div>

您可以看到table并且它的单元格现在都有正确的结束标记。

我没有对CSS或Style进行任何更改。

<强>的JavaScript

$(function() {
  var capitalizeFirstLetter = function(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };
  $("#search").autocomplete({
    source: function(request, response) {
      var results = [];
      $.ajax({
        url: "https://en.wikipedia.org/w/api.php",
        data: {
          format: "json",
          action: "query",
          generator: "search",
          gsrlimit: 6,
          prop: "extracts|pageimages",
          origin: "*",
          pilimit: "max",
          exintro: false,
          explaintext: false,
          exsentences: 1,
          gsrsearch: request.term
        },
        beforeSend: function() {
          $(".loading").show();
        },
        success: function(d) {
          $(".loading").hide();
          if (d.query.pages) {
            $.each(d.query.pages, function(k, v) {
              console.log(k, v.title, v.extract, v.pageid);
              results.push({
                label: v.title,
                value: "https://en.wikipedia.org/?curid=" + v.pageid,
                title: v.title,
                extract: v.extract,
                pageId: v.pageid
              });
            });
            response(results);
          }
        },
        datatype: "json",
        cache: false
      });
      response(results);
    },
    close: function() {
      if (!$(".ui-autocomplete").is(":visible")) {
        $(".ui-autocomplete").show();
      }
    },
    focus: function(e) {
      e.preventDefault();
      return false;
    },
    delay: 0,
    select: function(e, ui) {
      if ($(".search-results").css("opacity") != 1) {
        $(".search-results h4").text(capitalizeFirstLetter(ui.item.label));
        $(".search-results p").text(ui.item.extract);
        $(".search-results a").prop(
          "href",
          ui.item.value
        );
        $(".search-results").css("opacity", 1);
      } else if (
        $(".search-results h4")
        .text()
        .toLowerCase() != ui.item.label
      ) {
        $(".search-results").css("opacity", 0);
        setTimeout(function() {
          $(".search-results h4").text(capitalizeFirstLetter(ui.item.label));
          $(".search-results p").text(ui.item.extract);
          $(".search-results a").prop(
            "href",
            ui.item.value
          );
          $(".search-results").css("opacity", 1);
        }, 500);
      }
      return false;
    }
  }).autocomplete("instance")._renderItem = function(ul, item) {
    var $item = $("<li>");
    var $wrap = $("<div>").appendTo($item);
    var $field1 = $("<div>", {
      class: "autocomplete-first-field"
    }).appendTo($wrap);
    $("<i>", {
      class: "fa fa-search",
      "aria-hidden": true
    }).appendTo($field1);
    $("<div>", {
      class: "autocomplete-second-field three-dots"
    }).html(item.label).appendTo($wrap);
    return $item.appendTo(ul);
  };
});

有很多事情需要修复和改进。

让我们从Ajax开始。您正在调用MediaWiki API并期待一些结果。当呼叫返回时,它将生成关于pilimit的警告。深入研究API文档,这是一个特定于pageimages属性调用的参数。要解决此问题,prop值必须为extracts|pageimages。现在我得到一套干净的结果。

您可以看到我打破了数据,以便我可以更轻松地进行更改,并查看我发送给API的参数。你的方法没有错,我发现这更容易使用。

当我们填充.autocomplete()时,source内部就会发生这种情况。当我们将function用作source时,必须遵循一些准则:

  • 我们在
  • 中传递requestresponse
  • 结果必须在数组中
  • 数组可以包含对象,只要它们至少包含{ label, value }
  • 我们的结果数组必须传递给response函数。

一个简短的例子:

$(selector).autocomplete({
  source: function(req, resp){
    var q = req.term;
    // The Request is an object that contains 1 index: term
    // request.term will contain the content of our search
    var results = [];
    // An array to store the results
    $.getJSON("myapi.php", {query: q}, function(data){
      $.each(data, function(key, val){
        // iterate over the result data and populate our result array
        results.push({
          label: data.name,
          value: data.url
        });
        resp(results);
      });
    });
  }
});

您可以按自己喜欢的方式对结果进行排序或过滤;只要你最后将它们传递给response

使用focusselect回调,您希望返回false。这里将对此进行更多讨论:http://jqueryui.com/autocomplete/#custom-data

我们也看到了渲染菜单项的一个很好的例子。我转而制作jQuery对象与原始HTML。你做的最适合你。

工作示例:https://jsfiddle.net/Twisty/vr6gv2aw/4/

希望这有帮助。