简体   繁体   中英

Order in jQuery calls

I have a jQuery loop that iterates over specifics elements of an HTML page. For every element, I do a switch over a variable and append HTML code in specific places.

The problem is that, one of those appends is an import to another Javascript file. This file uses a variable from the first one but, for some reason, that variable doesn't always have the correct value, depending on the order of the HTML elements in the page.

UPDATE

As requested, I created a Plunker so it's easy to see code: http://plnkr.co/edit/mrEhgbZhhvu0Z4iniXGl?p=preview

Note : For this to work, you need to have correct pageId and appId for Instagram.

I'll put the code to be more clear:

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Demo</title>
    <link rel="stylesheet" href="estilo.css">
  </head>
  <body>
    <section id="rrss">
      <!-- If I put this article block as the last one, it works -->
      <article id="instagram">
        <div data-rrss="instagram"></div>
      </article>
      <br/>
      <article id="facebook">
        <div data-rrss="facebook"></div>
      </article>
      <br/>
      <article id="twitter">
        <div data-rrss="twitter"></div>
      </article>
    </section>

    <!-- SCRIPTS -->
    <script src='scripts/data.js'></script>
    <script src='scripts/jquery.js'></script>
    <script>var customJquery = $.noConflict(true);</script>
    <script src='../magic.js'></script>
  </body>
</html>

data.js

var data = {
  "facebook": {
    "id": "facebook",
    "width": 0,
    "height": 0,
    "custom_style": "border:none;overflow:hidden",
    "hide_cover": false,
    "show_facepile": true,
    "small_header": false,
    "adapt_container_width": true
  },
  "twitter": {
    "id": "twitter",
    "width": 0,
    "height": 0,
    "chrome": "nofooter noscrollbar noheader", // noborders  transparent
    "tweet_limit": 0,
    "lang": "es",
    "theme": "dark",
    "link_color": "#0084b4"
  },
  "instagram": {
    "id": "123456798123467/9876543219876543",
    "hidecaption": false,
    "custom_style": "overflow:auto;",
    "max_width": 0,
    "max_height": 500
  },
  "defaults": {
    "width": 380,
    "height": 500
  }
}

magic.js

var rrss = customJquery('div[data-rrss]');
var conf = undefined;
var defaults = undefined;
var node = document.querySelectorAll('[data-rrss="instagram"]')[0];

customJquery.each(rrss, function(ix, it) {
    var html = '';

    var network = customJquery(it).data('rrss');

    if (network === undefined || network == null || network.length <= 0)
        return;


    conf = data[network];

    if (conf === undefined ||conf === null || conf.length <= 0)
        return;

    defaults = data['defaults'];

    //Comprobamos si existe el key y si el value tiene texto
    if(conf.id === undefined || conf.id === null || conf.id.length === 0)
        return;

    switch(network) {
        case 'facebook':
            html =  '<iframe id="iFB" src="https://www.facebook.com/plugins/page.php?href=https%3A%2F%2Fwww.facebook.com%2F' + conf.id +
                        '&tabs=timeline' +
                        '&width=' + (conf.width <= 0 ? defaults.width : conf.width) +
                        '&height=' + (conf.height <= 0 ? defaults.height : conf.height) +
                        '&small_header=' + conf.small_header +
                        '&adapt_container_width=' + conf.adapt_container_width +
                        '&hide_cover=' + conf.hide_cover +
                        '&show_facepile=' + conf.show_facepile + '"' +
                        'width="' + (conf.width <= 0 ? defaults.width : conf.width) + '" ' +
                        'height="' + (conf.height <= 0 ? defaults.height : conf.height) + '" ' +
                        'style="' + conf.custom_style + '" ' +
                        'scrolling="no" frameborder="0" allowTransparency="true" allow="encrypted-media"></iframe>\n' +
                    '<script type="text/javascript">\n' +
                    '  setInterval(() => {\n' +
                    '    customJquery("#iFB")[0].src = customJquery("#iFB")[0].src\n' +
                    '  }, 5 * 60 * 1000);\n'
                    '</script>';
        break;
        case 'twitter':
            html =  '<a class="twitter-timeline" '+
                        'href="https://twitter.com/' + conf.id + '" ' +
                        'data-width="' + (conf.width <= 0 ? defaults.width : conf.width) + '" ' +
                        'data-height="' + (conf.height <= 0 ? defaults.height : conf.height) + '" ';

            if (conf.chrome !== undefined && conf.chrome !== '') {
                html += 'data-chrome="' + conf.chrome + '" ';
            }

            if (conf.tweet_limit > 0) {
                html += 'data-tweet-limit="' + conf.tweet_limit + '" ';
            }

            html += 'data-lang="' + conf.lang + '" ' +
                    'data-theme="' + conf.theme + '" ' +
                    'data-link-color="' + conf.link_color + '"' +
                    '>Tweets by ' + conf.id + '</a>\n' +
                    '<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>';
        break;
        case 'instagram':
            node = node.parentElement;
            html =  '<script async src="https://connect.facebook.net/es_ES/sdk.js"></script>\n' +
                    '<script src="../insta.js"></script>\n' +
                    '<script async defer src="https://www.instagram.com/embed.js"></script>\n' +
                    '<script>\n'+
                    '  setInterval(() => {\n' +
                    '    if (document.readyState === "complete") {\n' +
                    '      window.instgrm.Embeds.process();\n' +
                    '    }\n' +
                    '  }, 100);\n' +
                    '  setInterval(() => {\n' +
                    '    fbAsyncInit();\n' +
                    '  }, 5 * 60 * 1000);\n'
                    '</script>';
        break;
        default:
            html = '';
    }

    if (html != '') {
        customJquery(it).replaceWith(html);
    }
});

