Solved

AJAX can not access elements returned in array

Posted on 2016-08-09
21
58 Views
Last Modified: 2016-08-11
I have an AJAX function that works.  However, I can seem to access the elements inside the Array returned.

<?php
 echo json_encode(array('already'=>$already, 'success'=>$success));

<script>
 <script>
                var email = $('#email');
                $(function () {
                    $("#newsjoin").on('submit', function (e) {
                        e.preventDefault();
                    });
                    $("#submit").click(function () {
                        $.ajax({
                            data: $("#newsjoin").serialize(),
                            type: 'post',
                            url: 'includes/functions.php',
                            success: function (data) {
                                // d will hold the json representation of $errors
                                // there are errors
                                $("#successmessage").html(data);

                                $("#newsjoin")[0].reset();

                            }
                        });
                    });
                });
            </script>

Open in new window


This works:  $("#successmessage").html(data); It shows anything/everything in the Array

However this does not:  $("#successmessage").html(data.success);
OR
 $("#successmessage").html(data.already);

AND if I add : dataType: 'JSON',  to the AJAX, nothing returns.

Right now, it returns something like this (brackets and all):
{"already":"","success":"The email address  is receiving our newsletter."}
0
Comment
Question by:rgranlund
  • 6
  • 4
  • 3
  • +4
21 Comments
 
LVL 7

Expert Comment

by:James Bilous
ID: 41749795
Can you post the JSON returned? You may simply be using accessors incorrectly.
0
 
LVL 6

Expert Comment

by:Mukesh Yadav
ID: 41749959
Try this ;)
<?php

/* add this header to send JSON response */
header('Content-Type: application/json');
echo json_encode(array('already'=>$already, 'success'=>$success));

Open in new window

And add dataType: 'json' in ajax call.

Thanks,
Mukesh Yadav
0
 
LVL 6

Expert Comment

by:Mukesh Yadav
ID: 41749961
@James

Already posted JSON:

Right now, it returns something like this (brackets and all):
{"already":"","success":"The email address  is receiving our newsletter."}
0
 
LVL 30

Expert Comment

by:Marco Gasi
ID: 41750117
Try this:

                        $.ajax({
                            data: $("#newsjoin").serialize(),
                            type: 'post',
                            url: 'includes/functions.php',
                            dataType: 'json',
                            success: function (data) {
                                // d will hold the json representation of $errors
                                // there are errors
                                var response = JOSN.parse(data); 
                                $("#successmessage").html(response.success);

                                $("#newsjoin")[0].reset();

                            }
                        });

Open in new window

Notice lines 5 and 9.
0
 
LVL 6

Expert Comment

by:Mukesh Yadav
ID: 41750134
Hi @Marco I don't think we need to parser json response if we set dataType and sending correct headers to client what you say?
0
 
LVL 30

Expert Comment

by:Marco Gasi
ID: 41750143
rgranlund said he already tried to set dataType and nothing was displayed. So he can just try to parse the returned data, especially if in php it returns an array.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41750167
This does not appear to be an array.  PHP arrays can be "associative" or numerically indexed, and even a mixture of the two.  That's not so in JavaScript.  JavaScript arrays are positional with numeric keys, and they are written in square brackets.  This appears to be a JavaScript object (named keys, curly braces).  PHP json_encode() returns JavaScript objects when it encodes associative arrays.
{ "already": ""
, "success": "The email address  is receiving our newsletter." 
}

Open in new window

So you might be able to do something like this:
... success:function(data){
    alert(data.success);
    }

Open in new window

This article shows some ways of dealing with JSON in PHP and JavaScript:
https://www.experts-exchange.com/articles/22519/Understanding-JSON-in-PHP-and-JavaScript-Applications.html
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41750238
Press F12 to view the console.

Check that there are no errors

If there is a Post entry - expand it and copy any text that is in this tab and paste it here so we can see what is being returned from the server.

Marco was correct in his line 5 addition - adding the dataType: "json" is necessary for jQuery to automatically parse the returned JSON string. The JSON.parse() is not necessary in this case.

If this appears not to work and the sending script is definitely sending a response then it is possible the JSON it is returning is invalid.  If you can paste it here we can see what is going on.

