Bonjour,

J'ai un petit soucis avec mon code. L'idée est simple, je veux afficher un message de succès ou d'erreur lorsque la personne souscrit à la Newsletter, le tout sans actualiser la page.

Alors le tout fonctionne si mon traitement est dans un fichier définit, par exemple 'cible.php', là tout est ok, je peux faire ma requête et renvoyer le message.

Mais dans le cas où il y a du routing, le "success:" ne fonctionne pas.

Je tiens à précisier que je suis débutant dans le dev, je me doute bien qu'il y a 1001 meilleures façon de faire, mais je fais avec ce que je peux, so keep calm :)

Le formulaire :

<div class="col-lg-12">
    <form id="newsletter" action="index.php?action=subscribe-newsletter" method="post">
        <input name="email" type="email" placeholder="Votre adresse email" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Votre            adresse email'" required>
       <button type="submit" style="cursor: pointer;" class="template-btn">M'abonner</button>
    </form>
   <div class="mt-5" id="newsletter-response"></div>
</div>

Mon Router :

case "subscribe-newsletter";
        if(isset($_POST['email']))
        {
            $newsletter = new Newsletter($db);
            $newsletter->subscribe($data['email']);
        }

Ma Class :

 public function subscribe($getemail)
    {
        if(isset($getemail))
        {
            $query = $this->db->prepare('INSERT INTO `newsletter` SET email = :email');
            $query->bindvalue(':email', $getemail);
            $query->execute();

            return json_encode(['reponse' => true]);
        }else {
            return json_encode(['reponse' => false]);
        }
    }

AJAX :

$(document).ready(function() {
    $('#newsletter').on('submit', function(e) {
        e.preventDefault(); 

        var $this = $(this);
        $.ajax({
            url: $this.attr('action'), 
            type: $this.attr('method'), 
            data: $this.serialize(),
            dataType: 'json',
            success: function(json) 
            {
                if(json.reponse === true)
                {
                    $('#newsletter-response').html('<div class="alert alert-success text-center" role="alert">Souscription validée !</div>');
                } else {
                    alert('Erreur : '+ json.reponse);
                }
            }
        });
    });
});

Merci à tous :)

18 réponses


Salut,

Alors il faut que tu echo ta réponse serveur, et non que tu la retournes.

case "subscribe-newsletter";
        if (isset($_POST['email'])) {
            $newsletter = new Newsletter($db);
            echo $newsletter->subscribe($data['email']);
        }

// .....
 public function subscribe($getemail)
    {
        $response = false;
        if (isset($getemail)) {
            $query = $this->db->prepare('INSERT INTO `newsletter` SET email = :email');
            $query->bindvalue(':email', $getemail);
            $response = $query->execute();
        }

        return json_encode(compact('response'));
    }

Par contre y'a un petit souci de logique dans ton case :
Tu vérifies si $_POST contient bien email, mais tu passes $data['email'] à ta méthode subscribe. D'où vient ce $data ?

Autre chose : la méthode subscribe ne devrait être responsable que d'une seule tâche, et non de retourner une réponse. Je te conseille d'organiser les choses comme suit :

/* Dans ta classe Newsletter */
private $subscribed = false;

public function subscribe(string $email)
{
    if (isset($email)) {
        $query = $this->db->prepare('INSERT INTO `newsletter` SET email = :email');
        $query->bindvalue(':email', $getemail);
        $this->subscribed = $query->execute();
    }
}

public function hasSubscribed()
{
    return $this->subscribed === true;
}

/* Dans ton case : */
case "subscribe-newsletter";
    $newsletter = new Newsletter($db);
    $newsletter->subscribe($_POST['email']);
    echo json_encode(['response' => $newsletter->hasSubscribed()]);

J'espère avoir pu t'aider ;)

Yorïnis
Auteur

Hello !

