0

I have been developing a blogging application with CodeIgniter 3.1.8 and Twig. I am currently working on making a newsletter subscription system.

I have created a table named newsletter with 3 columns: id, email and subscription_date.

The newsletter subscription form:

<div id="messags" class="is-hidden h-text-center">
  <div class="success is-hidden alert-box alert-box--success">You have successfully subscribed to our newsletter</div>
  <div class="fail is-hidden alert-box alert-box--error">Sorry, the newsletter subscription filed</div>
</div>
<form name="newsletter" method="post" action="{{base_url}}newsletter/subscribe" id="newsletterForm" class="group" novalidate>
  <input type="email" value="{{set_value('email') | striptags}}" name="email" class="email" data-rule-required="true" placeholder="Your Email Address"> 
  <input type="submit" name="subscribe" value="subscribe">
</form>

The Newsletter_model model:

class Newsletter_model extends CI_Model {
    public function subscriber_exists() {   
        $query = $this->db->get_where('newsletter', ['email' => $this->input->post('email')]);
        return $query->num_rows() > 0;
    }

    public function add_subscriber() {
        $data = [
            'email' => $this->input->post('email'),
            'subscription_date' => date('Y-m-d H:i:s')
        ];
        return $this->db->insert('newsletter', $data);
    }
}

As you can see above, I use the subscriber_exists() to make sure there are no duplicate emails.

The Newsletter controller is quite simple:

class Newsletter extends CI_Controller {
  public function __construct(){
        parent::__construct();
    }

  public function subscribe(){
    $data['is_new_subscriber'] = true;
    if (!$this->Newsletter_model->subscriber_exists()) {
      $this->Newsletter_model->add_subscriber();
    } else {
      $data['is_new_subscriber'] = false;
    }
  } 
}

The problem

I use jQuery AJAX to submit the form and the script is unaware of the is_new_subscriber variable:

(function($) {

    // Add subscriber via AJAX
    $("#newsletterForm").validate({
        rules: {
            email: {
                email: true
            }
        },

        submitHandler: function(form) {
            var form = $("#newsletterForm"),
                $fields = form.find('input[type="email"]'),
                url = form.attr('action'),
                data = form.serialize();
            $.ajax({
                type: "POST",
                url: url,
                data: data,
                success: function() {
                    $('#messags').slideDown(250).delay(2500).slideUp(250);
                    if (is_new_subscriber == true) {
                        $fields.val('');
                        $('#messags .success').show();
                    } else {
                        $('#messags .fail').show();
                    }
                }
            });
        }
    });

})(jQuery);

UPDATE

Adding echo json_encode($data) to the subscribe() and changing the submitHandler to the below ddi not splve the issue:

submitHandler: function(form) {
  var form = $("#newsletterForm"),
  $fields = form.find('input[type="email"]'),
  url = form.attr('action'),
  data = form.serialize();
  $.ajax({
    dataType: "json",
    type: "post",
    url: url,
    data: data,
    success: function() {
      $('#messags').slideDown(250).delay(2500).slideUp(250);
      $fields.val('');
      if (data.is_new_subscriber == true) {
        $('#messags .success').show();
      } else {
        $('#messags .fail').show();
      }
    }
  });
}

How can I fix this issue?

Razvan Zamfir
  • 4,209
  • 6
  • 38
  • 252

2 Answers2

2

Your code doesn't do anything with the $data variable, after you populate it. You could for example return it JSON-encoded.

  public function subscribe(){
    $data['is_new_subscriber'] = true;
    if (!$this->Newsletter_model->subscriber_exists()) {
      $this->Newsletter_model->add_subscriber();
    } else {
      $data['is_new_subscriber'] = false;
    }
    echo json_encode($data);
  }

Then, in the success callback of your JS code you need to reference it:

...
                success: function(data) {
                    $('#messags').slideDown(250).delay(2500).slideUp(250);
                    if (data.is_new_subscriber == true) {
                        $fields.val('');
                        $('#messags .success').show();
                    } else {
                        $('#messags .fail').show();
                    }
                }