Alternatively, you can copy and paste into a JSON formater (Example https://jsonformatter.curiousconcept.com) to determine if your JSON is valid.

Best course of action is to post the Response text from the POST.
1
 
LVL 33

Expert Comment

by:Slick812
ID: 41750636
greetings  rgranlund, , looked at your javascript code, and in my view, it is not what is needed to get the AJAX job (to display messages) done., , I have redone your entire <script> block to what I consider to be a way to do what you want to do. I have choosen NOT TO USE the -
     dataType: 'json',
because this can be a block to trouble shooting server PHP failures and warnings, which I always have in development. I have also add a SERVER response for server lacks or mis steps in this line -
     if(data.already) {
so if there is anything (string) in the already property, its a server "non success" message, but you can make this more useful for what you need to do. . .


Please do not change your php output at this time by adding any header for json

<script>
//var email = $('#email');
// you never use the email, why is it here?

$(function () {
  $("#newsjoin").on('submit', function (e) {
  e.preventDefault();
// USE the form submit for the AJAX  
  $.ajax({
    data: $("#newsjoin").serialize(),
    type: 'post',
    url: 'includes/functions.php',
// use the more recent .done NOT .success
    done(function( data ) {
// the data here is PLAIN TEXT , no conversion is done, 
//you just use the jQuery.parseJSON to make your Object

// IMPORTANT check the data FIRST character, to see if there ia a PHP Failure or warning
      if((data.charAt(0) == "{") || (data.charAt(0) == "[") ) {
// if the data has the { or [ then JSON parse
      data = jQuery.parseJSON(data); // convert to object
      if(data.already) {
// IMPORTANT to need to have ERROR control from the server 
// so place a string in the already property, if there is a server lacks or mis step
        alert("There was an ERROR on the server side");
        } else {
// load the data.success message into a div with .html
        $("#successmessage").html(data.success);

        $("#newsjoin").reset();
        }
      } else {
      alert("ERROR There was a PHP FAILURE or warning");
      console.log("ajax data: "+data);
      }
                            
    });// end of .done
  });// end of ajax

  });// end of on('submit'
});// end of documant ready
</script>

Open in new window


I hope this helps you to understand the complicated browser, server AJAX operations.
   Ask questions if you need other explanations
0
 
LVL 7

Author Comment

by:rgranlund
ID: 41750681
@slick, when I change everything to what you have I get: Uncaught SyntaxError: Unexpected token function
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41750706
because this can be a block to trouble shooting server PHP failures and warnings

Typically a good test strategy would require signing off the PHP script output before testing in AJAX. During the testing of the PHP warnings and errors can be caught.

There is nothing wrong with using dataType: "JSON"

Just putting this out there as it comes across in the previous post that the use of the JSON dataType is not an acceptable strategy.

In the context of this problem it does not change or solve the problem.

What you need to be doing here is ensuring that your PHP output is valid before going near your AJAX script. This is done either by testing the script independently or by analysing the output in the console as described above.
1
 
LVL 7

Author Comment

by:rgranlund
ID: 41750762
@julian:  it returns this:
{"already":"","success":"The email address  is receiving our newsletter."}

There is nothing in the Console under post.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41750806
There seems to be a lot of information here, and maybe even so much that it causes confusion.  Not to add to the confusion, but to show a step-by-step approach (one way) for going forward.

The first step in the development process is to get the server-side of the script right.  Here is the server script.  It produces a JSON-encoded response containing either a JavaScript array or a JavaScript object.
<?php // demo/temp_rgranlund_server.php
/**
 * https://www.experts-exchange.com/questions/28962501/AJAX-can-not-access-elements-returned-in-array.html#a41750636
 */
error_reporting(E_ALL);

// ASSIGN THE REQUEST VARIABLE TO $q
$q = !empty($_GET['q']) ? $_GET['q'] : NULL;

// IF THE REQUEST WANTS TO RECEIVE AN ARRAY -- NUMERIC INDEXES
if ($q == 'array')
{
    echo json_encode( [ 'This is the array' ], TRUE);
}

// IF THE REQUEST WANTS TO RECEIVE AN OBJECT -- NAMED INDEXES
if ($q == 'object')
{
    echo json_encode( [ 'text' => 'This is the object' ] );
}

Open in new window

We need to test this script three ways.  Try these links and see what you get.  Note the different notation returned in the response when you request an array  vs when you request an object.  This difference is part of the nature of JSON.

No output: https://iconoun.com/demo/temp_rgranlund_server.php

Array: https://iconoun.com/demo/temp_rgranlund_server.php?q=array
["This is the array"]

Open in new window


Object: https://iconoun.com/demo/temp_rgranlund_server.php?q=object
{"text":"This is the object"}

Open in new window


Now that we have the server-side (back-end) script working, we can turn to the client-side (front end) script.  In this script we will have two clickable elements.  One of them will request an array and will use the information at position zero to populate the dynamic field (line 29).  The other element will request an object and will use the information at the index named "text" (line 36).

Here is the client-side script.
https://iconoun.com/demo/temp_rgranlund_client.php
<!DOCTYPE html>
<!-- demo/temp_rgranlund_client.php -->
<!-- https://www.experts-exchange.com/questions/28962501/AJAX-can-not-access-elements-returned-in-array.html#a41750636 -->
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<style type="text/css">
#dynamic {
    font-size:150%;
}
.clickable {
    color:white;
    background-color:navy;
    width:17em;
}
/* STYLE SHEET HERE */
</style>

<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function(){

    $("#click_4_array").click(function(){
        $.get("temp_rgranlund_server.php", {q:'array'}, function(response){
            var resp = JSON.parse(response);
            $("#dynamic").val(resp[0]);
        });
    });

    $("#click_4_object").click(function(){
        $.get("temp_rgranlund_server.php", {q:'object'}, function(response){
            var resp = JSON.parse(response);
            $("#dynamic").val(resp.text);
        });
    });

});
</script>

