JimmyBandit
JimmyBandit

Reputation: 109

JavaScript $.getJSON Issue

I have a problem with a piece of JavaScript code - a snippet is shown below. Basically the code is issuing a getJSON request to a rails controller and then should process the returned data, building an HTML table and then embedding it in a Div. It doesn't work. I have tried stepping through it with alerts, etc - all to no avail. The data is retrieved from the rails controller and I can verify that. I have placed the piece of code that issues and processes the getJSON request in the niddle of the Rails Welcome page - this is not all mine. The code is below:

     <!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails: Welcome aboard</title>
    <style type="text/css" media="screen">
      body {
        margin: 0;
        margin-bottom: 25px;
        padding: 0;
        background-color: #f0f0f0;
        font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
        font-size: 13px;
        color: #333;
      }

      h1 {
        font-size: 28px;
        color: #000;
      }

      a  {color: #03c}
      a:hover {
        background-color: #03c;
        color: white;
        text-decoration: none;
      }


      #page {
        background-color: #f0f0f0;
        width: 750px;
        margin: 0;
        margin-left: auto;
        margin-right: auto;
      }

      #content {
        float: left;
        background-color: white;
        border: 3px solid #aaa;
        border-top: none;
        padding: 25px;
        width: 500px;
      }

      #sidebar {
        float: right;
        width: 175px;
      }

      #footer {
        clear: both;
      }


      #header, #about, #getting-started {
        padding-left: 75px;
        padding-right: 30px;
      }


      #header {
        background-image: url("images/rails.png");
        background-repeat: no-repeat;
        background-position: top left;
        height: 64px;
      }
      #header h1, #header h2 {margin: 0}
      #header h2 {
        color: #888;
        font-weight: normal;
        font-size: 16px;
      }


      #about h3 {
        margin: 0;
        margin-bottom: 10px;
        font-size: 14px;
      }

      #about-content {
        background-color: #ffd;
        border: 1px solid #fc0;
        margin-left: -55px;
        margin-right: -10px;
      }
      #about-content table {
        margin-top: 10px;
        margin-bottom: 10px;
        font-size: 11px;
        border-collapse: collapse;
      }
      #about-content td {
        padding: 10px;
        padding-top: 3px;
        padding-bottom: 3px;
      }
      #about-content td.name  {color: #555}
      #about-content td.value {color: #000}

      #about-content ul {
        padding: 0;
        list-style-type: none;
      }

      #about-content.failure {
        background-color: #fcc;
        border: 1px solid #f00;
      }
      #about-content.failure p {
        margin: 0;
        padding: 10px;
      }


      #getting-started {
        border-top: 1px solid #ccc;
        margin-top: 25px;
        padding-top: 15px;
      }
      #getting-started h1 {
        margin: 0;
        font-size: 20px;
      }
      #getting-started h2 {
        margin: 0;
        font-size: 14px;
        font-weight: normal;
        color: #333;
        margin-bottom: 25px;
      }
      #getting-started ol {
        margin-left: 0;
        padding-left: 0;
      }
      #getting-started li {
        font-size: 18px;
        color: #888;
        margin-bottom: 25px;
      }
      #getting-started li h2 {
        margin: 0;
        font-weight: normal;
        font-size: 18px;
        color: #333;
      }
      #getting-started li p {
        color: #555;
        font-size: 13px;
      }


      #sidebar ul {
        margin-left: 0;
        padding-left: 0;
      }
      #sidebar ul h3 {
        margin-top: 25px;
        font-size: 16px;
        padding-bottom: 10px;
        border-bottom: 1px solid #ccc;
      }
      #sidebar li {
        list-style-type: none;
      }
      #sidebar ul.links li {
        margin-bottom: 5px;
      }

    </style>

    <script src="/javascripts/jquery.js" type="text/javascript"></script>

    <script type="text/javascript">
      function about() {
        info = document.getElementById('about-content');
        if (window.XMLHttpRequest)
          { xhr = new XMLHttpRequest(); }
        else
          { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
        xhr.open("GET","rails/info/properties",false);
        xhr.send("");
        info.innerHTML = xhr.responseText;
        info.style.display = 'block'
      }
    </script>


        <script type="text/javascript">

           alert('Start of JSON Routine');

           $(document).ready( function() {

             alert('Attach a JQuery Live event to the button');

             $('#getdata-button').live('click', function() {

               alert("Get JSON data");

               $.getJSON('http://0.0.0.0:3000/getjson/1', function(data) {

                  alert('Processing returned JSON data');

                  var tmp = '<table border=1>';

                  for (i=0;i<data.length;i++)
                  {
                    tmp = tmp +'<tr>';
                      tmp = tmp + '<td>' + data[i].book.price         + '</td>';
                      tmp = tmp + '<td>' + data[i].book.title         + '</td>';
                      tmp = tmp + '<td>' + data[i].book.author        + '</td>';
                      tmp = tmp + '<td>' + data[i].book.ISBN          + '</td>';
                      tmp = tmp + '<td>' + data[i].book.yearPublished + '</td>';
                      tmp = tmp + '<td>' + data[i].book.volume        + '</td>';
                      tmp = tmp + '<td>' + data[i].book.publisher     + '</td>';
                      tmp = tmp + '<td>' + data[i].book.edition       + '</td>';
                      tmp = tmp + '<td><a href=# onclick=\"alert('+ i +')\">View</a></td>'; 
                    tmp = tmp + '</tr>';
                  }

                  tmp = tmp + '</table>';

                  alert('About to insert Table into DOM in content Div');

                  $('#showdata').html(tmp);

               }); //getJSON        end
             });   //getdata-button end
           });     //document.ready end

           alert('End of JSON routine'); 

        </script>

  </head>



  <body>
    <div id="page">
      <div id="sidebar">
        <ul id="sidebar-items">
          <li>
            <h3>Browse the documentation</h3>
            <ul class="links">
              <li><a href="http://api.rubyonrails.org/">Rails API</a></li>
              <li><a href="http://stdlib.rubyonrails.org/">Ruby standard library</a></li>
              <li><a href="http://corelib.rubyonrails.org/">Ruby core</a></li>
              <li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li>
            </ul>
          </li>
        </ul>
      </div>





        <a href="#" id="getdata-button">Get JSON Data</a>

        <script>alert("Before the JMC div");</script>

        <div id="showdata">JMC</div>


        <script>alert("Past the JMC div");</script>


       <div id="content">


          <h1>Welcome aboard</h1>
          <h2>You&rsquo;re riding Ruby on Rails!</h2>
        </div>

        <div id="about">
          <h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
          <div id="about-content" style="display: none"></div>
        </div>

        <div id="getting-started">
          <h1>Getting started</h1>
          <h2>Here&rsquo;s how to get rolling:</h2>

          <ol>
            <li>
              <h2>Use <code>rails generate</code> to create your models and controllers</h2>
              <p>To see all available options, run it without parameters.</p>
            </li>

            <li>
              <h2>Set up a default route and remove or rename this file</h2>
              <p>Routes are set up in config/routes.rb.</p>
            </li>

            <li>
              <h2>Create your database</h2>
              <p>Run <code>rake db:migrate</code> to create your database. If you're not using SQLite (the default), edit <code>config/database.yml</code> with your username and password.</p>
            </li>
          </ol>
        </div>
      </div>

      <div id="footer">&nbsp;</div>
    </div>
  </body>
</html>

Here is the JSON data I get back when I just invoked the URL/ Controller action directly from the browser:

[
   {
      "book":{
         "price":"25.52",
         "created_at":"2011-10-27T22:35:04Z",
         "ISBN":"",
         "author":"Obie Fernandez",
         "title":"Rails 3 Way, The (2nd Edition)",
         "updated_at":"2011-10-27T22:35:04Z",
         "yearPublished":"2010",
         "id":1,
         "publisher":"Addison-Wesley",
         "volume":"2",
         "edition":"second edition"
      }
   },
   {
      "book":{
         "price":"23.94",
         "created_at":"2011-10-27T22:39:37Z",
         "ISBN":"",
         "author":"Michael Hartl",
         "title":"Ruby on Rails 3 Tutorial: Learn Rails by Example",
         "updated_at":"2011-10-27T22:39:37Z",
         "yearPublished":"2010",
         "id":2,
         "publisher":"Addison-Wesley",
         "volume":"",
         "edition":"first edition"
      }
   },
   {
      "book":{
         "price":"24.97",
         "created_at":"2011-10-27T22:42:42Z",
         "ISBN":"",
         "author":"Cloves Carneiro Jr. and Rida Al Barazi",
         "title":"Beginning Rails 3 ",
         "updated_at":"2011-10-27T22:42:42Z",
         "yearPublished":"2009",
         "id":3,
         "publisher":"Apress",
         "volume":"",
         "edition":"first edition"
      }
   }
]

Anything else that might be useful. The Rails logs show the request being handled correctly.

When I step through the script, the alerts come up in a starnge sequence:

THe first alert I get is "Here at start of JSON Routine", followed by "Finished document ready routine" and then "Attach a JQuery Live event to the button". I then click the button for getdata and then a # appears at the end of the URL and then nothing.

MOved the script into the head - same outcome.

SWitched #content to #showdata - same outcome.

Final Edit:

The problem is solved thanks to the input of many people.

There were a number of issues, but the final issue was a same origin error in that the URL on the getJSON request was different to the URL making the request. The request had 0.0.0.0:3000/getjson/1 whereas the requesting URL was localhost:3000/getjson/1. Very hard to spot and the lack of return / status info with getJSON made it more difficult. Anyway thanks is due to all contributors, who all made valid contributions. I hope I have the expertise to contribute myself someday.

Upvotes: 1

Views: 1678

Answers (4)

iwasrobbed
iwasrobbed

Reputation: 46703

Alright Joe, you need to start with the simplest case possible... clean up all of your HTML and get rid of everything that you do not need. I tested this and verified that it works on my local Rails server.

I mocked up the Rails controller action to return your JSON data using:

  def getjson
    json_data = '[{ "book": { "price": 18.75, "title": "Moby Dick", "author": "Herman Melville", "ISBN": "0393972836", "yearPublished": 2001, "volume": 1, "publisher": "W. W. Norton & Company", "edition": "2nd Edition" }}]'
    render :json => json_data, :status => :ok
  end

You shouldn't need to change your Rails controller code since you said it was working. I just wanted to show you how I mocked it up for your future reference.

Now, replace the contents of your HTML file with this:

<!DOCTYPE html>
  <html>
    <head>
      <title>JSON Test example</title>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>

      <script type="text/javascript">
        $(document).ready(function() {

            $('#getdata-button').live('click', function() {
                // clear out the old data:
                $('#content').html('');

                alert("Getting JSON data");

                $.ajax({
                    dataType: 'json',
                    type: 'GET',
                    url: '/getjson/1',
                    success: function(json) {
                        console.log(json);
                        alert('Processing returned JSON data');

                        var tmp = '<table border=1>';

                        for (i = 0; i < json.length; i++) {
                            tmp = tmp + '<tr>';
                            tmp = tmp + '<td>' + json[i].book.price + '</td>';
                            tmp = tmp + '<td>' + json[i].book.title + '</td>';
                            tmp = tmp + '<td>' + json[i].book.author + '</td>';
                            tmp = tmp + '<td>' + json[i].book.ISBN + '</td>';
                            tmp = tmp + '<td>' + json[i].book.yearPublished + '</td>';
                            tmp = tmp + '<td>' + json[i].book.volume + '</td>';
                            tmp = tmp + '<td>' + json[i].book.publisher + '</td>';
                            tmp = tmp + '<td>' + json[i].book.edition + '</td>';
                            tmp = tmp + '<td><a href=# onclick=\"alert(' + i + ')\">View</a></td>';
                            tmp = tmp + '</tr>';
                        }

                        tmp = tmp + '</table>';

                        alert('About to insert the following data into DOM: ' + tmp);

                        // Show the div we are looking for in the browser's console
                        console.log($('#content'));

                        $('#content').html(tmp);
                    },
                    error: function(response) {
                        alert('There was an error: ' + response.status);
                    }
                }); // $.ajax end
            }); //getdata-button end

        }); //document.ready end
    </script>
  </head>

  <body> 
    <a href="#" id="getdata-button">Get JSON Data</a>
    <br/><br/>
    <div id="content">The data will be placed here.</div>
  </body>
</html>

Notice that I am using the $.ajax method which allows me to specify an error handler callback. I would recommend using this way of doing things until you become more familiar with jQuery and feel confident that you can start using the other AJAX helpers.

I hope this helps!

Upvotes: 0

Ricardo Souza
Ricardo Souza

Reputation: 16456

This is most related to same origin policy (cross domain blocking) and can be resolved by using a JSONP call. Add a ?callback=? to the end of the URL:

    $(document).ready( function() { 
         alert('Attach a JQuery Live event to the button'); 
         $('#getdata-button').live('click', function() { 
           $.getJSONP('http://0.0.0.0:3000/getjson/1?callback=?, function(data) { 

             // ... Omiting for brevity

              $('#content').html(tmp); 

           }); 
         }); 
       }); 

Upvotes: 2

graphicdivine
graphicdivine

Reputation: 11211

$('#content') doesn't seem to exist.

EDIT

After another look, it seems to problem hinges on the button click event not firing. Since this is added via live, and as another user has posted, works on jsfiddle: I wonder what version of jQuery you are using? Looks like it could be very old indeed. Try upgrading to a newer version.

Upvotes: 0

Brett Pontarelli
Brett Pontarelli

Reputation: 1728

Your page is being refreshed and the data is likely getting dropped. Try:

$('#getdata-button').live('click', function(evt) {
  evt.preventDefault();     
}

Upvotes: 0

Related Questions