Mots-clé : jquery

Css inutilisé : comment supprimer toute information inutile – how to

Si jamais vous avez un site qui utilise plein d’outils et que vous pensez que beaucoup de votre CSS n’est pas utilisé, alors allez jeter un coup d’oeil ici : http://unused-css.com/.

C’est un site qui aide pour dire quels sont tous les styles CSS déclarés, et lesquels ne sont pas utilisés.
Extrêmement pratique.

Notez tout de même que si jamais vous construisez dynamiquement des objets DOM (notamment en jQuery) qui utilisent un CSS particulier, et que ce dernier n’est pas utilisé ailleurs, alors je pense que ça trompe le vérificateur et qu’il pense que ce CSS n’est jamais utilisé.

Php, AJAX et problèmes de cache sur iOS : comment les résoudre

J’ai expliqué qu’il fallait mettre, avant de faire le tout dernier ordre de sortie echo json_encode($resultat_final); les headers JSON.

header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');

On m’a demandé à quoi servaient les entête de cache. J’ai expliqué que ça servait à s’assurer que les interrogations AJAX se feraient toujours (notez le futur), c’est à dire à demander au navigateur de ne rien garder en cache.

Comme toujours, ma mémoire me fait défaut mais mon expérience reste, et je savais qu’il faut éviter tout risque de problème cache.
J’ai retrouvé une explication concrète du problème : certaines versions du navigateur Safari sur iOS6 ne réinterrogent pas les appels AJAX.

Il suffit donc de faire deux choses :

  • Soit modifier la configuration Apache (c’est pour ça que j’ai consacré quelques heures sur les hôtes virtuels et leur configuration) pour qu’il y ait ces entêtes par défaut :
    Header set Cache-Control "no-cache"
  • Soit faire ma solution directement en Php (mais ça implique de le faire dans tous les retours AJAX – ce qui ne gêne en rien pour les petits projets)
  • Soit préciser en JavaScript de modifier le header :
    $.ajaxSetup({
        type: 'POST',
        headers: { "cache-control": "no-cache" }
    });

Toutes les solutions sont prises via le site de questions/réponses de reférence : en Anglais ici.

jQuery Mobile : rafraîchir une liste créée dynamiquement

Si vous créez dynamiquement une liste en jQuery Mobile, et que la liste n’apparaît pas correctement, il faut demander à jQuery Mobile de la rafraîchir. La solution ? « Refresh ». Voici le code, avec en gras la ligne qu’il vous faut ajouter :

$(document).ready(function() {
    $.ajax("../php/monajax.php")
    .done(function(data) {
        /* Vider la liste avant de la remplir : */
        $("#list").empty();
        /* Remplir la liste : */
        for (var i in data) {
            $('#list').append(
                $('<li />').append(
                    $('<a />')
                        .attr('title', tab[i].description)
                        .html(tab[i].contenu)
                )
            );
        }
        $("#list").listview("refresh");
    });
});

jQuery et submit : comment éviter que le POST ne soit envoyé « classiquement »

Si jamais vous essayez de faire ce que je préconisais (et qui fonctionne dans la plupart des cas) à savoir :

$('#mondiv').submit( function (event) {
    ...
    /* blabla plein de code */
    ...
    return false;
});

Alors ça fonctionne : lorsqu’on détourne la soumission du formulaire, le « return false; » est censé simuler une erreur et stopper la propagation de l’événement.
Seulement il arrive des cas où ce n’est pas suffisant, et où le formulaire est tout de même soumis « à l’ancienne », c’est à dire qu’il efface la page courante et attend le retour du « post » classique. Pour éviter ce genre de désagrément, il faut utiliser event.preventDefault(); :

$('#mondiv').submit( function (event) {
    event.preventDefault();
    ...
    /* blabla plein de code */
    ...
    return false;
});

jQuery Mobile : comment forcer le rechargement d’une page ?

Si vous faites des boutons de navigation, votre code jQuery Mobile va ressembler à ceci :

<a href="/">Home</a>

Le seul hic, c’est qu’en cliquant dessus, le navigateur ne va pas recharger réellement la page, il va se baser sur son cache, en supposant que la page n’a pas changé. Ce qui peut poser problème. Par exemple, sur mon site mobile, lorsqu’un commande est validée, je vide le panier côté serveur et je fais un lien vers la page racine, le « home ». Avec le code précédent, le navigateur ne recharge pas réellement la page, et garde le panier toujours « rempli » car il garde les informations et variables JavaScript en mémoire. Dans ce cas, il faut forcer au rechargement de la page. Comment faire ?

