web-dev-qa-db-fra.com

Modèle externe en soulignement

J'utilise modèle de soulignement . Il est possible de joindre un fichier externe comme modèle ?

En mode Backbone, j'ai:

 textTemplate: _.template( $('#practice-text-template').html() ),

 initialize: function(){                                            
  this.words = new WordList;            
  this.index = 0;
  this.render();
 },

Dans mon html, c'est:

<script id="practice-text-template" type="text/template">
   <h3>something code</h3>
</script>

Ça marche bien. Mais j'ai besoin d'un modèle externe . J'essaie:

<script id="practice-text-template" type="text/template" src="templates/tmp.js">

ou

textTemplate: _.template( $('#practice-text-template').load('templates/tmp.js') ),

ou

$('#practice-text-template').load('templates/tmp.js', function(data){ this.textTemplate = _.template( data ) })

mais cela n'a pas fonctionné.

120
Tomáš

EDIT: Cette réponse est ancienne et obsolète. Je l’effacerais, mais c’est la réponse "acceptée". Je vais injecter mon opinion à la place.

Je ne recommanderais plus de faire cela. Au lieu de cela, je séparerais tous les modèles en fichiers HTML individuels. Certains suggéreraient de les charger de manière asynchrone (Require.js ou une sorte de cache de modèles). Cela fonctionne bien pour les petits projets mais sur de gros projets avec beaucoup de modèles, vous vous retrouvez avec une tonne de petites requêtes asynchrones lors du chargement de page que je n'aime pas vraiment. (euh ... ok, vous pouvez le contourner avec Require.js en pré-compilant vos dépendances initiales avec r.js, mais pour les modèles, cela me semble toujours faux)

