Est-il possible de prendre en quelque sorte un élément DOM d'un modèle de soulignement et de l'utiliser comme un autre modèle?
L'idée est que mon application doit restituer un document contenant une boucle avec des éléments et un résumé. Je dois occasionnellement refaire le rendu du résumé ou de quelques éléments afin de ne pas refaire le rendu du document entier.
Cependant, j'aimerais que les utilisateurs de l'application créent facilement leurs propres modèles pour le document et je pense que le fait de tout conserver dans un seul fichier pour un document faciliterait les choses.
J'essaie d'utiliser quelque chose comme ceci:
<script type="text/template" id="document-template">
<div id="document">
<h1><%= name %></h1>
<ul class="items">
<% _.each(items, function(item) { %>
<li><%= item %></li>
<% }); %>
</ul>
<div id="summary">
<p>Total items: <%= totalitems %></p>
</div>
</div>
</script>
Maintenant, je peux facilement faire cela var documentTemplate = _.template($('#document-template').html());
pour transformer cela en un modèle de document, mais je voudrais également transformer la partie récapitulative en un modèle et un élément de liste en un modèle.
Puis-je faire quelque chose comme ça:
var summaryTemplate = _.template($('#document-template #summary').html());
var itemTemplate = _.template($('#document-template .items li').html());
PS. En fait, je charge le modèle depuis un fichier externe en utilisant $ .get de jQuery. De cette façon, je vais obtenir le modèle de document dans une grosse chaîne. À partir de là, je peux juste faire documentTemplate = _.template(loadedString);
.
Maintenant, si je pouvais simplement extraire l’élément #summary de la chaîne, cela devrait fonctionner. Mais lorsque j'essaie de convertir la chaîne en élément DOM (var domElement = $(loadedString)
) (Pour que je puisse le faire: summaryTemplate = _.template($('#summary',domElement).html());
, cela ne fonctionnera pas, car le trait de soulignement ne reconnaît plus les balises <% =%>.
Vous pouvez transmettre le modèle imbriqué en tant que variable dans les affectations de modèle au modèle principal, par exemple:
HTML:
<script type="text/template" id="sub_template">
<article>
<h1>id: <%= id %><h1>
</article>
</script>
<script type="text/template" id="main_template">
<% for (var i = 0; i < num; i++) { %>
<%= renderSub({id:i}) %>
<% } %>
</script>
JS:
var renderSub = _.template( $('#sub_template').remove().text() ),
renderMain = _.template( $('#main_template').remove().text() );
renderMain({num:5, renderSub:renderSub});
/////// TEMPLATES //////
var mainTemplate = "<ul> \
<% _.each(items, function(item) { %> \
<%= listItem({item:item}) %> \
<% }); %> \
<ul>";
var subTemplate = '<li><%=item %></li>';
/////// MODEL (our data) //////
var model = {
items : [1,2,3,4,5]
}
/////// COMPILE //////
// add the subTemplate to the model data, to be passed to the mainTemplate
model.listItem = _.template(subTemplate);
// Render main template to the DOM
document.body.innerHTML = _.template(mainTemplate, model);
Au lieu de tout charger en même temps en tant que modèle unique, puis d'essayer de charger une partie de celui-ci ultérieurement, séparez-les en plusieurs modèles.
Ayez votre modèle de document principal et un modèle de résumé. Le chargement initial extrait le document-modèle, puis dans le résumé-modèle et l'insère dans le DOM compilé à partir du premier modèle. Ensuite, vous pouvez recharger le deuxième modèle à tout moment. Voir les étapes suivantes:
1) Charger le modèle initial, illustré ci-dessous:
<script type="text/template" id="document-template">
<div id="document">
<h1><%= name %></h1>
<ul class="items">
<% _.each(items, function(item) { %>
<li><%= item %></li>
<% }); %>
</ul>
</div>
</script>
2) Une fois que cela est compilé dans le DOM, chargez le deuxième modèle via le trait de soulignement, comme indiqué ci-dessous:
<script type="text/template" id="summary-template">
<div id="summary">
<p>Total items: <%= totalitems %></p>
</div>
</script>
3) Appelez $ ("# document"). Append (summaryTemplate) ou la variable contenant le modèle compilé.
4) Répétez les étapes 2 et 3 chaque fois que vous avez besoin de recharger le résumé, sauf d’abord, supprimez le $ ("# summary") existant avant d’ajouter de nouveau.
Vous pouvez également utiliser cette même stratégie pour les éléments. Assurez-vous simplement d’utiliser les sélecteurs/méthodes jQuery appropriés afin d’écraser les div existants dans le bon ordre. Append ne fonctionnera que pour ajouter quelque chose à la fin d’un élément.
Je sais que j'ai 3 ans de retard dans la conversation, mais aucune de ces réponses ne s'appliquait à une situation que j'avais dans mon dernier projet. Et comme ma façon de penser à l’origine du jeu a finalement fonctionné, j’ai pensé que je devrais l’afficher au cas où quelqu'un voudrait imbriquer réellement des modèles underscore.js, comme le titre de cette question l’indique.
Mes exigences étaient fondamentalement:
1) Si un modèle contient des éléments dynamiques, ceux-ci doivent être en mesure de se restituer individuellement, sans exiger que le modèle entier soit restitué avec les données mises à jour.
2) Les pièces dynamiques ne devraient pas avoir besoin d'être dissociées dans leurs propres modèles au même niveau que le modèle parent; au lieu de cela, il devrait y avoir une sorte de hiérarchie de modèles - un modèle déclarant tous les sous-modèles requis pour lui-même.
Le concept de modèles imbriqués dans Underscore.js est identique à celui utilisé dans PHP (par exemple). Le code suivant est un exemple "faisant écho à PHP":
<?php echo '<?php echo $var_unknown_until_runtime; ?>'; ?>
Bien que cette syntaxe imbriquée puisse être extrêmement compliquée et déroutante, l’idée est simple:
Code d'écho qui fera écho aux valeurs plus tard.
Cela s'applique également aux modèles Underscore.js.
Le code ressemblera à ceci:
<script type="text/template" id="outer-tpl">
<%= value %>
<script type="text/template" id="inner-tpl">
<%= '<%= value %\>' %> <!-- NOTE how the inner '>' is escaped ('\>') -->
<%= "</script\>" %> <!-- NOTE same thing -->
</script>
Décomposons cela un peu. La ligne avec la première NOTE
est notre ligne clé ici. Normalement, lorsque Underscore compile ce modèle, vous devez vous attendre à ce que la valeur de value
soit imprimée dans les modèles interne et externe. Nous avons fait quelques choses pour empêcher cela:
1) Transformez l’énoncé de soulignement imbriqué en chaîne.
2) Interpolez cette chaîne (
<%= "string here" %>
).3) échappez le
>
de clôture dans l'instruction de soulignement imbriqué (\>
). Cela empêche les expressions rationnelles d’Underscore de correspondre à la balise d’ouverture de l’étape 2 (<%=
). Lorsque cette chaîne est répercutée, le caractère d'échappement est supprimé, laissant%>
, prêt à être interprété par Underscore lors de la prochaine passe.
Faire la même chose dans la seconde NOTE
de notre exemple empêche le navigateur de terminer la première balise script
. Les balises script
imbriquées ne sont techniquement pas autorisées. Par conséquent, le navigateur recherche la première séquence de caractères: </script>
, puis termine l'exécution du script. Cela empêche le navigateur de reconnaître cette séquence.
Pour un exemple plus détaillé, voir ceci JSFiddle .
Je n'approuve pas cela comme n'importe où près de la meilleure façon de faire ce genre de chose. C'est, après tout, très hacky. Alors que la réponse de @John z casse ma première exigence, ce qui n'était pas une option pour moi, l'autre option consistant à fractionner des éléments dynamiques d'un modèle dans leurs propres modèles peut être plus facile à gérer. C'est juste moins organisé.
Il peut être difficile de suivre l’emplacement de toutes ces balises script
imbriquées dans votre DOM (car les balises imbriquées script
seront injectées dynamiquement dans le DOM quand et où vous insérez le modèle externe). Le risque de duplication est élevé et peut être ennuyeux à maintenir.
La difficulté d'imbrication des modèles augmente considérablement pour chaque niveau d'imbrication (pour imbriquer un modèle dans un modèle imbriqué, vous devez tout échapper à nouveau, etc.). Le violon en donne un exemple.