2015-09-15 14 views
11

Ich weiß nicht, wie ich das Folgende lösen soll: Ich möchte mein Model dynamisch auf Basis einiger Modelllogik dynamisches JavaScript generieren lassen.Thymeleaf th: inline = "javascript" Ausgabe

Dieser letzte Teil von JavaScript-Code sollte dann innerhalb der $ (Dokument) .ready {} Teil meiner HTML-Seite hinzugefügt werden.

Die Sache ist: Wenn ich inline = „javascript“ verwenden, wird der Code zitiert mein Getter ein String ist (das ist, wie es in der Thymeleaf doc erwähnt wird, aber es ist nicht das, was ;-) Ich brauche

Wenn ich inline = "text" benutze wird in quotes aber alle quotes werden stattdessen maskiert ;-) - auch nett aber unbrauchbar 8)

Wenn ich inline versuche = "none" passiert nichts.

Hier sind die Beispiele

Mein Modell Getter den folgenden Javascript-Code erstellt.

PageHelper Klasse

public String documentReady() { 

// do some database operations to get the numbers 8,5,3,2 
return "PhotoGallery.load(8,5,3,2).loadTheme(name='basic')"; 

} 

Also, wenn jetzt inline = "javascript" Ich versuche

<script th:inline="javascript"> 
/*<![CDATA[*/ 
    jQuery().ready(function(){ 
     /*[[${pageHelper.documentReady}]]*/ 
    }); 
/*]]>*/ 
</script> 

es

<script> 
/*<![CDATA[*/ 
    jQuery().ready(function(){ 
     'PhotoGallery.load(8,5,3,2).loadTheme(name=\'basic\')' 
    }); 
/*]]>*/ 
</script> 

gemacht wird, die nicht der Fall ist Hilfe, wie es eine Zeichenfolge litera ist l, nichts mehr (so behandelt Thymeleaf es).

Also, wenn ich inline versuchen = "text" statt

<script> 
/*<![CDATA[*/ 
    jQuery().ready(function(){ 
     PhotoGallery.load(8,5,3,2).loadTheme(name=&#39;basic&#39;) 
    }); 
/*]]>*/ 
</script> 

Welche entgeht den Anführungszeichen.

inline = „none“ Ich verstehe nicht wirklich, da es nichts tut

<script> 
/*<![CDATA[*/ 
    jQuery().ready(function(){ 
     [[${pageHelper.documentReady}]] 
    }); 
/*]]>*/ 
</script> 

Um ehrlich zu sein, ich habe keine Ahnung, wie dieses Problem zu lösen, und hoffentlich heraus da jemand weiß, wie man mit umgehen Dies.

Vielen Dank im Voraus Prost John

+0

Nun, Sie können immer 'eval()' verwenden, obwohl es definitiv nicht die schönste Lösung ist. – Kejml

+0

Hallo Kejml. Danke für diese schnelle Hilfe. Und in der Tat funktioniert eval() ;-) Was für ein schmutziger Hack. Hatte google eval() googeln, da ich mich definitiv nicht wirklich erinnern konnte, aber am Ende funktionierte mein 'inline =" javascript "' in Verbindung mit 'eval ([{{{Helper.documentReady}]]) wirklich gut. Obwohl ich diese Frage gerne für einen Moment unbeachtet lassen würde, um zu sehen, ob es einen "offiziellen" Thymelaf-Weg gibt. Jedenfalls. Vielen Dank nochmal. Prost. John. –

+0

Sicher, ich denke nicht, dass dies der richtige Weg ist, deshalb habe ich es als Kommentar gepostet, nicht als Antwort, aber es bringt dich am wenigsten in Gang. Hoffentlich kommt jemand mit der richtigen Antwort. Prost :) – Kejml

Antwort

10

würde ich den Ansatz ändern. Mit Thymeleaf können Sie einfach Modellvariablen in Ihre Vorlagen einfügen, um sie in Javascript zu verwenden. In meinen Implementierungen setze ich diese Variablen normalerweise vor das schließende Header-Tag; um sicherzustellen, dass sie auf der Seite sind, sobald JS geladen wird. Ich lasse die Vorlage natürlich entscheiden, was genau geladen werden soll. Wenn Sie eine Galerie anzeigen, rendern Sie sie wie gewünscht und verwenden Sie Datenattribute, um die Galerie zu definieren, die sich auf einen JS-Code bezieht. Dann schreibe dir eine nette jQuery plugin für deine Galerie.

