web-dev-qa-db-fra.com

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

J'ai un tableau que je boucle en boucle. Chaque fois qu'une condition est vraie, je souhaite ajouter une copie du code HTML ci-dessous à un élément conteneur contenant certaines valeurs.

Où puis-je mettre ce code HTML à 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
    });
});
105
Patrick Reck

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

Si vous ne souhaitez pas inclure une autre bibliothèque, John Resig propose une solution jQuery , similaire à celle ci-dessous.


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

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

Avec jQuery, ajouter des lignes basées sur le modèle ressemblerait à ceci:

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

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

Vieille question, mais puisque la question demande "utiliser jQuery", je pensais que je fournirais une option qui vous permet de le faire sans introduire de dépendance du fournisseur.

Bien qu'il existe de nombreux moteurs de gabarit, beaucoup de leurs fonctionnalités ont récemment été désavantagées, avec l'itération (<% for), les conditionnels (<% if) et les transformations (<%= myString | uppercase %>) considérées au mieux comme microlangues et au pire. Les pratiques modernes de création de modèles encouragent simplement la mise en correspondance d'un objet avec sa représentation DOM (ou autre), par ex. 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 conserver le code HTML de votre modèle à côté du reste de votre code HTML consiste à utiliser un <script> non-exécutable _ 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>

Lors du chargement du document, lisez votre modèle et créez-le en utilisant un simple String#split

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

Notez qu'avec notre jeton, vous l'obtenez au format alternatif [text, property, text, property]. Cela nous permet de bien le mapper en utilisant un Array#map, avec une fonction de mappage:

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' }.

Rassemblez tout en supposant que vous ayez analysé et chargé votre itemTpl comme ci-dessus et que vous ayez un tableau items:

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

Cette approche est également à peine jQuery - vous devriez être capable de prendre la même approche en utilisant le javascript Vanilla avec document.querySelector et .innerHTML.

jsfiddle

Modèles à l'intérieur de JS

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

Dans es7-land, à l'aide de la déstructuration, des chaînes de modèle et des fonctions de flèche, vous pouvez écrire des fonctions de composants jolies et jolies qui peuvent être facilement chargées à l'aide de la méthode $.fn.html 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 pouvez facilement le rendre, même mappé depuis 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 nettoyer vos propriétés transmises à un modèle, si elles sont lues à partir d'une base de données, sinon quelqu'un pourrait passer au format HTML (puis exécuter des scripts, etc.) à partir de votre page.

135
Josh from Qaribou

Utilisez plutôt un modèle HTML!

Étant donné que la réponse acceptée représenterait une méthode de script de surcharge, je souhaiterais en proposer une autre qui, à mon avis, est beaucoup plus propre et plus sûre en raison des risques XSS liés aux scripts de surcharge.

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

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 & lttemplate>

  • + Son contenu est effectivement inerte jusqu'à ce qu'il soit activé. Essentiellement, votre balisage est un DOM masqué et ne s'affiche pas.

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

  • + Le contenu est considéré ne pas être dans le document. L'utilisation de document.getElementById() ou querySelector() dans la page principale ne renvoie pas de nœuds enfants d'un modèle.

  • + Les modèles peuvent être placés n'importe où dans <head>, <body> ou <frameset> et peuvent 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é dans des endroits interdits par l'analyseur HTML.

Se retirer

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

Pour détecter les fonctionnalités <template>, créez l'élément DOM et vérifiez 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.
}

Quelques informations sur la méthode de script Overloading

  • + Rien n'est rendu - le navigateur ne rend pas ce bloc car la balise <script> a display:none par défaut.
  • + Inert - le navigateur n'analyse pas le contenu du script en tant que JS car son type est défini sur autre chose que "text/javascript".
  • - Problèmes de sécurité - encourage l'utilisation de .innerHTML. L'analyse des chaînes au moment de l'exécution 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/importNodehttp://caniuse.com/#feat=queryselector

29
DevWL

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éez css

.hide { display: none; }

et ajouter à votre js

$('#output').append( $('.hide').html() );
13
Mateusz Nowak

Autre alternative: Pure

Je l'utilise et cela m'a beaucoup aidé. Un exemple montré sur leur site web:

HTML

<div class="who">
</div>

JSON

{
  "who": "Hello Wrrrld"
}

Résultat

<div class="who">
  Hello Wrrrld
</div>
3
alditis

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

  • Le premier correspond à AJAX, avec lequel vous devez charger le modèle à partir d’un autre fichier et l’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 l'ajax terminé pour être sûr que les données sont disponibles!

  • La seconde serait de l'ajouter directement n'importe où dans le code HTML d'origine, de le sélectionner et de le masquer dans 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())
        });
    });
    
  • Identique au précédent, mais si vous ne voulez pas que le modèle reste là, mais juste dans le javascript, je pense que vous pouvez utiliser (ne l'avez pas testé!) .detach() au lieu de masquer.

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

    .detach() supprime les éléments du DOM tout en conservant les données et les événements actifs (ce n'est pas le cas de .remove ()!).

2
Sebastian Neira