2

I have a page where I am loading another remote source using a element. Everything works great, except, now I want to be able to change the 'src' of the script depending on certain conditions when loading the page. The problem is, when I change the 'src', even though it changes in the DOM, it has no affect. The original 'src' is used and never updated.

Is it possible to dynamically retrieve the source of a remote site, or does this value have to be constant?

Edit: here is a sample of what I'm attempting:

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="http://voap.weather.com/weather/oap/90210?

template=GENXV&par=3000000007&unit=0&key=XXX"></script>
<script>
$(document).ready(function(){
  var newS = document.createElement('script');
  newS.type = "text/javascript"; 
  newS.src = "http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=XXX";
  $("head").append (newS);
});
</script>
</head>
<body>
</body>
</html>

You will notice that the 'script' which is at the top works fine. The script I attempt to add dynamically does not work at all. It shows up in the DOM-inspector, but not in the page.

Also, see the following:

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$(document).ready(function(){
  $.getScript("http://w3schools.com/jquery/demo_ajax_script.js");
  $.getScript("http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=XXX");
});
</script>
</head>
<body>
</body>
</html>

In this example, the w3school example works, but the weather does not.

Serodis
  • 2,092
  • 4
  • 25
  • 34
  • can you please give more details as of why you want to do that? Why not create another script element? – Mircea Sandu Dec 15 '13 at 16:47
  • you should just load specific script. Changing src of script tag doesn't unload previous loaded script and won't load new one. – A. Wolff Dec 15 '13 at 16:50
  • I am fine with just adding a new script, in fact , I'd prefer it. However, I have edited the question to show my problem with that. – Serodis Dec 15 '13 at 17:17
  • 1
    wow. view-source:http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=twciweatherwidget is the worst javascript I've seen in years. `document.write` is an obsolete JS call from the early days of JS, and should under no circumstance be used anymore. Nor 5 years ago for that matter. – Mike 'Pomax' Kamermans Dec 15 '13 at 17:32
  • 1
    You can not append that script to the page AFTER it was loaded. Reason, it was written very badly. Adidng that script to the page will cause the html of the page to be overwritten! – epascarello Dec 17 '13 at 19:08

5 Answers5

3

There's a couple things going on here:

  1. The remote server is returning the wrong content type
  2. The script returned by the remote server is using document.write

The first problem seems to mean you can't use $.getScript to get the remote script. But even if you could, you wouldn't want to because of the second concern because you can't run the script from weather.com inside your top-level document after the document is ready unless you want to destroy the whole page and replace it with the weather data.