Ein relativ einfaches Beispiel:

Standard-Layout Decorator: Layout/default.html

<!doctype html> 
<html xmlns:layout="http://www.thymeleaf.org" xmlns:th="http://www.thymeleaf.org"> 
<head> 
    <title>My Example App</title> 
    <object th:remove="tag" th:include="fragments/scripts :: header" /> 
</head> 
<body> 
    <div layout:fragment="content"></div> 
    <div th:remove="tag" th:replace="fragments/scripts :: footer"></div> 
    <div th:remove="tag" layout:fragment="footer-scripts"></div> 
</body> 
</html> 

Die Sache zu bemerken ist hier die Einbeziehung der generischen Fußzeile Skripte und dann ein Layout: Fragment div definiert. Mit diesem Layout-Div werden wir unser jQuery-Plugin für die Galerie verwenden.

Datei mit allgemeinen Skripte: Fragmente/scripts.html

<div th:fragment="header" xmlns:th="http://www.thymeleaf.org"> 
    <script type="text/javascript" th:inline="javascript"> 
    /*<![CDATA[*/ 
    var MY_APP = { 
     contextPath: /*[[@{/}]]*/, 
     defaultTheme: /*[[${theme == null} ? null : ${theme}]]*/, 
     gallery: { 
     theme: /*[[${gallery == null} ? null : ${gallery.theme}]]*/, 
     images: /*[[${gallery == null} ? null : ${gallery.images}]]*/, 
     names: /*[[${gallery == null} ? null : ${gallery.names}]]*/ 
     } 
    }; 
    /*]]>*/ 
    </script> 
</div> 
<div th:fragment="footer" xmlns:th="http://www.thymeleaf.org"> 
    <script type="text/javascript" src="/js/jquery.js"></script> 
    <script type="text/javascript" src="/js/my_app.js"></script> 
</div> 

In den Skripten Datei gibt es zwei Fragmente, die aus dem Dekorateur enthalten sind. Im Header-Fragment ist ein hilfreicher Kontextpfad für die JS-Ebene enthalten, ebenso wie ein DefaultTheme nur zum Spaß. Ein Galerieobjekt wird dann von unserem Modell definiert und zugewiesen. Das Fußzeilenfragment lädt die jQuery-Bibliothek und eine JS-Hauptdateidatei erneut, und zwar für die Zwecke dieses Beispiels.

Eine Seite mit einer faulen belasteten Galerie: products.html

<html layout:decorator="layout/default" xmlns:layout="http://www.thymeleaf.org/" xmlns:th="http://www.thymeleaf.org"> 
<head> 
    <title>Products Landing Page</title> 
</head> 
<body> 
    <div layout:fragment="content"> 
    <h1>Products</h1> 
    <div data-gallery="lazyload"></div> 
    </div> 
    <div th:remove="tag" layout:fragment="footer-scripts"> 
    <script type="text/javascript" src="/js/my_gallery.js"></script> 
    </div> 
</body> 
</html> 

Unsere Produkte Seite nicht viel drauf. Mit dem Standard-Dekorator überschreibt diese Seite den Seitentitel im Kopf. Unser Inhaltsfragment enthält einen Titel in einem h1 -Tag und ein leeres div mit einem Datengalerienattribut. Dieses Attribut wird in unserem jQuery-Plugin verwendet, um die Galerie zu initialisieren. Der Wert ist auf lazyload gesetzt, also weiß unser Plugin, dass wir die Bild-IDs irgendwo in einer Variablen finden müssen. Dies könnte leicht leer gewesen sein, wenn das einzige, was unser Plugin unterstützt, eine Lazy Loaded Gallery ist.

So lädt das Layout einige Standard-Skripte und mit geschickt platzierten Layout: Fragmente, erlauben Sie bestimmten Bereichen der Website Bibliotheken unabhängig von den Rest zu laden.

Hier ist ein grundlegendes Feder Controller Beispiel mit unseren App zu arbeiten: MyController.java

@Controller 
public class MyController { 
    @RequestMapping("/products") 
    public String products(Model model) {   
    class Gallery { 
     public String theme; 
     public int[] images; 
     public String[] names; 
     public Gallery() { 
     this.theme = "basic"; 
     this.images = new int[] {8,5,3,2}; 
     this.names = new String[] {"Hey", "\"there's\"", "foo", "bar"}; 
     } 
    } 
    model.addAttribute("gallery", new Gallery()); 
    return "products"; 
    } 
} 