<title>HTML5 Page With jQuery in UTF-8 Encoding</title>
</head>
<body>

<noscript>Your browsing experience will be much better with JavaScript enabled!</noscript>

<input id="dynamic"        value="Dynamic Field" />
<br>
<input id="click_4_array"  value="Click here for Array Communication"  class="clickable" />
<br>
<input id="click_4_object" value="Click here for Object Communication" class="clickable" />

</body>
</html>

Open in new window

The entire debugging process is made easier because we use a GET-method request to call the background script.  That means we can test from the browser address bar, changing the URL parameters and examining the browser output to see that our background script is working the way we expect.  If we later decided that we needed to use POST in the deployed application, it would be an easy change to get the q= argument from $_POST instead of $_GET.

This is how I build all jQuery (JavaScript, AngularJS, etc) applications.  First get the server-side right, then build the client-side.  What I never do is try to work on them both at one time.  Too much chance for confusion there!
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41750842
here is a slightly reworked version of your code
$(function() {
  var email = $('#email');
  $("#submit").click(function () {
    $.ajax({
      data: $("#newsjoin").serialize(),
      type: 'post',
      url: 't1475.json',
      dataType: 'json'
    }).then(function(response) {
        // d will hold the json representation of $errors
        // there are errors
        $('#success').html(response.success);
        $('#already').html(response.already);
        console.log(response);
    });
  });
});

Open in new window

I have setup the .json file to simply be the JSON you posted above.

If you look in the console after clicking the Submit button you will see thisScreen Shot
A working version of the above is available here
0
 
LVL 33

Expert Comment

by:Slick812
ID: 41751002
sorry, I copied code that was not correct from this question, this works for me in fire fox -
<script>
$(function () {
  $("#newsjoin").on('submit', function (e) {
  e.preventDefault();
// USE the form submit for the AJAX  
  $.ajax({
    data: $("#newsjoin").serialize(),
    type: 'post',
    url: 'server2.php',
// use the more recent .done NOT .success
  // end of ajax
  }).done(function( data ) {
// the data here is PLAIN TEXT , no conversion is done, 
//you just use the jQuery.parseJSON to make your Object

// IMPORTANT check the data FIRST character, to see if there ia a PHP Failure or warning
      if((data.charAt(0) == "{") || (data.charAt(0) == "[") ) {
// if the data has the { or [ then JSON parse
      data = jQuery.parseJSON(data); // convert to object
      if(data.already) {
// IMPORTANT to need to have ERROR control from the server 
// so place a string in the already property, if there is a server lacks or mis step
        alert("There was an ERROR on the server side");
        } else {
// load the data.success message into a div with .html
        $("#successmessage").html(data.success);

        $("#newsjoin").reset();
        }
      } else {
      alert("ERROR There was a PHP FAILURE or warning");
      console.log("ajax data: "+data);
      }
                            
    });// end of .done;

  });// end of on('submit'
});// end of documant ready
</script>

Open in new window


this is the php in my server2.php -

$already = '';
$success = "The email address  is receiving our newsletter.";
echo json_encode(array('already'=>$already, 'success'=>$success));
0
 
LVL 33

Expert Comment

by:Slick812
ID: 41751017
I for got to say that you will need to replace my server2.php with the address that you use like -
   includes/functions.php

@rgranlund , , not sure all of the comments here are helping you understand what you need to know about using the very useful browser server exchange of AJAX, and how to trouble shoot your AJAX code on browser and server to get the results you may need.

I did not mean to indicate that using the  dataType: "JSON"   was a bad or incorrect path to take in coding this, but perhaps my not explaining or assuming you know things about this operation was a poor choice for me. But I feel that it may give you options to consider.