J'aime utiliser une tâche grunt (grunt-contrib-jst) pour compiler tous les modèles HTML dans un seul fichier templates.js et l'inclure. Vous obtenez le meilleur de tous les mondes Les modèles IMO ... vivent dans une fichier, la compilation desdits modèles a lieu au moment de la construction (pas à l'exécution), et vous n'avez pas cent petites requêtes asynchrones au démarrage de la page.

Tout ce qui est en dessous est indésirable

Pour moi, je préfère la simplicité d'inclure un fichier JS avec mon modèle. Donc, je pourrais créer un fichier appelé view_template.js qui inclut le modèle en tant que variable:

app.templates.view = " \
    <h3>something code</h3> \
";

Il suffit ensuite d'inclure le fichier de script comme un fichier normal, puis de l'utiliser dans votre vue:

template: _.template(app.templates.view)

Pour aller un peu plus loin, j'utilise le coffeescript, mon code ressemble donc davantage à ceci et évite les caractères d'échappement de fin de ligne:

app.templates.view = '''
    <h3>something code</h3>
'''

En utilisant cette approche, vous évitez d’introduire des require.js dans les cas où cela n’est pas vraiment nécessaire.

51
Brian Genisio

Voici une solution simple:

var rendered_html = render('mytemplate', {});

function render(tmpl_name, tmpl_data) {
    if ( !render.tmpl_cache ) { 
        render.tmpl_cache = {};
    }

    if ( ! render.tmpl_cache[tmpl_name] ) {
        var tmpl_dir = '/static/templates';
        var tmpl_url = tmpl_dir + '/' + tmpl_name + '.html';

        var tmpl_string;
        $.ajax({
            url: tmpl_url,
            method: 'GET',
            dataType: 'html', //** Must add 
            async: false,
            success: function(data) {
                tmpl_string = data;
            }
        });

        render.tmpl_cache[tmpl_name] = _.template(tmpl_string);
    }

    return render.tmpl_cache[tmpl_name](tmpl_data);
}

Utiliser "async: false" n'est pas une mauvaise solution car, dans tous les cas, vous devez attendre que le modèle soit chargé.

Donc, "rendre" la fonction

  1. vous permet de stocker chaque modèle dans un fichier html séparé dans un répertoire statique
  2. est très léger
  3. compile et met en cache les modèles
  4. abstracts template logique de chargement. Par exemple, à l'avenir, vous pourrez utiliser des modèles préchargés et précompilés.
  5. est facile à utiliser

[Je modifie la réponse au lieu de laisser un commentaire car j'estime que c'est important.]

si les modèles n'apparaissent pas dans application native et que vous voyez HIERARCHY_REQUEST_ERROR: DOM Exception 3, regardez la réponse de Dave Robinson à Qu'est-ce qui peut provoquer une "HIERARCHY_REQUEST_ERR: DOM Exception 3" - Erreur? .

Fondamentalement, vous devez ajouter

dataType: 'html'

à la demande $ .ajax.

107
koorchik

Ce mixin vous permet de rendre un modèle externe en utilisant Underscore de manière très simple: _.templateFromUrl(url, [data], [settings]). L'API de méthode est presque identique à Underscore _. Template () . Caching inclus.

_.mixin({templateFromUrl: function (url, data, settings) {
    var templateHtml = "";
    this.cache = this.cache || {};

    if (this.cache[url]) {
        templateHtml = this.cache[url];
    } else {
        $.ajax({
            url: url,
            method: "GET",
            async: false,
            success: function(data) {
                templateHtml = data;
            }
        });

        this.cache[url] = templateHtml;
    }

    return _.template(templateHtml, data, settings);
}});

Usage:

var someHtml = _.templateFromUrl("http://example.com/template.html", {"var": "value"});
17
Dmitriy

Je ne voulais pas utiliser require.js pour cette tâche simple, j'ai donc utilisé la solution modifiée de koorchik.

function require_template(templateName, cb) {
    var template = $('#template_' + templateName);
    if (template.length === 0) {
        var tmpl_dir = './templates';
        var tmpl_url = tmpl_dir + '/' + templateName + '.tmpl';
        var tmpl_string = '';

        $.ajax({
            url: tmpl_url,
            method: 'GET',
            contentType: 'text',
            complete: function (data, text) {
                tmpl_string = data.responseText;
                $('head').append('<script id="template_' + templateName + '" type="text/template">' + tmpl_string + '<\/script>');
                if (typeof cb === 'function')
                    cb('tmpl_added');
            }
        });
    } else {
        callback('tmpl_already_exists');
    }
}

require_template('a', function(resp) {
    if (resp == 'tmpl_added' || 'tmpl_already_exists') {
        // init your template 'a' rendering
    }
});
require_template('b', function(resp) {
    if (resp == 'tmpl_added' || 'tmpl_already_exists') {
        // init your template 'b' rendering
    }
});

Pourquoi ajouter des modèles à un document plutôt que de les stocker dans un objet javascript? Parce que dans la version de production, je voudrais générer un fichier HTML avec tous les modèles déjà inclus, donc je n’aurai pas besoin de faire de requêtes ajax supplémentaires. Et dans le même temps, je n’aurai pas besoin de refactoriser mon code, car j’utilise

this.template = _.template($('#template_name').html());

dans mes vues de colonne vertébrale.

17
Tyth

Cela peut être légèrement hors sujet, mais vous pouvez utiliser Grunt (http://gruntjs.com/) - qui fonctionne sur node.js (http://nodejs.org/, disponible pour toutes les principales plates-formes) pour exécuter des tâches à partir du ligne de commande. Il existe de nombreux plugins pour cet outil, comme un compilateur de modèles, https://npmjs.org/package/grunt-contrib-jst . Voir la documentation sur GitHub, https://github.com/gruntjs/grunt-contrib-jst . (Vous aurez également besoin de comprendre comment exécuter le gestionnaire de package de noeud, https://npmjs.org/ . Ne vous inquiétez pas, c'est incroyablement facile et polyvalent.)

Vous pouvez ensuite conserver tous vos modèles dans des fichiers HTML séparés, exécutez l'outil pour les précompiler en utilisant un trait de soulignement (ce qui, à mon avis, est une dépendance du plug-in JST, mais ne vous inquiétez pas, le gestionnaire de paquets du noeud installera automatiquement les dépendances pour vous).

Ceci compile tous vos modèles en un script, disons

templates.js

Le chargement du script définira un paramètre global - "JST" par défaut - qui est un tableau de fonctions, auquel on peut accéder de la manière suivante:

JST['templates/listView.html']()

qui serait semblable à

_.template( $('#selector-to-your-script-template'))

si vous mettez le contenu de cette balise de script dans (templates /) listView.html

Cependant, le vrai kicker est le suivant: Grunt contient cette tâche appelée "surveillance", qui surveillera essentiellement les modifications apportées aux fichiers que vous avez définis dans votre fichier local grunt.js (qui est essentiellement un fichier de configuration pour votre projet Grunt, en javascript). ) Si vous avez démarré cette tâche pour vous, en tapant:

grunt watch

à partir de la ligne de commande, Grunt surveillera toutes les modifications apportées aux fichiers et exécutera automatiquement toutes les tâches que vous avez configurées dans le fichier grunt.js s'il détecte des modifications, comme le (j) tâche décrite ci-dessus. Éditez puis enregistrez vos fichiers et tous vos modèles sont recompilés dans un fichier js, même s’ils sont répartis sur plusieurs répertoires et sous-répertoires.

Des tâches similaires peuvent être configurées pour imbriquer votre javascript, exécuter des tests, concaténer et minimiser/uglifier vos fichiers de script. Et tout peut être lié à la tâche de surveillance afin que les modifications apportées à vos fichiers déclenchent automatiquement une nouvelle "construction" de votre projet.

Il faut un peu de temps pour mettre les choses en place et comprendre comment configurer le fichier grunt.js, mais cela vaut bien le temps investi, et je ne pense pas que vous reviendrez jamais à une méthode de travail pré-grunt

16
Mansiemans

Je pense que this est ce qui pourrait vous aider. Tout dans la solution tourne autour de require.js bibliothèque qui est un fichier JavaScript et un chargeur de module.

Le tutoriel sur le lien ci-dessus montre très bien comment un projet dorsal pourrait être organisé. Un exemple d'implémentation est également fourni. J'espère que cela t'aides.

15
nayaab

J'ai dû définir le type de données sur "texte" pour que cela fonctionne pour moi:

get : function(url) {
    var data = "<h1> failed to load url : " + url + "</h1>";
    $.ajax({
        async: false,
        dataType: "text",
        url: url,
        success: function(response) {
            data = response;
        }
    });
    return data;
}
4
user1828189

Je me suis intéressé sur les templates javascript et maintenant je fais les premiers pas avec backbone. C’est ce que j’ai trouvé et qui semble fonctionner assez bien.

window.App = {

    get : function(url) {
        var data = "<h1> failed to load url : " + url + "</h1>";
        $.ajax({
            async: false,
            url: url,
            success: function(response) {
                data = response;
            }
        });
        return data;
    }
}

App.ChromeView = Backbone.View.extend({
    template: _.template( App.get("tpl/chrome.html") ),
    render: function () {
        $(this.el).html(this.template());
        return this;
    },
});

App.chromeView = new App.ChromeView({ el : document.body });
App.chromeView.render();
4
j040p3d20

J'ai trouvé une solution qui fonctionne pour moi avec l'utilisation de jQuery.

J'ajoute le code du modèle de soulignement, avec la méthode jQuery.load (), au fichier html principal.

Une fois qu'il est là, je l'utilise pour générer les modèles. Tous doivent se produire de manière synchrone!

Le concept est:

J'ai un code de modèle de carte de soulignement:

<!-- MAP TEMPLATE-->
<script type="text/template" id="game-map-template">
    <% _.each(rc, function(rowItem, index){ %>
      <ul class="map-row" data-row="<%- index %>">
        <li class="map-col <%- colItem.areaType ? 'active-area' : '' %>"></li>
        ...
</script>

Et je mets ce code dans un fichier nommé map-template.html

Après cela, je crée un wrapper pour les fichiers de modèle.

<div id="templatesPool"></div>

Ensuite, j'inclus ce fichier dans mon fichier html principal comme suit.

En tête:

<!-- Template Loader -->
<script> 
    $(function(){
      $("#templatesPool").append($('<div>').load("map-template.html")); 
    });
</script> 

À votre santé.

2
Kaloyan Stamatov

Je sais que cette question est vraiment ancienne mais elle est apparue comme le premier résultat d'une recherche google sur les modèles de soulignement ajax.

J'étais fatigué de ne pas trouver une bonne solution pour cela alors j'ai créé la mienne:

https://github.com/ziad-saab/underscore-async-templates

En plus de charger des modèles de soulignement avec AJAX, il ajoute la fonctionnalité <% include%>. J'espère que cela peut être utile à quelqu'un.

1
ziad-saab

Avertissement - Voici les dragons:

Je mentionne l'approche ci-dessous simplement pour aider ceux qui ont du mal à faire en sorte que les piles ASP.NET (et des cadres similaires) fonctionnent de manière harmonieuse avec l'écosystème de js-libs. Il va sans dire qu'il ne s'agit pas d'une solution générique. Ayant dit cela ...

/ fin de la mise en garde

Si vous utilisez ASP.NET, vous pouvez externaliser vos modèles en les plaçant simplement dans une ou plusieurs vues partielles qui leur sont propres. Aka dans votre .cshtml:

  @Html.Partial("path/to/template")

Dans votre template.cshtml:

   // this is razorview and thusly if you ever need to use the @ character in here  
   // you will have to either escape it as @@ or use the html codepoint which is &#64
   // http://stackoverflow.com/questions/3626250/escape-character-in-razor-view-engine
   <script type="text/x-template" id="someId">
        <span class="foo"><%= name %></span>
   </script>

Et maintenant, vous pouvez utiliser le modèle comme d'habitude:

  _.template($("#someId").html())({ name: "Foobar" });

J'espère que cette approche évasive évite à quelqu'un d'économiser une heure de casse-tête.

0
XDS

J'étais un peu mal à l'aise en obligeant jQuery à fonctionner de manière synchrone. J'ai donc modifié le précédent exemple synchrone à l'aide de promesses. C'est à peu près la même chose, mais fonctionne de manière asynchrone. J'utilise des modèles hbs dans cet exemple:

var asyncRenderHbs= function(template_name, template_data) {
    if (!asyncRenderHbs.template_cache) { 
        asyncRenderHbs.template_cache= {};
    }

    var promise= undefined;

    if (!asyncRenderHbs.template_cache[template_name]) {
        promise= new Promise(function(resolve, reject) {
            var template_url= '/templates/' + template_name;
            $.ajax({
                url: template_url,
                method: 'GET',
                success: function(data) {
                    asyncRenderHbs.template_cache[template_name]= Handlebars.compile(data);
                    resolve(asyncRenderHbs.template_cache[template_name](template_data));
                },
                error: function(err, message) {
                    reject(err);
                }           
            });
        });
    } else {
        promise= Promise.resolve(asyncRenderHbs.template_cache[template_name](template_data));
    }

    return promise;
};

Ensuite, pour utiliser le code HTML rendu:

asyncRenderHbs('some_template.hbs', context)
    .then(function(html) {
        applicationMain.append(html);
        // Do other stuff here after html is rendered...
    })
    .catch(function(err) {
        // Handle errors
    });

REMARQUE: comme indiqué par d’autres, il serait préférable de compiler tous les modèles dans un seul fichier templates.js et de le charger au début plutôt que d’avoir de nombreux petits appels synchrones AJAX pour obtenir les chargements de page Web.

0
Megatron