2015-09-15 15 views
11

Nie wiem, jak rozwiązać następujące problemy: Chciałbym pozwolić, aby mój model dynamicznie generował prawdziwy javascript na podstawie pewnej logiki modelu.Thymeleaf th: inline = "javascript" numer

Ten ostatni fragment kodu javascript należy dodać wewnątrz części $ (document) .ready {} na mojej stronie html.

Chodzi o to: Jeśli używam inline = „javascript”, kod zostanie podane jako moja rodzicielka jest String (czyli jak to jest wymienione w dok Thymeleaf ale to nie to co muszę ;-)

Jeśli używam inline = "text" w nie jest cytowany, ale zamiast tego wszystkie cytaty są zamienione ;-) - również ładne, ale bezużyteczne 8)

Jeśli spróbuję inline = "none" nic się nie dzieje.

Oto przykłady

Mój model getter utworzone następujący kod Javascript.

klasa PageHelper

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')"; 

} 

Więc jeśli teraz spróbować inline = "javascript"

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

będzie renderowany do

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

który nie pomoc, ponieważ jest to litera String l, nic więcej (tak radzi sobie Thymeleaf).

Więc jeśli staram inline = "text" zamiast

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

wydostające cytaty.

inline = „none” I naprawdę nie rozumiem, jak to robi nic

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

Szczerze mówiąc nie mam pojęcia, jak rozwiązać ten problem i mam nadzieję, że ktoś tam wie, jak radzić sobie z to.

Wiele z góry dzięki Cheers John

+0

Zawsze można użyć 'eval()', chociaż zdecydowanie nie jest to najładniejsze rozwiązanie. – Kejml

+0

Hi Kejml. Dzięki za szybką pomoc. I rzeczywiście eval() działa ;-) Co za brudny hack. Musiałem google eval(), którego zdecydowanie nie mogłem sobie przypomnieć, ale na końcu mój 'inline =" javascript "w połączeniu z' eval ([[$ {pageHelper.documentReady}]]) naprawdę dobrze się sprawdził. Chociaż chciałbym, aby ta kwestia pozostała bezładna przez chwilę, aby zobaczyć, czy istnieje "oficjalny" sposób Thymeleaf tego. W każdym razie. Wielkie dzięki jeszcze raz. Twoje zdrowie. Jan. –

+0

Jasne, nie sądzę, że jest to właściwy sposób na zrobienie tego, dlatego opublikowałem to jako komentarz, a nie jako odpowiedź, ale przynajmniej to może pomóc. Mam nadzieję, że ktoś przyjdzie z poprawną odpowiedzią. Pozdrawiam :) – Kejml

Odpowiedz

10

Chciałbym zmienić podejście. Thymeleaf pozwala łatwo dodawać zmienne modelowe do twoich szablonów do użycia w JavaScript. W moich implementacjach zwykle umieszczam te zmienne gdzieś przed zamykającym tagiem nagłówka; aby upewnić się, że są na stronie po załadowaniu WS. Pozwoliłem szablonowi zdecydować, co dokładnie załadować, oczywiście. Jeśli wyświetlasz galerię, wyrenderuj ją tak, jak chcesz i użyj atrybutów danych, aby zdefiniować galerię powiązaną z pewnym kodem JS. Następnie napisz sobie miłe jQuery plugin do obsługi swojej galerii.

Stosunkowo prosty przykład:

Układ domyślny Dekorator: Układ/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> 

Należy zwrócić uwagę na ogólne skrypty stopki, a następnie na układ: zdefiniowany fragment div. Ten layout div jest tym, czego użyjemy do włączenia naszej wtyczki jquery potrzebnej do galerii.

plików ze skryptami ogólnych: fragmenty/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> 

W skryptach pliku, są 2 fragmenty, które są zawarte od dekoratora. W fragmencie nagłówka użyta jest pomocna ścieżka kontekstu dla warstwy JS, a także domyślna metoda dla samego piekła. Obiekt galerii jest następnie definiowany i przypisywany z naszego modelu. Fragment stopki ładuje bibliotekę jQuery i plik JS głównej witryny, ponownie dla celów tego przykładu.

Strona z leniwym załadowane galerii: 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> 

Strona produkty nie ma zbyt wiele na jej temat. Korzystając z domyślnego dekoratora, ta strona zastępuje tytuł strony w nagłówku. Nasz fragment treści zawiera tytuł w znaczniku h1 i pusty element div z atrybutem galerii danych. Ten atrybut jest użyty w naszej wtyczce jQuery do zainicjowania galerii. Wartość jest ustawiona na lazyload, więc nasza wtyczka wie, że musimy znaleźć identyfikatory obrazów w niektórych zmiennych zestaw gdzieś. Mogło to być łatwo puste, jeśli jedyną rzeczą, którą obsługuje nasza wtyczka, jest galeria z leniwymi załadowaniami.

Tak więc układ ładuje niektóre domyślne skrypty i sprytnie rozmieszczony układ: fragmenty, pozwalasz niektórym sekcjom strony ładować biblioteki niezależne od reszty.

Oto prosty przykład kontroler Wiosna, aby pracować z naszej aplikacji: 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"; 
    } 
} 

Klasa Galeria została rzucił inline w metodzie produktów, w celu uproszczenia naszego przykładu tutaj. Może to być usługa lub repozytorium jakiegoś typu, które zwraca tablicę identyfikatorów lub cokolwiek, czego potrzebujesz.

Nasz jQuery plugin, który stworzyliśmy, mógłby wyglądać tak: 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)); 

Ostateczne renderowanie strony produktów będzie wyglądać tak:

<!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> 

Jak widać , Thymeleaf robi całkiem niezłą robotę, tłumacząc twój model na poprawny JS i dodaje cytaty tam, gdzie jest to potrzebne, i ucieka im również. Po zakończeniu renderowania strony, z wtyczką jQuery na końcu pliku, wszystko, co potrzebne do zainicjowania galerii, powinno być załadowane i gotowe do pracy.

To jest , a nie idealny przykład, ale uważam, że jest to całkiem prosty wzór dla aplikacji internetowej.

+0

Cześć Yorgo, dzięki za wspaniałe wyjaśnienie. Wygląda na to, że naprawdę muszę zmienić moje podejście, tak jak proponowałeś. Podejrzewałem to już po tym, jak Kejml i Hossein też to potwierdzili. Dziękuję wszystkim. Pozdrawiam Johna –

+0

Spodziewałbym się, że nie ma odwrotnego ukośnika przed podwójnym cudzysłowem w html. Dlaczego Thymeleaf uciekłby od podwójnego cudzysłowu, gdy nie jest naprawdę potrzebny. – T3rm1

+0

Dobre pytanie T3rm1. Nie przypominam sobie, w jaki sposób otrzymałem ostateczną wersję ... najprawdopodobniej źródło widoku, kopiuj/wklej. Kazałem im uciec w kontrolerze próbek, który zawarłem, więc zakładam, że to właśnie Thymeleaf zachował go z oryginalnego napisu. – yorgo