Since you have more posts than I have time to read here, I will not add anymore to this.

Good Luck.
0
 
LVL 7

Author Comment

by:rgranlund
ID: 41751128
OK, here is the best thing I can offer:
<form method="post" id="newsjoin">
<input name="email" type="text" id="email" class="newsletter-input"/>
<div class="newsletter-button">
<input name="submit" type="image" id="submit" src="img/buttons/submit.png" alt="Join Mailing List" />
</div>
</form>

<script>
                $(function () {
                    $("#newsjoin").on('submit', function (e) {
                        e.preventDefault();
                    });
                    $("#submit").click(function () {
                        $.ajax({
                            url: 'includes/functions.php',
                            data: $("#newsjoin").serialize(),
                            method: 'POST',
                            success: function (response) {
                                $("#successmessage").html(response.success);
                                $("#successmessage").html(response.already);
                                console.log(response);
                                $("#newsjoin")[0].reset();
                            }
                        });
                    });
                });
            </script>


<?php // functions.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

$db_host = "localhost";
$db_name = "BLAH BLAH";
$db_user = "BLAH BLAH";
$db_word = "BLAH BLAH";

$dsn = "mysql:host=$db_host;dbname=$db_name";
try {
    $pdo = new PDO($dsn, $db_user, $db_word);
} catch (PDOException $exc) {
    var_dump($exc);
    trigger_error('NO PDO Connection', E_USER_ERROR);
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$e = $_POST['email'];
$already = "";
$success = "";

$user_id = "1";
file_put_contents("performance.log", __LINE__ . "::" . microtime(true), FILE_APPEND);

$sql = "SELECT subscriber_id FROM pommo_subscribers WHERE email = :email";

$pdos = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));

$pdos->bindParam(':email', $e, PDO::PARAM_STR);

//  START the TRY to see if the email is already in the DB
try {
    $pdos->execute();
    $num = $pdos->rowCount();
    print_r(error_get_last(), true);
    //  START if the email is available
    if ($num == 1) { // The email address is not available.
        $already = 'That email address <br /> ' . $e . ' has already been registered and is receiving our newsletter';
    } else {
        // Add the user to the database:
        $q = "INSERT INTO pommo_subscribers
                  (email, time_registered, user_id, season, status) VALUES 
                  (:email, NOW(), :user_id, 6, 1)";

        $pdos_b = $pdo->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));

        $pdos_b->bindParam(':email', $e, PDO::PARAM_STR);
        $pdos_b->bindParam(':user_id', $user_id, PDO::PARAM_STR);

        //  START Run the insert query
        try {
            $pdos_b->execute();
            print_r(error_get_last(), true);
            // HOW MANY ROWS WERE AFFECTED BY DELETE?
            $num_b = $pdos_b->rowCount();

//  START If an email address has been successfully added to the DB
            if ($num_b) {
                // SEND EMAIL NOTIFICATION
                $body = 'thanks for joining our newsletter';

                //require("../sendgrid-php/vendor/autoload.php");
                require("../sendgrid-php/sendgrid-php.php");

$from = new SendGrid\Email("me", "info@BLAH BLAH.com");
$subject = "BLAH BLAH";
$to = new SendGrid\Email(null, $e);
$content = new SendGrid\Content("text/plain", $body);
$mail = new SendGrid\Mail($from, $subject, $to, $content);

$apiKey = 'BLAH BLAHBLAH BLAHBLAH BLAH';
$sg = new \SendGrid($apiKey);

if($response = $sg->client->mail()->send()->post($mail))   {
                    echo "Mail Sent." . print_r(error_get_last(),true);
                    echo '<br />';
                } else {
                    echo "Mail NOT sent " . print_r(error_get_last(), true);
                }
echo $response->statusCode().'<br />';
echo $response->headers().'<br />';
echo $response->body().'<br />';

                $success = 'The email address ' . $e . '  is now receiving the newsletter.';
            } else { // If it did not run OK.
                $success = '<span class="red">This email address could not be registered due to a system error. We apologize for any inconvenience.</span>';
            }

//  END If an email has been successfully added to the DB
        }  //  END The Insert query
        catch (PDOException $exc) {
            var_dump($exc);
            trigger_error($exc->getMessage(), E_USER_ERROR);
        }
    }
    echo json_encode(array('already'=>$already, 'success'=>$success));
    
}  // END THIS Is the end of the first query to see if the email was already in the DB
catch (PDOException $exc) {
    var_dump($exc);
    trigger_error($exc->getMessage(), E_USER_ERROR);
}

?>     }

Open in new window