Grâce à l’astuce de ce site, voici la solution : il suffit d’ajouter cette balise : rel="external".

Et la page sera rechargée.

<a href="/" rel="external">Home</a>

En espérant que cela aide du monde !

JavaScript, jQuery et closure: petit exercice à faire

Ci suit un petit exercice JavaScript: copiez collez les deux morceaux de code qui suivent dans une page jsfiddle.net

Si vous examinez le code JavaScript, il est très simple : l’objectif de l’exercice semble simple : il faut juste faire « flasher » les libellés les uns après les autres (c’est là que la difficulté se trouve).

Seul problème, avec le code qui suit et semble correct : ça ne fonctionne pas. L’exercice est… de trouver la solution en JavaScript.

Ne regardez pas la fin, car il y a la solution !.

Code HTML :

<table id="s-inscrire-infos">
<tbody>
<tr>
<td id="label-nomprenom"> <span><label for="label-nomprenom"><b>Nom et prénom&nbsp;:&nbsp;</b></label></span> </td>
<td> <span> <input type="text" name="nomprenom" id="nomprenom" class="form-nom-prenom" size="50" maxlength="50" /> </span> </td>
</tr>
<tr class="erreur" id="erreur-nomprenom" style="display:none">
<td colspan="2">* Il faut renseigner votre nom et prénom</td>
</tr>
<tr>
<td id="label-adresse1"> <span> <label for="label-adresse"> <b>Adresse ligne 1 :&nbsp;</b> <br /> <font size="-2">(ou nom de la société)&nbsp;</font> </label> </span> </td>
<td> <span><input type="text" name="adresse1" id="adresse1" class="form-adresse" size="50" maxlength="60" /></span> <br /> <span class="tiny">Rue, voie, boîte postale, nom de société</span> </td>
</tr>
<tr class="erreur" id="erreur-adresse1" style="display:none">
<td colspan="2">* Il faut au moins renseigner une ligne</td>
</tr>
<tr>
<td id="label-adresse2"> <span><label for="label-adresse"><b>Adresse ligne 2 :&nbsp;</b> <br /> <font size="-2">(facultatif)&nbsp;</font> </label></span> </td>
<td> <span><input type="text" name="adresse2" id="adresse2" class="form-adresse" size="50" maxlength="60" /></span> <br /> <span class="tiny">Appartement, bâtiment, étage, digicode, cedex, etc.</span> </td>
</tr>
<tr>
<td id="label-cp"> <span><label for="label-cp"><b>Code postal&nbsp;:&nbsp;</b></label></span> </td>
<td> <span> <input type="text" name="cp" id="cp" class="form-cp" size="20" maxlength="20" /> </span> </td>
</tr>
<tr class="erreur" id="erreur-cp" style="display:none">
<td colspan="2">* Il faut renseigner votre code postal</td>
</tr>
<tr>
<td id="label-ville"> <span><label for="label-ville"><b>Ville&nbsp;:&nbsp;</b></label></span> </td>
<td> <span> <input type="text" name="ville" id="ville" class="form-ville" size="25" maxlength="50" /> </span> </td>
</tr>
<tr class="erreur" id="erreur-ville" style="display:none">
<td colspan="2">* Il faut renseigner votre ville</td>
</tr>
<tr>
<td id="label-tel"> <span> <label for="tel"><b>Numéro de téléphone&nbsp;:&nbsp;</b></label> </span> </td>
<td> <span> <input type="text" name="tel" id="tel" class="form-tel" size="15" maxlength="20" /> </span> </td>
</tr>
<tr class="erreur" id="erreur-tel" style="display:none">
<td colspan="2">* Il faut renseigner votre téléphone</td>
</tr>
<tr>
<td colspan="2" class="form-submit"> <input type="submit" value="Valider" /> </td>
</tr>
</tbody>
</table>

Code JavaScript :

jQuery.fn.getBg = function() {
return $(this).parents().filter(function() {
var color = $(this).css('background-color');
return color != 'transparent' && color != 'rgba(0, 0, 0, 0)';
}).eq(0).css('background-color');
};

function flash(id, font_color, bg_color, nb) {
var bc = $(id).getBg();
var cl = $(id).css('color');
var mx = parseInt(nb);
if (mx <= 0) {
mx = 1;
}
for (var i = 0; i < mx; i++) {
$(id).animate({
backgroundColor: bg_color,
color: font_color
}, 200).animate({
backgroundColor: bc,
color: cl
});
};
}

