Vote up to Idea Filling DOM elements with Javascript based on custom tags Vote down to Idea Filling DOM elements with Javascript based on custom tags

Rank87

Idea#16

This idea is active.
Application Showcase »

Filling DOM elements with Javascript based on custom tags

http://pad.human.cornell.edu/Unlisted/api_json.html

Please take a look at the source.

What I tried to do is creating a web page using empty DOM elements and fill them later with Javascript and API calls. The Javascript loops through all elements with class='acs5' and I use the HTML5 data-* custom tags to define what value I would like to see in that element. The browser might throw a warning because I violate same-origin security check. I don't have a lot of experience with callback function and was not able to implement something similar with JSONP.

Comment

Submitted by Jan Vink 1 year ago

Vote Activity

  1. Approved
    1 year ago

Events

  1. The idea was posted
    1 year ago

Comments (5)

  1. Jan,

    Hi. Are you saying that the javascript fails due to a same-origin violation? What browser and version are you using?

    Your code does work for me in firefox 12. The API is sending a "Access-Control-Allow-Origin: *" response header so any browser that supports CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) should run just fine; older browsers will not, however.

    I can help you with JSONP if you need.

    1 year ago
    1. Jan Vink Idea Submitter

      Internet Explorer 8 throws up a warning about same-origin violation. It works fine after the viewer agrees to continue. I haven't tested this page with many other browsers.

      I would like to get a better understanding of JSONP and callback functions and some examples would be very useful for me. All simple examples I could find online were examples where the callback function contained a not so useful alert-statement.

      1 year ago
  2. So, the idea with JSONP is that you (the caller) may specify a function name with your request, for example:

    http://thedataweb.rm.census.gov/data/2010/acs5?key=...&get=NAME&for=county:109&in=state:36&jsonp=MyFuncName

    The HTTP response for the above is not JSON but rather JavaScript which calls "MyFuncName" with the data as its first argument. As you're writing the function, it may do anything you like including modifying the DOM (as you're currently doing).

    The Wikipedia article for JSONP provides a link to this code on pastebin: http://pastebin.com/ADxHdCnB which is a small, standalone utility library for JSONP. It includes an example at the bottom. Modifying your code to use that library would look something like this:

    var scr1;

    var acs_elem_i;

    function GotSomeData(resp_arr) {

    if (resp_arr === null) {

    return;

    }

    var dataelem = resp_arr[1][0];

    acs_elem_i.innerHTML = dataelem;

    Jsonp.removeTag(scr1);

    }

    function fill() {

    var acs_elem = getElementsByClassName('acs5');

    for (var i = 0; i < acs_elem.length; i++) {

    acs_elem_i = acs_elem[i];

    var elemid = acs_elem[i].getAttribute("data-elem");

    var geo = acs_elem[i].getAttribute("data-geo")?acs_elem[i].getAttribute("data-geo"):defaultGeo;

    var url = "http://thedataweb.rm.census.gov/data/2010/acs5?key="+mykey+"&get="+elemid+"&"+geo+"&jsonp=GotSomeData";

    scr1 = Jsonp.invoke(url);

    }

    }

    1 year ago
    1. Jan Vink Idea Submitter

      Thanks for your suggestion. Because of the asynchronous nature of the jsonp requests, having just one global variable available to refer to the element that need to filled was not sufficient. I found a way around it by defining a callback function for each request.

      http://pad.human.cornell.edu/Unlisted/api_jsonp.html

      The code looks like:

      var acs_elem = [];

      var func = [];

      function GotSomeData(resp_arr, i) {

      if (resp_arr === null) {

      return;

      }

      var dataelem = resp_arr[1][0];

      acs_elem[i].innerHTML = dataelem;

      }

      function fill() {

      var script = [];

      var elemid, geo;

      var scr_elem = document.createElement('script');

      scr_elem.async = true;

      scr_elem.type ="text/javascript";

      acs_elem = document.querySelectorAll('.acs5');

      for (var i = 0; i < acs_elem.length; i++) {

      script[i] = scr_elem.cloneNode(false);

      func[i] = new Function("resp_arr", "GotSomeData(resp_arr, "+i+")");

      elemid = acs_elem[i].getAttribute("data-elem");

      geo = acs_elem[i].getAttribute("data-geo")?acs_elem[i].getAttribute("data-geo"):defaultGeo;

      script[i].src = "http://thedataweb.rm.census.gov/data/2010/acs5?key="+mykey+"&get="+elemid+"&"+geo+"&jsonp=func["+i+"]";

      acs_elem[i].appendChild(script[i]);

      }

      }

      The code defines an array of functions func[] which has a tie to the array of elements to be filled.

      I attach the request script as a child to the DOM element and replace that later through innerHTML with the value returned value. I don't know if this is against good coding practices.

      1 year ago
  3. Jan,

    WRT coding practices there is nothing wrong with it. The only thing I'd caution is that, as written, each of the dynamically allocated functions will have a lifespan of the page so you may eventually exhaust availabe memory if you continually append items to the array.

    An alternative would be to use a JavaScript Object as an associative array, for example:

    var func = {};

    And use a closure or "new Function()" as your doing inside fill(). Then, inside the callback remove the function from the funcs Object. That way, the garbage collector can make that memory available for reuse.

    Also, just in case you have not seen it, jquery (and similar libraries/frameworks) provides JSONP support in its AJAX abstraction and takes care of these details for you.

    1 year ago