Die Galerie Klasse inline in der Produkte-Methode geworfen wurde, unser Beispiel hier zu vereinfachen. Dies könnte leicht ein Service oder ein Repository eines Typs sein, der ein Array von Identifikatoren oder was auch immer Sie benötigen zurückgibt.

Unser jQuery-Plugin, das wir erstellt haben, könnte so etwas wie so aussehen: my_gallery.js

(function($) { 
    var MyGallery = function(element) { 
    this.$el = $(element); 
    this.type = this.$el.data('gallery'); 
    if (this.type == 'lazyload') { 
     this.initLazyLoadedGallery(); 
    } 
    }; 

    MyGallery.prototype.initLazyLoadedGallery = function() { 
    // do some gallery loading magic here 
    // check the variables we loaded in our header 
    if (MY_APP.gallery.images.length) { 
     // we have images... sweet! let's fetch them and then do something cool. 
     PhotoGallery.load(MY_APP.gallery.images).loadTheme({ 
     name: MY_APP.gallery.theme 
     }); 
     // or if load() requires separate params 
     var imgs = MY_APP.gallery.images; 
     PhotoGallery.load(imgs[0],imgs[1],imgs[2],imgs[3]).loadTheme({ 
     name: MY_APP.gallery.theme 
     }); 
    } 
    }; 

    // the plugin definition 
    $.fn.myGallery = function() { 
    return this.each(function() { 
     if (!$.data(this, 'myGallery')) { 
     $.data(this, 'myGallery', new MyGallery(this)); 
     } 
    }); 
    }; 

    // initialize our gallery on all elements that have that data-gallery attribute 
    $('[data-gallery]').myGallery(); 
}(jQuery)); 

Die endgültige Wiedergabe der Produkte Seite würde wie so aussehen:

<!doctype html> 
<html> 
<head> 
    <title>Products Landing Page</title> 
    <script type="text/javascript"> 
    /*<![CDATA[*/ 
    var MY_APP = { 
     contextPath: '/', 
     defaultTheme: null, 
     gallery: { 
     theme: 'basic', 
     images: [8,5,3,2], 
     names: ['Hey','\"there\'s\"','foo','bar'] 
     } 
    }; 
    /*]]>*/ 
    </script> 
</head> 
<body> 
    <div> 
    <h1>Products</h1> 
    <div data-gallery="lazyload"></div> 
    </div> 
    <script type="text/javascript" src="/js/jquery.js"></script> 
    <script type="text/javascript" src="/js/my_app.js"></script> 
    <script type="text/javascript" src="/js/my_gallery.js"></script> 
</body> 
</html> 

Wie Sie sehen können , Thymeleaf ist ziemlich gut darin, Ihr Modell in gültiges JS zu übersetzen und fügt die Zitate dort hinzu, wo sie gebraucht werden und entgeht ihnen auch. Sobald die Seite mit dem jQuery-Plugin am Ende der Datei fertig ist, sollte alles, was zur Initialisierung der Galerie benötigt wird, geladen werden und fertig sein.

Das ist nicht ein perfektes Beispiel, aber ich denke, es ist ein ziemlich geradliniges Design-Muster für eine Web-App.

+0

Hallo Yorgo, danke für diese tolle Erklärung. Es scheint, dass ich meinen Ansatz wirklich umgestalten muss, wie Sie es vorgeschlagen haben. Ich habe es bereits vermutet, nachdem Kejml und Hossein das auch angedeutet haben. Also danke an alle. Prost John –

+0

Ich hätte erwartet, dass es keinen umgekehrten Schrägstrich vor dem doppelten Zitat in HTML gibt. Warum sollte Thymeleaf dem doppelten Zitat entkommen, wenn es nicht wirklich gebraucht wird? – T3rm1

+0

Gute Frage T3rm1. Ich kann mich nicht erinnern, wie ich die endgültige Ausgabe dort bekommen habe ... wahrscheinlich eine Quelltextquelle, copy/paste. Ich habe sie in dem Sample-Controller, den ich eingefügt habe, entkommen lassen, also nehme ich an, dass es nur Thymeleaf war, das es von der ursprünglichen Zeichenfolge behielt. – yorgo

Verwandte Themen