dataMessage = new Array("#erreur-nomprenom", "#erreur-adresse1", "#erreur-cp", "#erreur-ville", "#erreur-tel");
var theQueue = $({});
for (key in dataMessage) {
var m = dataMessage[key];
if (m.indexOf('#erreur') == 0) {
console.log('should add:'+m);
theQueue.queue('flash', function(next) {
console.log('i will flash:'+m);
$(m).fadeIn('slow', function() {
flash('#label-' + this.id.substr(7), "#ffffff", "#aa0000", 3);
next();
});
});
}
}
theQueue.dequeue('flash');

Solution :

var theQueue = $({});
for (key in dataMessage) {
var m = dataMessage[key];
if (m.indexOf('#erreur') == 0) {
console.log('should add:' + m);
var toFlash = (function(m) {
return function(next) {
console.log('i will flash:' + m);
$(m).fadeIn('slow', function() {
flash('#label-' + this.id.substr(7), "#ffffff", "#aa0000", 3);
next();
});
}
})(m);
theQueue.queue('flash', toFlash);
}
}
theQueue.dequeue('flash');

Eh oui pas si évident que ça à trouver !

Merci à Julien pour son aide !

Si vous avez d’autres solutions n’hésitez pas à les mettre dans un commentaire en bas !

jQuery et changement de css / class / classname

Encore la petite astuce pratique qui vous évitera de chercher des heures :

Très souvent, on veut changer la propriété d’un div. C’est facile via la fonction jQuery

$('#mondiv').css('propriété', 'nouvelle valeur');

Mais si on veut applique carrément tout une classe ?

C’est très simple, c’est la fonction .toggleClass() :

$('#mondiv').toggleClass('nouvelle classe');

jQuery : différence entre visible et hidden

Je voulais tester si un élément est visible, ou non, en jQuery.

Après quelques recherches sur le net, on tombe souvent sur des exemples comme cela :

if ( $("#monid").is(':visible')) {
...
}

C’est une grossière erreur.

Voici l’explication, et le principe qu’il faut avoir en tête :

Lorsqu’on cache ou qu’on montre un élément avec jQuery ou jQueryUI, cela va presque toujours modifier la propriété display (display:none, display:block, etc).

La propriété visible est complètement différente, et est utilisée pour cacher un élément, mais en gardant la place qu’elle occupe.

Pour vérifier si quelque chose est « caché » (notez la subtilité avec la différence de « pas visible« ) il faut vérifier la propriété css display.

Exemple concret :

if ( $("#monid").css('display')!='none') {
...
}

Astuce jQuery : accepter un clic une fois, une seule fois, pas de double clic

A lieu de faire

$('#mon_element').on('click', function() {
  mafonction();
} );

c’est pas « on » c’est « one » :

$('#mon_element').one('click', function() {
  mafonction();
} );

En fait une fois qu’on a cliqué sur l’élément en question, jQuery supprime l’évènement avec la fonction unbind().

jQuery : animate(), queue() et dequeue() solution

Voilà le problème que je viens de rencontrer et que vous avez sûrement rencontré si vous faites un petit peu de jQuery : j’ai fait un <div></div> qui était un petit rectangle, et je voulais, que lorsque la souris entre dedans, il s’agrandisse, et lorsqu’elle en sort, il diminue.

Le problème (qui est la plupart du temps un avantage) avec jQuery, c’est que lorsqu’une animation commence, s’il y en a une autre pour le même élément, il la met dans une queue() (toute plaisanterie grivoise mise à part).
Donc, si, comme moi, vous voulez faire une animation assez lente, et que vous entrez et sortez rapidement avant la fin de l’animation, il va y avoir plein d’éléments qui vont aller à l’intérieur, et… même si vous éloignez la souris, les animations d’entrée-sortie vont continuer à jusqu’à ce que la queue soit vide ! …là aussi toute plaisanterie grivoise mise à part.

La solution est simple : il faut non seulement dire à l’élément concerné d’arrêter l’animation via stop(), mais aussi :

  1. dire de supprimer tout ce qu’il y a dans la queue (premier paramètre = true)
  2. dire de jouer immédiatement l’animation qui suit (premier paramètre = true)

Exemple de code qui fonctionne :

  $('tr')
    .mouseenter(function() {
      var id=$(this).attr('id').substring(3);
      var c=$(this).children('.principal').children('.texte');
      c.stop(true, true).animate({ height: '400px'}, 'slow');
    })  
    .mouseleave(function() {
      var c=$(this).children('.principal').children('.texte');
      c.stop(true, true).animate({ height: '89px'}, 'slow');
    });