145 votes

Définition d'un modèle HTML à ajouter à l'aide de JQuery

J'ai un tableau que je parcours en boucle. Chaque fois qu'une condition est vraie, je veux ajouter une copie de l'objet de la liste. HTML ci-dessous à un élément conteneur avec quelques valeurs.

Où puis-je mettre ce HTML pour le réutiliser de manière intelligente ?

<a href="#" class="list-group-item">
    <div class="image">
         <img src="" />
    </div>
    <p class="list-group-item-text"></p>
</a>

JQuery

$('.search').keyup(function() {
    $('.list-items').html(null);

    $.each(items, function(index) {
        // APPENDING CODE HERE
    });
});

228voto

Josh from Qaribou Points 955

Vieille question, mais puisque la question demande "l'utilisation de jQuery", j'ai pensé que je pourrais fournir une option qui vous permet de le faire sans introduire une dépendance de fournisseur.

Bien qu'il existe de nombreux moteurs de modélisation, nombre de leurs fonctionnalités sont tombées en disgrâce récemment, avec l'itération ( <% for ), les conditionnels ( <% if ) et transforme ( <%= myString | uppercase %> ) considérés au mieux comme un micro-langage, et au pire comme des anti-modèles. Les pratiques modernes de modélisation encouragent le simple mappage d'un objet à sa représentation DOM (ou autre), par exemple ce que nous voyons avec les propriétés mappées aux composants dans ReactJS (en particulier les composants sans état).

Modèles à l'intérieur du HTML

Une propriété sur laquelle vous pouvez compter pour garder le HTML de votre modèle à côté du reste de votre HTML, est l'utilisation d'un fichier non exécutant <script> type par exemple <script type="text/template"> . Pour votre cas :

<script type="text/template" data-template="listitem">
    <a href="${url}" class="list-group-item">
        <table>
            <tr>
                <td><img src="${img}"></td>
                <td><p class="list-group-item-text">${title}</p></td>
            </tr>
        </table>
    </a>
</script>

Au chargement du document, lisez votre modèle et tokenisez-le à l'aide d'une simple fonction String#split

var itemTpl = $('script[data-template="listitem"]').text().split(/\$\{(.+?)\}/g);

Remarquez qu'avec notre jeton, vous l'obtenez en alternance. [text, property, text, property] format. Cela nous permet de le mettre en correspondance de manière agréable en utilisant un fichier Array#map avec une fonction de mise en correspondance :

function render(props) {
  return function(tok, i) { return (i % 2) ? props[tok] : tok; };
}

props pourrait ressembler à { url: 'http://foo.com', img: '/images/bar.png', title: 'Lorem Ipsum' } .

En mettant tout ça ensemble, en supposant que vous avez analysé et chargé votre itemTpl comme ci-dessus, et vous avez un items réseau dans le champ d'application :

$('.search').keyup(function () {
  $('.list-items').append(items.map(function (item) {
    return itemTpl.map(render(item)).join('');
  }));
});

Cette approche n'est également qu'à peine jQuery - vous devriez être en mesure de prendre la même approche en utilisant vanilla javascript avec document.querySelector y .innerHTML .

jsfiddle

Modèles dans JS

Une question à se poser est la suivante : voulez-vous vraiment/avez-vous besoin de définir les modèles comme des fichiers HTML ? Vous pouvez toujours composer et réutiliser un modèle de la même manière que vous réutiliseriez la plupart des choses que vous voulez répéter : avec une fonction.

Au pays d'es7, l'utilisation de la déstructuration, des chaînes de modèles et des fonctions fléchées permet d'écrire des fonctions de composants très jolies qui peuvent être facilement chargées à l'aide de l'outil de gestion des composants. $.fn.html méthode ci-dessus.

const Item = ({ url, img, title }) => `
  <a href="${url}" class="list-group-item">
    <div class="image">
      <img src="${img}" />
    </div>
    <p class="list-group-item-text">${title}</p>
  </a>
`;

Ensuite, vous pourriez facilement le rendre, même mappé à partir d'un tableau, comme ceci :

$('.list-items').html([
  { url: '/foo', img: 'foo.png', title: 'Foo item' },
  { url: '/bar', img: 'bar.png', title: 'Bar item' },
].map(Item).join(''));

Oh et note finale : n'oubliez pas de désinfecter vos propriétés passées à un modèle, si elles sont lues à partir d'une DB, ou quelqu'un pourrait passer du HTML (et ensuite exécuter des scripts, etc.) à partir de votre page.

174voto

Vous pouvez décider d'utiliser un moteur de modélisation dans votre projet, par exemple :

Si vous ne voulez pas inclure une autre bibliothèque, John Resig propose une Solution jQuery semblable à celui ci-dessous.


Les navigateurs et les lecteurs d'écran ignorent les types script non reconnus :

<script id="hidden-template" type="text/x-custom-template">
    <tr>
        <td>Foo</td>
        <td>Bar</td>
    <tr>
</script>

En utilisant jQuery, l'ajout de rangs basés sur le modèle ressemblerait :

var template = $('#hidden-template').html();

$('button.addRow').click(function() {
    $('#targetTable').append(template);
});

