-1

I know questions similar to this wrt the confusing nature of $(this) have been asked many times before, but I still couldn't figure this out reading through them; apologies in advance if this is really simple / already answered elsewhere.

I have an input form with an autocomplete which gets its suggestions from a JSON file.

HTML:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <link rel="stylesheet" type="text/css" href="style.css">
    <title>HTML Form</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
    <input type="text" name="example" id="example">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="code.js"></script>
</body>

Then I have some javascript

$(document).ready(function () {
    $("#example").autocomplete({
        source: function () {
            console.log($(this).prop("id"));
            var suggestions = [];
            $.getJSON("parameters.json", function (data) {
                $.each(data, function (key, val) {
                    if (key == $(this).prop("id")) {
                        suggestions = val;

                    }
                });
            })
            return suggestions;
        }
    });

    $("#example").keyup(function () {
        console.log($(this).prop("id"));
    })
});

The console.log($(this).prop("id")); in the $("#example").keyup() event handler binder outputs "example", as expected. However, the console.log($(this).prop("id")); in the code for the autocomplete widget outputs Undefined. Why is this happening? If I remove the .prop("id") from both then they return JQuery Objects

Where the top object is outputted from the keyup and the bottom is from the autocomplete.

Could anyone explain the discrepancy here? Thanks!

Padaca
  • 337
  • 1
  • 6
  • 2
    Why would you use $(this).prop on something that isn't a dom element? it's just an object... access it's properties like any other object. – Kevin B Jul 17 '19 at 19:40
  • Oh, i see, that's your problem. You expected `this` to refer to the input element... but it in fact does not. You mightaswell just do `key === 'example'`, id's shouldn't be changing anyway. Otherwise, you'll need to bind that function (and the one above it) such that it has the expected `this`. – Kevin B Jul 17 '19 at 19:44
  • `$(this)` is `undefined`. `this` within the function passed to the `source` property of the autocomplete options **is not** the `input` on which the autocomplete is instantiated, but the function itself. – Louys Patrice Bessette Jul 17 '19 at 20:06
  • Inside `$.each()`, `this` refers to the current object in the iteration, it's the same as `val`. – Barmar Jul 17 '19 at 20:16
  • You know what's the `id`... Why do you want to use `this` anyway? – Louys Patrice Bessette Jul 17 '19 at 20:18
  • Why do you need to use `$(this).prop('id')` in the first place? You bind the handler to a specific ID, it will always be `example`. – Barmar Jul 17 '19 at 20:18
  • In my actual the one autocomplete is going to be used for multiple inputs, that's why I don't have it addressed by id – Padaca Jul 18 '19 at 12:58

1 Answers1

-1

You can interrogate the $(this) object to find what you're looking for. Using console.log($(this)) jQuery returns an array containing one object. That object includes a another array of objects called "elements" which contains a reference to the <input> element.

I used $(this)[0].element[0].id instead of $(this).prop("id") and it worked, even when I added multiple <input> elements and bound the autocomplete function by class rather than ID.

EDIT

To further my answer - which is likely to be more useful that the oblique references and dismissals provided by some others. The following will handle the callback issue described by @Barmar and will allow to you get access to the ID as you describe.

$(document).ready(function () {
    $("#example").autocomplete({
        source: function () {
            var suggestions = [];
            var elementId = $(this)[0].element[0].id;
            $.getJSON("parameters.json", function (data) {
                $.each(data, function (key, val) {
                    console.log(elementId);
                    if (key == elementId) {
                        suggestions = val;
                    }
                });
            });
            return suggestions;
        }
    });

    $("#example").keyup(function () {
        console.log($(this).prop("id"));
    });
});

The variable elementId catches the ID while the $(this) is still in the correct context and makes it available to the delegate functions resulting from $.getJSON and $.each. In my example, elementId would be written out to console for each returned key/val pair.

  • When you call a jQuery method that returns information on a collection, it automatically returns it from the first element. You don't need to index it yourself. – Barmar Jul 17 '19 at 20:12
  • the problem in the question is that `this` doesn't refer to the element at all. – Barmar Jul 17 '19 at 20:13
  • You're right that `$(this)` doesn't refer directly to the element but it does include a reference to the element which is easily accessible. Agree with the short hand re: not requiring an index. Disagree with your understanding of the OP's problem and requirement. – Craig Hunter Jul 17 '19 at 20:17
  • The problem is that he's using `$(this).prop('id')` inside `$.each`. In that callback, `this` is the current element of the `data` array, not a DOM element at all. I've marked this as a duplicate of a question that explains how to access the outer `this` variable. – Barmar Jul 17 '19 at 20:20