...
Zoli Szabó
  • 4,366
  • 1
  • 13
  • 19
  • @RazvanZamfir this should work, if you use dataType='json' in your ajax settings, otherwise you need to JSON.parse(data) in your success. Anyway you can always console.dir(data) in your success to see what you get back – Vickel Mar 14 '21 at 19:41
  • @Vickel If I use `JSON.parse(data)'` I get `Uncaught SyntaxError: Unexpected token e in JSON at position 0` – Razvan Zamfir Mar 14 '21 at 19:48
  • @RazvanZamfir in your success? using Zoli's code? – Vickel Mar 14 '21 at 19:57
  • @Vickel Yes. In the `success` method. – Razvan Zamfir Mar 14 '21 at 19:59
  • @RazvanZamfir you must have something echo'd out somewhere in your php, e.g. an error message or a print_r()...which then is sent via ajax together with $data) and throws the JSON.parse error, as it is not a valid json string anymore. Try it with a simple array (to debug), you'll see it works... – Vickel Mar 14 '21 at 20:07
  • jQuery will make an "intelligent guess" on the response type (as per https://api.jquery.com/jquery.ajax/). This may however only work when the content type header is correctly set. In any case, like @Vickel wrote, explicitly specifying `dataType` (set to 'json') should do the trick.. If it's not, then there is additional output which is breaking the correct json formatted output. Please open devtools in your browser (usually F12), go to the network tab and inspect the response of the ajax call. – Zoli Szabó Mar 14 '21 at 21:30
  • I did specify the `dataType` as JSON, and the form stopped working altogether. The form _does_ work correctly (it did so from the beginning). The messages do not. – Razvan Zamfir Mar 14 '21 at 22:27
  • @RazvanZamfir You must help us with some debugging info, otherwise we cannot help you :) See my previous commit of what would be needed. – Zoli Szabó Mar 15 '21 at 05:41
  • Also please update the original question with the new version of your code. Both PHP and JS. – Zoli Szabó Mar 15 '21 at 05:43
  • There is no nwe version – Razvan Zamfir Mar 15 '21 at 08:35
  • I have updated the question. Please have a look. Thank you! :) – Razvan Zamfir Mar 15 '21 at 12:50
  • Since you're not willing to give us debug info from the browser devtools, let's try another thing. Please change `echo json_encode($data);` to `die(json_encode($data));`. This should help avoiding eventual additional output. Let's see if it gets you closer to the solution. – Zoli Szabó Mar 15 '21 at 13:28
  • @Vickel Here is **[what worked](https://stackoverflow.com/a/66639501/4512005)** for me. – Razvan Zamfir Mar 15 '21 at 14:08
0

Here is what worked for me:

In the controller, I added echo json_encode($data):

class Newsletter extends CI_Controller {
  
  public function __construct() {
        parent::__construct();
    }

  public function subscribe(){
    $data['is_new_subscriber'] = true;
    if (!$this->Newsletter_model->subscriber_exists()) {
      $this->Newsletter_model->add_subscriber();
    } else {
      $data['is_new_subscriber'] = false;
    }
    echo json_encode($data);
  }
}

The script:

(function($) {

  // Add subscriber via AJAX
  $("#newsletterForm").validate({
    rules: {
      email: {
        email: true
      }
    },

    submitHandler: function(form) {
      var form = $("#newsletterForm"),
      $fields = form.find('input[type="email"]'),
      url = form.attr('action'),
      data = form.serialize();
      $.ajax({
        dataType: "json",
        type: "post",
        url: url,
        data: data,
        success: function(response) {
          $('#messags').slideDown(250).delay(2500).slideUp(250);
          $fields.val('');
          if (response.is_new_subscriber === true) {
            $('#messags .success').show();
             $('#messags .notnew').hide();
          } else {
            $('#messags .notnew').show();
          }
        },
        error: function() {
          $('#messags .fail').show();
        }
      });
    }
  });

})(jQuery);

The HTML:

<div id="messags" class="is-hidden h-text-center">
    <div class="success is-hidden alert-box alert-box--success">You have successfully subscribed to our newsletter</div>
    <div class="notnew is-hidden alert-box alert-box--info">You are already subscribed</div>
    <div class="fail is-hidden alert-box alert-box--error">Sorry, the newsletter subscription filed</div>
</div>
Razvan Zamfir
  • 4,209
  • 6
  • 38
  • 252