53voto

GlupiJas Points 196

Utilisez plutôt un modèle HTML !

Puisque la réponse acceptée représenterait la surcharge de la méthode script, je voudrais en suggérer une autre qui est, à mon avis, beaucoup plus propre et plus sûre en raison des risques XSS qui viennent avec la surcharge de script.

J'ai fait un Démo pour vous montrer comment l'utiliser dans une action et comment injecter un modèle dans un autre, le modifier puis l'ajouter au DOM du document.

exemple html

<template id="mytemplate">
  <style>
     .image{
        width: 100%;
        height: auto;
     }
  </style>
  <a href="#" class="list-group-item">
    <div class="image">
      <img src="" />
    </div>
    <p class="list-group-item-text"></p>
  </a>
</template>

exemple js

// select
var t = document.querySelector('#mytemplate');

// set
t.content.querySelector('img').src = 'demo.png';
t.content.querySelector('p').textContent= 'demo text';

// add to document DOM
var clone = document.importNode(t.content, true); // where true means deep copy
document.body.appendChild(clone);

HTML <template>

  • +Son contenu est effectivement inerte jusqu'à ce qu'il soit activé. Essentiellement, votre balises sont cachées dans le DOM et ne sont pas rendues.

  • +Le contenu d'un modèle n'aura pas d'effets secondaires. Les scripts ne s'exécutent pas, les images ne se chargent pas, l'audio ne joue pas ...tant que le modèle n'est pas utilisé.

  • +Le contenu est considéré comme ne faisant pas partie du document. Utilisation de document.getElementById() o querySelector() dans la page principale ne retournera pas les noeuds enfants d'un modèle.

  • +Les modèles peuvent être placés n'importe où à l'intérieur de l'arborescence. <head> , <body> ou <frameset> et peut contenir tout type de contenu autorisé dans ces éléments. Notez que "n'importe où" signifie que <template> peut être utilisé en toute sécurité à des endroits que l'analyseur HTML n'autorise pas.

Reculer

La prise en charge des navigateurs ne devrait pas être un problème, mais si vous voulez couvrir toutes les possibilités, vous pouvez faire une vérification facile :

Pour détecter les caractéristiques <template> crée l'élément DOM et vérifie que la propriété .content existe :

function supportsTemplate() {
  return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
  // Good to go!
} else {
  // Use old templating techniques or libraries.
}

Un aperçu de la surcharge de la méthode script.

  • +Rien n'est rendu - le navigateur ne rend pas ce bloc parce que l'adresse de l'utilisateur a été modifiée. <script> L'étiquette a display:none par défaut.
  • +Inert - le navigateur n'analyse pas le contenu de script comme JS parce que son type est défini comme autre chose que "text/javascript" .
  • -Les questions de sécurité - encourage l'utilisation de .innerHTML . L'analyse syntaxique des données fournies par l'utilisateur peut facilement conduire à des vulnérabilités XSS.

Article complet : https://www.html5rocks.com/en/tutorials/webcomponents/template/#toc-old

Référence utile : https://developer.mozilla.org/en-US/docs/Web/API/Document/importNode http://caniuse.com/#feat=queryselector

CRÉATION DE COMPOSANTS WEB Tutoriel sur la création de composants web personnalisés à l'aide de modèles HTML par Trawersy Media : https://youtu.be/PCWaFLy3VUo

13voto

Mateusz Nowak Points 3571

Ajouter quelque part dans le corps

<div class="hide">
<a href="#" class="list-group-item">
    <table>
        <tr>
            <td><img src=""></td>
            <td><p class="list-group-item-text"></p></td>
        </tr>
    </table>
</a>
</div>

puis créer le css

.hide { display: none; }

et ajoutez à votre js

$('#output').append( $('.hide').html() );

3voto

Sebastian Neira Points 539

Afin de résoudre ce problème, je reconnais deux solutions :

  • La première va avec AJAX, avec lequel vous devrez charger le modèle à partir d'un autre fichier et ajouter chaque fois que vous le souhaitez avec .clone() .

    $.get('url/to/template', function(data) {
        temp = data
        $('.search').keyup(function() {
            $('.list-items').html(null);
    
            $.each(items, function(index) {
                 $(this).append(temp.clone())
            });
    
        });
    });

    Tenez compte du fait que l'événement doit être ajouté une fois que l'ajax est terminé pour être sûr que les données sont disponibles !

  • La seconde serait de l'ajouter directement n'importe où dans le html original, de le sélectionner et de le cacher avec jQuery :

    temp = $('.list_group_item').hide()

    Vous pouvez ensuite ajouter une nouvelle instance du modèle avec

    $('.search').keyup(function() {
        $('.list-items').html(null);
    
        $.each(items, function(index) {
            $(this).append(temp.clone())
        });
    });
  • Comme la précédente, mais si vous ne voulez pas que le modèle reste là, mais juste dans le javascript, je pense que vous pouvez utiliser (je ne l'ai pas testé !) .detach() au lieu de cacher.

    temp = $('.list_group_item').detach()

    .detach() supprime les éléments du DOM tout en gardant les données et les événements en vie (.remove() ne le fait pas !).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X