1

Please help me to refresh a single html element after the initial page load. What my program should do in basic terms: (FreeCodeCamp exercise: Random Quote Machine)

  • obtain random quote from API
  • display quote and author
  • button to obtain new quote/author
  • button to tweet the quote/author

I have succeeded in making everything work as it should but I find that my anchor element that I use to send the tweet will not refresh after the initial page load. Its "data-text" attribute has changed accordingly but it does not reflect so on the button/link.

This is an extract from my html body: full code at http://codepen.io/jattas/pen/gmNQpv

<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<div class="button-box">
  <button id="getQuote">Generate new quote</button>
  <a href="https://twitter.com/share" class="twitter-share-button" data-text="" data-show-count="false">Tweet</a>
  <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>

I need the anchor element to refresh in order to display the newly changed attribute and not the one from the initial page load. Please help! I'm sure this is not supposed to be so difficult.

This is the relevant extract from my javascript:

var textToTweet = '';

function processQuote() {

  var currentQuote = obj.quote;
  var currentAuthor = obj.author;
  $(".quote").html(currentQuote);
  $(".author").html("- " + currentAuthor);
  textToTweet = currentQuote + " " + "-" + currentAuthor;
  $(".twitter-share-button").attr("data-text", textToTweet);
  alert($(".twitter-share-button").attr("data-text"));       //this is to confirm that the "data-text" attribute has changed as planned
}

$(document).ready(function() {

  processQuote();

  $("#getQuote").on("click", function() {
    getQuote();
    processQuote();
  });

});

Many thanks.

JanPotgieter
  • 11
  • 1
  • 4
  • Where is the code of `getQuote`? – Satpal Apr 18 '17 at 12:20
  • Sorry. I didn't include it as I didn't think it was relevant. function getQuote() { $.ajax({headers: {"X-Mashape-Key": "Dl90qAQ9VQmshXTMzxEekaeOmVZVp1WneLgjsnnWyXci322XQi", Accept: "application/json", ContentType: "application/x-www-form-urlencoded"}, url: 'https://andruxnet-random-famous-quotes.p.mashape.com/?cat=famous', async: false, success: function(response) { obj = JSON.parse(response); } }) } – JanPotgieter Apr 18 '17 at 12:29
  • Invoke `processQuote();` in the `success` callback in `getQuote()` method; i.e. `obj = JSON.parse(response);processQuote();` – Satpal Apr 18 '17 at 12:38
  • I still get the same result. Attribute is changed successfully but I need the anchor to refresh in order to reflect the new information. The state of the anchor is as it was on initial page load. – JanPotgieter Apr 18 '17 at 12:47

2 Answers2

0

Guessing from your description I think your selectors for the quote and author elements are wrong. Since you don't show the html for those I'm not 100% sure though.

You probably load the elements with predefined text in html and then try to fill them with processQuote(). I thought of this, since you can fill the data attribute correctly, but seem to fail to update the link text. Please check if your elements really have class="quote" and class="author" and not ids or different names.

An easy way to verify this is to call your selector in your browsers developer console. You'll get an element back, that is also highlighted when hovered. If they don't return an element they are wrong.

As Satpal suggested you should call processQuote() within the callback function success. This is because your data is retrieved asynchronously and you can not guarantee you already have it when you reach processQuote() after calling getQuote().

Another small thing: Since you only want to change text, you can use .text('my text') instead of .html('my text'). This prevents injection (not likely in your case, but still a good practice imo).

Edit: I totally missed you point then sorry.

If you add this to your getQuote success case at the end it should work:

var parentElem = $('iframe').parent(); $('iframe').remove(); $(parentElem).append('<a href="https://twitter.com/share" class="twitter-share-button" data-text="' + obj.quote + '" data-show-count="false">Tweet</a>'); twttr.widgets.load();

I found this in another stack overflow page here.

All links were dead though, so I tried it myself. I never used a twitter button, so this might not be the best way to do it. Basically it deletes your current button and recreates it. You might want to try if special characters (especially quotes) still work with this way.

Community
  • 1
  • 1
Morfium
  • 241
  • 4
  • 7
  • Thanks, Morfium. You are right in how I initially load empty div elements before populating them with processQuote(). I've added my code to [Codepen](http://codepen.io/jattas/pen/gmNQpv?editors=1010) See the tweet button at the bottom of the page. If you press it it is populated with the quote shown at the top. This is exactly what it should do. However, once you click on 'Generate new quote' and you click on the tweet button again, it is still loaded with the initial quote. Therefore I think it should somehow be refreshed or reloaded. – JanPotgieter Apr 18 '17 at 13:54
  • I updated my answer. Please note that I'm not certain this is the best way. It looks and feels hacky and I didn't test it much. Hope it helps you solve your problem. – Morfium Apr 18 '17 at 14:59
  • Thanks for your time, Morfium. It worked but it did create additional buttons which I don't want. I managed to have it replace the original button by calling '$(".twitter-share-button").remove() as soon as I generate a new quote. The problem now is that the new button is in the wrong place (below my final html element instead of above it). Because of my limited knowledge of what the code was actually doing to it I couldn't get it to move. However, in the process of trying to fix this I did find a fairly simple solution (rather a work-around) to the problem which I will post as an answer. – JanPotgieter Apr 19 '17 at 12:23
  • Alright, glad you found a way. The reason for your positioning problems might be that the twitter code adds an iframe around your initial anchor element and adds all kinds of styling. That's why I removed the iframe and appended to its parent. But as I said, it looks quite hacky. :/ Maybe check your solution in different browsers. Maybe the script acts different based on the used browser. – Morfium Apr 19 '17 at 12:48
0

I found a work-around to this problem thanks to Danyx's answer to this question.

Morfium's solution above does work but it created additional buttons which were difficult to place where needed.

Instead, as per Danyx's solution, do not create the button in html. Rather create it in a function that runs each time a new quote is created:

function createButton() {           
  $(".twitter-share-button").remove();  //this does nothing during the first run but is required in order to prevent creating duplicate buttons
  var button = document.createElement('a');
  button.classList += "twitter-share-button";
  button.innerHTML = "Tweet";
  button.setAttribute("data-text", textToTweet);
  button.setAttribute("data-url", " "); //removes unwanted codepen url at end of tweet      
  button.setAttribute("data-via", "");
  button.setAttribute("href", "https://twitter.com/intent/tweet");
  document.querySelector(".button-box").appendChild(button);
  twttr.widgets.load();  //this reloads the twitter widget (https://dev.twitter.com/web/javascript/loading) that I failed to mention in my original question - more info on this in Danyx's answer mentioned above
}

The full code can be seen here.

Community
  • 1
  • 1
JanPotgieter
  • 11
  • 1
  • 4