Listen in Content Script for when AJAX response changes textarea val

877 views Asked by At

I'm writing a WebExtension for a text editor. When the user clicks a button, format the editor fires an ajax request and then returns the formatted text. I need my addon to listen for a change in the textarea.

I've tried using onchange or oninput, but when the response is received, these events aren't triggered. The ajax response sets the body with this function (not my own):

function setBody(text) {
  $(opts.codeEl).val(text); // opts.codeEl is the textarea in question
}

the ajax response looks like this:

{"Body":"Hello World","Error":""}

Is it possible to handle this ajax request/response from a WebExtension Content Script? Somehow listen for a change in val of the textarea in the DOM? Can I listen and intercept the response?

The ajax request is being sent and received in the website's javascript code, isolated from the content script which I'm using (the WebExtension code) for the editor. the request is this

function fmt() {
  loading();
  var data = {"body": body()};
  if ($(opts.fmtImportEl).is(":checked")) {
    data["imports"] = "true";
  }
  $.ajax("/fmt", {
    data: data,
    type: "POST",
    dataType: "json",
    success: function(data) {
      if (data.Error) {
        setError(data.Error);
      } else {
        setBody(data.Body);
        setError("");
      }
    }
  });
}

Edit

Injecting a ajaxComplete handler:

  $(document).ajaxComplete(function(event, jqxhr, options) {
    if(options.url === "/fmt") {
      console.log("fmtted");
      $('#code').change();
    }
  });

Into the target site header will be called when the ajax response is received. However, when trying to modify the DOM using injected scripts (by, for example, calling change() or onchange(), for security reasons, it raises an Error: Permission denied to access property "apply" error.

1

There are 1 answers

9
guest271314 On BEST ANSWER

jQuery .val(value) does does dispatch change event. Call .change() or .trigger("change").

If you do not know when setBody will be called you can use .ajaxStop() to call .change() on $(opts.codeEl) when last $.ajax() call completes.

$(function() {

  let opts = {
    codeEl: document.querySelector("textarea")
  }

  $(opts.codeEl).on("change", function(event) {
    console.log("changed")
  });

  function setBody(text) {
    $(opts.codeEl).val(text)
  }

  let url = URL.createObjectURL(
    new Blob([
      JSON.stringify({
        "Body": "Hello World",
        "Error": ""
      })
    ], {
      type: "application/json"
    })
  );

  $.get(url)
  .then(function(data) {
    URL.revokeObjectURL(url);
    setBody(JSON.stringify(data))
  });
  
  $(document).ajaxComplete(function(event, jqxhr, options) {
    if (options.url === url) {
      console.log("ajaxStop");
      $(opts.codeEl).change(); // trigger `change` event
    }
    
  });

})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<textarea></textarea>