Merci pour ta réponse ! J'ai suivi ton conseil pour améliorer mon code, pour autant ça ne fonctionne pas mieux :(
En fait le soucis est que je ne parviens pas à rentrer dans l'AJAX (au niveau du :success). J'ai essayé de mettre un console.log juste après success: function(json)et la console ne me retourne rien.
Le traitement quant à lui se passe bien, l'email s'ajoute à la BD 'Newsletter'.

Pour répondre à ta question le "$data" est juste une variable de$_POST, je l'utilise simplement pour que ce soit moins pénible à écrire.

Bonsoir.

En fait le soucis est que je ne parviens pas à rentrer dans l'AJAX (au niveau du :success).

Fais attention à la version que tu utilises pour jQuery :

Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

Source : jQuery.ajax() | jQuery API Documentation » The jqXHR Object.

@Lartak bien vu (l'aveugle) !

@Jérôme Snk Je pense que tu es sur une version de jQuery qui utilises les promises.
Donc tu dois faire qqch dans ce genre là :

var loading = true // si jamais tu veux ajouter un loader qqpart ;)
$.ajax({
    url: $this.attr('action'), 
    type: $this.attr('method'), 
    data: $this.serialize(),
    dataType: 'json'
}).done(function (data) {
    console.log(data) // vérifies bien ce que te renvoie le back
    if (data.reponse === true) {
        $('#newsletter-response').html('<div class="alert alert-success text-center" role="alert">Souscription validée !</div>')
    } else {
        alert(`Erreur : ${data.reponse}`)
    }
})
.fail(function (data, status, err) {
    console.error('Une erreur est survenue', err)
})
.always(function () {
    loading = false
})
Yorïnis
Auteur

Merci pour vos réponses !

J'utilise la version 3.3.1 de JQuery.

J'ai utilisé ton morceau de code et voici ce que me retourne la console :

newsletter.js:43 Une erreur est survenue SyntaxError: Unexpected token < in JSON at position 10
    at parse (<anonymous>)
    at Ut (jquery-3.3.1.min.js:2)
    at k (jquery-3.3.1.min.js:2)
    at XMLHttpRequest.<anonymous> (jquery-3.3.1.min.js:2)
(anonymous) @ newsletter.js:43
u @ jquery-3.3.1.min.js:2
fireWith @ jquery-3.3.1.min.js:2
k @ jquery-3.3.1.min.js:2
(anonymous) @ jquery-3.3.1.min.js:2
load (async)
send @ jquery-3.3.1.min.js:2
ajax @ jquery-3.3.1.min.js:2
(anonymous) @ newsletter.js:29
dispatch @ jquery-3.3.1.min.js:2
y.handle @ jquery-3.3.1.min.js:2

Il y a du mieux par rapport à avant, au moins il se passe quelque chose maintenant. En revanche je vais être franc, je ne suis pas sûr de tout bien comprendre à ce qu'il se passe... :)

Yorïnis
Auteur

Petit up :)