It shows the following in the console but nothing on the screen:
Mail Sent.<br />202<br />HTTP/1.1 100 Continue

HTTP/1.1 202 Accepted
Server: nginx
Date: Wed, 10 Aug 2016 21:19:57 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 0
Connection: keep-alive
X-Message-Id: fxcEFCY9TeuqrdhzHCdK3g
X-Frame-Options: DENY

<br /><br />{"already":"","success":"The email address BLAH BLAH has been entered into the DB."}

Open in new window

0
 
LVL 51

Accepted Solution

by:
Julian Hansen earned 500 total points
ID: 41751504
There is your problem - you are sending back other information as part of your return.

For a JSON return you can only send the JSON back. The AJAX call is trying to interpret the other output as JSON and it is failing because it is invalid.

Take out all your echo / output statements except for this line
echo json_encode(array('already'=>$already, 'success'=>$success));

Open in new window

0
 
LVL 51

Assisted Solution

by:Julian Hansen
Julian Hansen earned 500 total points
ID: 41751563
I have put together a sample that demonstrates the debugging process for AJAX applications.

The application is a simple form that allows you to turn a debug switch on / off. If on the sending script dumps debug information in the return - creating an invalid JSON response. This is picked up in the receiving script as an AJAX error and handled by displaying an error message.

If the debug switch is off then only the JSON is returned - the return includes a random status field and a static text field. This demonstrates the mechanism by which the sending script can inform the client that there was an error with the data sent by the client. It is handled in the success callback but a check on the status is done to determine what action should be taken.

The sample also demonstrates how you can debug the server without having to reload the client - the debug switch emulates changing code on the server - clicking the submit button on the client without refreshing the page results in a new server call that does not require a page refresh.

The sample also demonstrates how, by looking at the console, one can determine what the server script is doing and debug either a bad return or unexpected / incorrect return.

The HTML for the sample looks like this
  <form>
    <input type="checkbox" name="debug" value="1" id="debug"/> Debug<br/>
    <button type="submit" class="btn btn-default">Submit</button>
  </form>
  
  <div id="results-container">
    Result parameter 1: <input type="text" id="result1" /><br/>
    Result parameter 2: <input type="text" id="result2" /><br/>
  </div>
  <h2>Error</h2>
  <div id="error">
  </div>

Open in new window

The jQuery looks like this
$(function() {
  $('form').submit(function(e) {
    e.preventDefault();

    // CAPTURE THE DEBUG checkbox BEFORE CLEARING INPUTS

    var data = $(this).serialize();

    // CLEAR THE STATUS INPUTS

    $('#error').html('');
    $('input').val('');

    // MAKE THE AJAX CALL

    $.ajax({
      url: 't1476.php',
      data: data,
      type: 'POST',
      dataType: 'JSON'
    }).then(function(response) {

      // VALID JSON RESPONSE
      // CHECK APPLICATION STATUS

      if (response.success) {
        $('#result1').val(response.result1);
        $('#result2').val(response.result2);
      }
      else {

        // APP STATUS failed SHOW ERROR
        $('#error').html('There was an error in the return');
      }
    }, 
    // INVALID RESPONSE - JSON INVALID
    function(error) {
      $('#error').html('The returned data was invalid');
    });
    
    return false;
  });
});

Open in new window

The sending script looks like this
<?php
$debug = isset($_POST['debug']);
if ($debug) {
  echo "Dumping post ...\n";
  print_r($_POST);
  echo "More debugging here - note the AJAX return is not recognised";
}
$status = rand(1,2) == 1;
$result = array(
  'success' => $status,
  'result1' => rand(1,10),
  'result2' => 'Result2'
);

die(json_encode($result));

Open in new window

Working sample here
0
 
LVL 6

Expert Comment

by:Mukesh Yadav
ID: 41751573
Hi rgranlund,

This problem is taking too much time so can you please share PHP and JavaScript code you are using as it is.

So that experts can check what is broken. Right now we can only assume that this or that thing may be broken but not sure exactly what is broken.

Thanks,
Mukesh Yadav
1
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41751607
So that experts can check what is broken.
Nothing is broken - the problem is he is returning debug output as part of his response which is invalidating the JSON.

Once the debug output is removed the code should work as expected.
1

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

In this article you'll learn how to use Ajax calls within your CodeIgniter application. To explain this, I'll illustrate how to implement a simple contact form to allow visitors to send you an email through your web site.
Introduction Knockoutjs (Knockout) is a JavaScript framework (Model View ViewModel or MVVM framework).   The main ideology behind Knockout is to control from JavaScript how a page looks whilst creating an engaging user experience in the least …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to dynamically set the form action using jQuery.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now