insta.js

window.fbAsyncInit = function () {
  var html = '';
  var style = '';

  // When the Instagram's article bloke in HTML isn't the last one, this shows data from Twitter bloke
  console.log(conf);

  if (node !== undefined) {
    if (document.getElementById('instagram') !== null) {
      document.getElementById('instagram').innerHTML = '';
    }

    if (conf !== undefined && conf !== '') {
      if (conf.max_width !== undefined && conf.max_width > 0) {
        style += 'max-width: ' + conf.max_width + 'px;';
      } else {
        style += 'max-width: ' + defaults.width + 'px;';
      }

      if (conf.max_height !== undefined && conf.max_height > 0) {
        style += 'max-height: ' + conf.max_height + 'px;';
      } else {
        style += 'max-height: ' + defaults.height + 'px;';
      }

      style += conf.custom_style;
    }

    var div = document.createElement('div');
    div.id = 'instagram';

    if (style !== '') {
      div.style = style;
    }

    node.appendChild(div);
  }

  var pageId = conf.id.substring(0, conf.id.indexOf('/'));
  var appId = conf.id.substring(conf.id.indexOf('/') + 1);

  FB.init({
    appId: appId,
    autoLogAppEvents: true,
    xfbml: true,
    version: "v3.1"
  });

  FB.getLoginStatus(function (response) {
    if (response.status === "connected") {
      FB.api(
        "/" + pageId + "/",
        "GET", { "fields": "instagram_business_account" },
        function (response) {
          if (response.error && response.error !== '') {
            console.log("Error recovering 'instagram_business_account': " + response.error.message);
          } else {
            FB.api(
              "/" + response.instagram_business_account.id + "/media",
              "GET", { "fields": "shortcode" },
              function (response) {
                for (var i = 0; i < response.data.length; i++) {
                  var xhttp = new XMLHttpRequest();

                  xhttp.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                      html = JSON.parse(this.response).html;
                      document.getElementById("instagram").innerHTML += html;
                    }
                  };

                  xhttp.open("GET", "https://api.instagram.com/oembed/?url=http://instagr.am/p/" + response.data[i].shortcode + "&omitscript=true&hidecaption=" + conf.hidecaption, true);
                  xhttp.send();
                }
              }
            );
          }
        }
      );
    } else {
      console.log("Error recovering access token: Not connected.")
      console.log(response)
    }
  });
};

Well, I've solved with some ugly lonely line:

case 'instagram':
    node = node.parentElement;
    instaconf = conf; // ***** Saved the conf here *****
    html = '<script async src="https://connect.facebook.net/es_ES/sdk.js"></script>\n' +
           '<script src="../tecInsta.js"></script>\n' +
           '<script async defer src="https://www.instagram.com/embed.js"></script>\n' +
           '<script>\n'+
           '  setInterval(() => {\n' +
           '    if (document.readyState === "complete") {\n' +
           '      window.instgrm.Embeds.process();\n' +
           '    }\n' +
           '  }, 100);\n' +
           '  setInterval(() => {\n' +
           '    fbAsyncInit();\n' +
           '  }, 5 * 60 * 1000);\n'
           '</script>';
    break;

Then changed the conf references to instaconf in insta.js file.

Since this file was loaded after the jQuery loops ended, the configuration was the last one in that loop (the last article in index.html file).

Here the problem is you are appending HTML elements dynamically. Here jquery will append in DOM then browser will some time to parse. Until that controller wont wait for the operation so loop continue execution. so here config is hold last element of twitter configuration.

And we can't pass reference to html string as per my knowledge. This we can achieve by passing config as string into html string from there we can pass to fbAsyncInit() method.

                    '<script>\n'+
                '  setInterval(() => {\n' +
                '    if (document.readyState === "complete") {\n' +
                '      window.instgrm.Embeds.process();\n' +
                '    }\n' +
                '  }, 100);\n' +
                '  setInterval(() => {\n' +
                ' let configuration = '+ JSON.stringify(conf) +';'+
                '    fbAsyncInit(configuration);\n' +
                '  }, 5 * 60 * 1000);\n'
                '</script>';

and we can receive as

window.fbAsyncInit = function (con) {

or we can pass call back function to html method and we do operation which is done in magic.js

Reference: http://api.jquery.com/html/#html-function

then we can return html accordingly.

I hope this will help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM