0

I'm trying to make a Chrome extension that will take the headlines of a web page, send it to a language processing API which returns a "sentiment score", and then highlight the headlines on the page in different colors based on the weight of the score. I've got everything working except the highlighting functionality.

My guess is that because the XMLHTTPRequests are run asynchronously, they only return information after the DOM has finished loading, at which point it's too late to alter the CSS and change the element.style.backgroundColor. When I remove the API call and just have it check if the textContent matches a particular word or phrase, the highlighting works fine.

Is there anyway to have the page re-render after the data is received and the promise is resolved? I looked into the chrome "messages" but that doesn't seem to be the solution. Thanks for any advice you can provide!

Here's the script below. (I've removed headers from the HTTP request):

function highlightSentiment(){
 var elements = document.getElementsByTagName('a');

 for (var i = 0; i < elements.length; i++) {
  var element = elements[i];

   function highlight(sentiment){
      if(sentiment.type == "negative"){
        element.style.backgroundColor = "red";
        console.log("neg");
      } else if(sentiment.type == "positive"){
        console.log("pos");
        element.style.backgroundColor = "blue";
      }
    }

    var text = element.textContent;

    getSentiment(text).then(highlight, function(status){
          console.log("error");
    });
   }
  }

 function getSentiment(headline){
  var urltext = "text=" + headline.split(' ').join('+');
  return new Promise(function(resolve, reject){
    var req = new XMLHttpRequest();
      req.open(
              "GET",
              "https://twinword-sentiment-analysis.p.mashape.com/analyze/?"+
              urltext,
              true);

      req.responseType='json';
      req.onload = onResponseReceived;
      req.send(null); 
      function onResponseReceived() {
        var status = req.status;
        if(status ==200){
          resolve(req.response);
        } else {
          reject(status);
        }
      }
  });
 }
thesoorae
  • 11
  • 4
  • 1
    You should read the linked questions. They explain the problem, which is that your variables are not what you expect them to be *at the time the code is executed*, after the asynchronous call. A relatively simple solution is to change: `function highlight(sentiment){` to `function highlight(element,sentiment){` and `getSentiment(text).then(highlight, function(status){` to `getSentiment().then(highlight.bind(null,element), function(status){` – Makyen Feb 21 '17 at 02:22
  • thank you Makyen! That worked! I knew that I wouldn't have access to the variable within the callback, but couldn't figure out how to pass it in or bind it properly, since there was also the HTTP response being passed in. The null, element binding worked great! – thesoorae Feb 21 '17 at 03:13

1 Answers1

-1

(Edit - please ignore this - I hadn't heard of 'Promises' before this post.)

You want to call the HighlightSentiment() function after you receive the response, not as you make the request.

So, in onResponseReceived, in either the "if(status==200) {" block or in "resolve(req.response);" itself, call HighlightSentiment() with the returned data.

You have full control of the DOM even after you receive the response.

HTH, Jim

Jim
  • 201
  • 1
  • 8