121 votes

Modèle externe dans Underscore

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

Dans la vue Backbone, j'ai :

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

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

Dans mon html est :

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

Il fonctionne 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é.

107voto

koorchik Points 761

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);
}

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

Donc, la fonction "rendre"

  1. vous permet de stocker chaque modèle dans un fichier html distinct dans le répertoire statique statique
  2. est très léger
  3. compile et met en cache les modèles
  4. abstrait la logique de chargement des modèles. 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 je pense que c'est important].

si les modèles ne s'affichent pas dans application native et vous voyez HIERARCHY_REQUEST_ERROR: DOM Exception 3 Voir la réponse de Dave Robinson à la question Qu'est-ce qui peut causer l'erreur "HIERARCHY_REQUEST_ERR : DOM Exception 3" ? .

En gros, vous devez ajouter

dataType: 'html'

à la requête $.ajax.

3 votes

@BinaryNights - Devrions-nous toujours ajouter dataType: 'html' à notre requête ajax, juste au cas où ?

0 votes

Cela fonctionne-t-il également pour les vues imbriquées ? Apparemment, je ne peux pas le faire fonctionner si une vue fait référence à une autre vue.

1 votes

Oui, cela devrait également fonctionner pour les modèles imbriqués. Il suffit d'ajouter l'aide de rendu et de l'appeler comme : <%= render('nested_template', data) %>

51voto

Brian Genisio Points 30777

EDIT : Cette réponse est ancienne et périmée. Je la supprimerais bien, mais c'est la réponse "acceptée". Je vais injecter mon opinion à la place.

Je ne préconise plus de faire cela. À la place, je séparerais tous les modèles en fichiers HTML individuels. Certains suggèrent de les charger de manière asynchrone (Require.js ou une sorte de cache pour les modèles). Cela fonctionne bien sur les petits projets mais sur les gros projets avec beaucoup de modèles, vous vous retrouvez à faire une tonne de petites requêtes asynchrones au chargement de la page, ce que je n'aime vraiment pas. (ugh... ok, vous pouvez contourner cela avec Require.js en pré-compilant vos dépendances initiales avec r.js, mais pour les templates, cela me semble toujours erroné)

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, selon moi... les modèles sont dans un fichier, la compilation de ces modèles se fait au moment de la construction (et non de 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 de la camelote

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

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

Ensuite, il suffit d'inclure le fichier script comme un fichier normal et de l'utiliser dans votre vue :

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

En allant un peu plus loin, je en fait utiliser coffeescript, donc mon code ressemble plus à ceci et évite les caractères d'échappement de fin de ligne :

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

Cette approche permet d'éviter d'introduire require.js là où il n'est pas vraiment nécessaire.

46 votes

Cette approche perdrait toutes les fonctions de coloration syntaxique, de reformatage et de refactoring disponibles avec l'ide. pas de vote cependant.

1 votes

Je suis désolé, mais j'ai dû rétrograder cette réponse. C'est horriblement maladroit car il gardera toujours les fichiers de modèles comme des fichiers script, juste un peu forcé à ressembler à des modèles. Les modèles doivent être des modèles, donc si vous devez introduire Require.js ou utiliser la brillante solution de koorchik ci-dessous, je pense que cela en vaut vraiment la peine.

3 votes

@TommiForsström Je suis d'accord. Je me suis éloigné de cette approche. Wow ! Le 4 décembre 2011 est une date très lointaine dans le monde du développement Backbone.js :)

18voto

Dmitriy Points 1324

Ce mixin vous permet d'effectuer le rendu d'un modèle externe à l'aide de Underscore de manière très simple : _.templateFromUrl(url, [data], [settings]) . L'API de la méthode est presque la même que Underscore's _.template() . Mise en cache incluse.

_.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);
}});

Utilisation :

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

2 votes

Très joli petit mélange, très soigné ! Merci pour le partage

0 votes

Très cool D, c'est le genre de solution que je cherchais. et je pense qu'elle pourrait être utilisée pour garder un ensemble de modèles privés.

0 votes

@abhi, il est fourni dans la réponse. En outre, vous avez besoin de jQuery pour charger le modèle, mais vous pouvez réécrire la partie du code qui charge le modèle via AJAX à votre goût en utilisant n'importe quelle autre bibliothèque.

17voto

Tyth Points 153

Je ne voulais pas utiliser require.js pour cette simple tâche, 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 les modèles au 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, de sorte que je n'aurai pas besoin de faire des demandes ajax supplémentaires. Et dans le même temps, je n'aurai pas besoin de faire de refactoring dans mon code, car j'utilise

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

dans mes vues Backbone.

1 votes

Je l'utilise aussi, c'est génial pour le scénario où j'essaie d'utiliser Jasmine pour le TDD et je souhaite tester les modèles avant d'avoir implémenté requirejs et son plugin textjs. Bien joué @Tramp

0 votes

L'appel à $.ajax est asynchrone, tout ce qui dépend des résultats, doit être exécuté dans la méthode done de la promesse retournée.

0 votes

Merci pour cela. Je l'ai utilisé. Une suggestion : il n'y a pas de raison d'ajouter une balise script - on pourrait simplement la convertir en modèle et la conserver dans un hash de recherche. Voici un exemple de bricolage (non fonctionnel) : jsfiddle.net/PyzeF

15voto

nayaab Points 355

Je pense ce est ce qui pourrait vous aider. Tout dans cette solution tourne autour require.js qui est un chargeur de fichiers et de modules JavaScript.

Le tutoriel au lien ci-dessus montre très bien comment un projet de backbone pourrait être organisé. A exemple de réalisation est également fourni. J'espère que cela vous aidera.

3 votes

Merci pour la référence à mon site. Pour ceux qui le souhaitent, j'ai lancé un projet qui tente de mettre en œuvre les meilleures pratiques. backboneboilerplate.com

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