Bonjour,
Vu le Unexpected token <, ta requette ajax doit renvoyer une erreur php ou une page html (que le moteur JSON du moteur js n'arrive evidement pas à gerer).

Si je ne me trompe pas, ton souci se situe au niveau de ta requette preparée avec PDO:

$query = $this->db->prepare('INSERT INTO `newsletter` SET email = :email');
$query->bindvalue(':email', $getemail);
$this->subscribed = $query->execute();

Or, quand tu fait un binvalue, il ne faut pas préciser les :. De manière alternative tu pourrais aussi faire:

$query = $this->db->prepare('INSERT INTO `newsletter` SET email = :email');
$this->subscribed = $query->execute(['email' => $email]);

// OU

$query = $this->db->prepare('INSERT INTO `newsletter` SET email = ?');
$this->subscribed = $query->execute($email);

De plus, t'est tu assuré que ta requtte ajax est en POST ? De ce que je vois on dirait du GET.

J'espère que ma réponse aidera,
Vasco.

Yorïnis
Auteur

Hello !

Merci pour ta réponse, mais cela ne semble pas résoudre le problème, même erreur :/

Et oui il s'agit bien de post (voir le formulaire plus haut)

Merci tout de même pour ta contribution !

Ah, J'ai toutefois un doute, vu que tu fait un e.prevenDefault(); le formulaire ne s'envoie pas (normal), et vu que tu ne precise pas type: "POST" dans les paramteres en appelant JQuery.ajax() il est possible que la requette soit en get, essaye de verifier en regardant la console du navigateur.

Sinon, tu peux aussi utiliser JQuery.post() pour s'en assurer, et si ce n'est pas ca, essaye de voir ce que ta requette ajax retourne via la console du navigateur (sur chrome: F12 puis onglet network).

En esperant aider, Vasco.

Yorïnis
Auteur
type: $this.attr('method'),

Cela doit bien récupérer le post non ?

My bad, effectivement, cela devrait, ce qui me fait dire qu'il faut regarder la réponse du serveur car d'apres l'erreur citée plus haut, il ne renvoie pas du json, essaye

$.ajax({
    url: $this.attr('action'), 
    type: $this.attr('method'), 
    //data: $this.serialize(),
    //dataType: 'json'
}).done(function (data) {
    console.log(data);
})

Pour voir ce que le serveur dit en console :)

(Encore désolé de mon erreur, je suis totalement passé a coté :|)

Vasco.

Yorïnis
Auteur

J'ai déjà un console.log après le .done, mais vu que je ne rentre pas dans ce cas de figure mais directement dans le .fail, je ne peux pas voir ce qui m'est retourné à cet endroit précis.

En revanche je viens de le mettre dans le .fail et voici ce qui m'est retourné (entre autre)

<!DOCTYPE html>
<html lang="fr">
<head>
 etc...

En gros tout le contenu de ma page ! (j'ai coupé car ça aurait été un peu long) D'où le "<" qui correspond donc à " <!DOCTYPE html>", mais alors pourquoi est-ce que ça me retourne tout le contenu de ma page, ça... Bizarre ^^'

Et pas de soucis pour ton "erreur" ahah déjà tu m'aides je vais pas encore faire le difficile :)

Essaye un

var_dump($_POST);

Au debut de ton index.php pour verifier si les champs sont biens envoyés, et pense a mettre die:

case "subscribe-newsletter";
        if (isset($_POST['email'])) {
            $newsletter = new Newsletter($db);
            header('Content-Type: application/json'); //On ne sait jamais, ca peux parfois servir.
            echo $newsletter->subscribe($data['email']);
            die;
        }

Vasco.

Yorïnis
Auteur
array(1) {↵  ["email"]=>↵  string(10) "qzg@zg.com"↵}↵
<!DOCTYPE html>
<html lang="fr">
<head>
etc...
↵

J'ai donc bien l'adresse email + le contenu de ma page... J'ai bien mis un die() pourtant.

J'aurais donc tendance a dire que le die arrive après l'affichage de la page, verifie si le json est pas tout en bas dès fois que.

Vasco.

Yorïnis
Auteur

Je l'ai mis dans un fichier .js qui est appelé en dernier (après tous mes autres scripts), mais pour autant je ne comprends pas pourquoi est-ce que cela retourne tout le contenu de ma page.

Ma page est découpée comme ça : (index.php)

quelques initialisations (session_start, ob_start,  set time pour la date, requires, autoloader, etc...)
quelques appels de class

include du header

include du router qui va déterminer quel contenu afficher <- (là où se trouve donc mon switch)

include du footer

Appel de tous mes scripts (bootstrap, etc...)
newsletter.js <- en dernier (script AJAX)

Si ça peut aider à comprendre... :/

Tu include le router apres le header, ducoup ca envoie du texte, sinon possibilité de pastebin le index.php pour l'etudier ?

Vasco.

Si tu inclues le header, qui contient donc du code HTML avant même d'atteindre le code qui va être utilisé pour l'Ajax, c'est tout à fait normal.