You can, however, insert the script tag dynamically using your own document.write before the document is finished loading (don't wrap it with $(function(){})), $(document).ready(function(){}) or any other variant of document readiness event handler:

<script type="text/javascript">
document.write('<script src="http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=XXX">' + '<\/script>');
</script>

And you can build those string parameters using some dynamic logic if you need to.

Stephen Crosby
  • 1,157
  • 7
  • 19
  • This is exactly what I was looking for. I assume since I don't have JQuery running until ready, it is guaranteed that this script will run before my JQuery, is this correct? That is, part of the readying process is completing the other scripts, right? – Serodis Dec 18 '13 at 01:55
  • As long as your script tag that includes jQuery comes before this script tag, then you can use jQuery, but certain things might not work (like selecting elements that come later in the document). Waiting for the document to be ready ensures the DOM is ready and all the external scripts/css are loaded. – Stephen Crosby Dec 18 '13 at 04:58
2

The script is not being loaded because its it being returned with text/html headers. It would need to be served and returned with the Content-Type header of application/x-javascript.

If you dont have control over the headers that the script is served with then I would suggest you contact the provider and request that they change those.

Right now it gives a warning:

Resource interpreted as Script but transferred with MIME type text/html: "http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=XXX&_=1387307745041"

Have a look for yourself using this fiddle: http://jsfiddle.net/sVAP9/

Chase
  • 9,289
  • 5
  • 51
  • 77
1

#!

How about fiddling with the <iframe> element, and using it to do xrequests?

I approach ( hardcore one ):

Doing document.write() thing after window.onload wipes out all the content you've got loaded before running it. Async script load is using 'document.write', and browsers don't like it very much ( check out the A call to document.write() from an asynchronously-loaded external script was ignored. error in the console ). Something like this maybe ( fiddle ):

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>x</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
  $( function () {
    var widg$ = $("#widg");
    $("#btn")
    .on({
      click : function () {
        widg$.attr({
          src : "http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=XXX"
        });
      }
    });
  } );
</script>
</head>
<body>
<button id="btn" style="display:block;">load</button>
<iframe 
  id="widg"
  src=""
  frameborder="0" 
  style="margin:0; padding:0; border:none; width:300px; height:500px;" 
  seamless 
></iframe>
</body>
</html>

II approach ( a little bit of hack ):

You cannot send xdomain requests via ajax inside browser sandbox, without the help of backend curl that is. Make this php file ( hope your server supports it ):

_xdread.php


<?php
    
   header('Content-Type: '. $_POST['url_mime']);
   $url  = $_POST['fetch_url'];
   $ch   = curl_init( $url );
   curl_setopt( $ch, CURLOPT_HEADER, false );
   curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
   echo curl_exec( $ch );
   exit;

Place it in the same directory where your page is. Use jQuery to send http request to local php file. Set .dataType to text/plain, to avoid script auto-interpretation. It will curl the url and echo the response back. eval the response in the context of <iframe>'s .contentWindow. That way it will not ignore 'xdomain document.write()', because it is done localy:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>x</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
  $(function () {
  var widg$ = $("#widg");
  $("#btn")
    .on({
      click: function () {
        $.ajax({
            url       :'_xdread.php', 
            type      :'post', 
            dataType  :'text', 
            data      :{ 
                        fetch_url  :'http://voap.weather.com/weather/oap/90210?template=GENXV&par=3000000007&unit=0&key=XXX', 
                        url_mime   :'text/plain'
                      }, 
            success:function ( jstxt ) { 
              //console.log( jstxt );
              widg$[0]
              .contentWindow
              .eval( jstxt );
            }
      });
      }
    });
});
</script>
</head>
<body>
<button id="btn" style="display:block;">load</button>
<iframe 
  id="widg"
  src=""
  frameborder="0" 
  style="margin:0; padding:0; border:none; width:200px; height:300px;" 
  seamless 
></iframe>
</body>
</html>
Community
  • 1
  • 1
public override
  • 974
  • 8
  • 17
0

You're using jQuery, so use getScript. http://api.jquery.com/jQuery.getScript

Don't reinvent the wheel if you already included the car factory.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • Mike, sadly getScript does not work either. Though, both my method and getScript work with the URL: http://www.w3schools.com/jquery/demo_ajax_script.js Is there a reason it wouldn't work with the URL I am providing in my question? – Serodis Dec 15 '13 at 17:58
  • 1
    check your browser's error console. Both approaches should work so the file you're loading is probably not proper javascript. – Mike 'Pomax' Kamermans Dec 16 '13 at 16:17
  • The only error I am receiving is: Resource interpreted as Script but transferred with MIME type text/html – Serodis Dec 17 '13 at 01:50
  • Hey, look at this question http://stackoverflow.com/questions/16951681/jquery-getscript-issue It seems similar. Maybe there is a problem with loaded script and jQuery just swallow an exception. – Sebastian.Belczyk Dec 17 '13 at 19:12
-1

Most of above answers clearly tell that you are accessing content from cross domain and also the return type is text/html rather jsonp which could have solved this problem.

It seems like you using only that service and not designing it, that is why you could not change to response of script.

There is one solution that you include all possible scripts in html like this

<body>
  <div id="script1">
    <script src="{url of script 1}"></script>
  </div>

  <div id="script2">
    <script src="{url of script 2}"></script>
  </div>

  <div id="script3">
    <script src="{url of script 3}"></script>
  </div>
</body>

and according to your manipulation show only that div which is required and hide other because normally we can change the scr value of script but it will not load fresh content from that URL.

Therefore strategy will be load all script then show only one of them

Zainul Abdin
  • 835
  • 4
  • 10
  • -1. I strongly discourage that practice, you're loading something without intent to use it, and additionaly increase page load time by waiting for junk old-style widgets to load all their stuff. I've just did a count on how much time I lose in a year waiting for that stuff, and stupid 'click-here' flush plugins and commercials to load: half an hour a day minimum, times 365 days in a year, that's ~180 hours, so minimum 9 days per year I waste on some madmans design practice! – public override Dec 18 '13 at 21:11