Użycie Mustache JS na przykładzie aplikacji Express. Część 1/2.

mustache-js

Poziom zaawansowany

Dziś stworzymy aplikację Web w oparciu o wspaniałe narzędzia – html5, Bootstrap, jQuery, Mustache JS i Express. Krok po kroku. Użyjemy także ionicons do wyświetlenia ikon.

Mustache JS

Nie każdy (w tym ja) przepada za systemami szablonów np. w PHP. Tutaj jednak sprawa wygląda znacznie inaczej. Mustache JS to implementacja dla języka JavaScript mini-engine szablonów Mustache (logic-less), który powstał dla wielu różnych języków programowania: http://mustache.github.io.

Dlaczego Mustache (i podobne biblioteki) są fajne?

Przede wszystkim mając dane np. pochodzące z obiektów JSON, nie musimy przetwarzać ich ręcznie, co bywa żmudne. Zamiast tego definiujemy niewielki szablon i placeholdery, w których Mustache JS dokona interpolacji. W ten sposób otrzymamy od razu dane zintegrowane z warstwą front-end naszego projektu.

Mając opanowane Mustache JS, oszczędzamy cenny czas i wysiłek. Za chwilę zobaczymy to w praktyce.

Wydawnictwo Strefa Kursów

Nauka Mustache JS

Warto zacząć od szybkiego wprowadzenia do pracy z tą biblioteką.

1. Szablon definiujemy jak w poniższym przykładzie:

...
<body onload="loadUser()">
<div id="target">Loading...</div>

<script id="template" type="x-tmpl-mustache">
Hello {{ name }}!
</script>

</body>

2. Kod JS, który uruchomi magię Mustache:

function loadUser() {
  var template = $('#template').html();
  Mustache.parse(template); // optional, speeds up future uses
  var rendered = Mustache.render(template, {name: "Luke"});
  $('#target').html(rendered);
}

Dodatkowy, mały tutorial na Tutsplus:

http://code.tutsplus.com/tutorials/using-the-mustache-template-library–net-14590

Samą bibliotekę z prostą dokumentacją znajdziemy na stronie GitHub projektu:

https://github.com/janl/mustache.js

Mustache JS jest proste, wręcz przyjemne w użyciu, a potrafi znacząco pomóc programiście.

W praktyce – piszemy małą aplikację web

Będzie to mała aplikacja node.js (express) z frontem single page app.

Projekt miał kilka założeń:

Aplikacja on-line do zamawiania jedzenia (pizza, drinks)

– wyświetlanie menu w przejrzysty sposób

– cart – możliwość dodania różnych produktów do koszyka

– każda pizza ma nazwę, cenę, opis i obrazek, napoje zamiast opisu mają typ (soda, beer, rum)

– prosta logika walidacji ceny:

– jeśli użytkownik zamawia tylko napoje, minimalna cena musi wynosić 10 EUR

– jeśli tylko pizza, minimum 30 EUR

– jeśli zarówno jedzenie i napoje – nie ma ceny minimalnej

– użytkownik może podać swoje dane i kliknąć Zamów, aplikacja wyśle zamówienie do serwera (node.js) lub wyświetli komunikat, gdy cena wybranych produktów jest za niska.


Od strony technicznej:

– jQuery (i dowolny plugin, jeśli będzie potrzebny)

– HTML5, Bootstrap

– działanie min. w przeglądarkach FF, Chrome, IE oraz na urządzeniach mobilnych.

Zacznijmy od przygotowania testowych danych wejściowych (jedzenie i napoje)

Dane mogą pochodzić z zewnętrznego źródła w postaci JSON, z API, lub po prostu pobrane z bazy danych i zwrócone via AJAX. Dla uproszczenia, w przykładzie trzymamy je jako tablice obiektów w zewnętrznym pliku JS, który zostanie odczytany przez nasz prosty serwer napisany w node.js:


// pizzas
var pizzaList = [
    {
        name: "Margherita",
        price: 20.99,
        details: "Lorem ipsum",
        img: "img/pizza.jpg"
    },
    {
        name: "Salami",
        price: 24,
        details: "Dolor sit amet",
        img: "img/pizza.jpg"
    },
    {
        name: "Pizza Super Good, with a long name",
        price: 44,
        details: "Great pizza with extra cheese, corn and bacon",
        img: "img/pizza.jpg"
    },
    {
        name: "Pepperoni",
        price: 20,
        details: "Lorem ipsum Pepperoni",
        img: "img/pizza.jpg"
    }
];

// drinks
var drinkList = [
    {
        name: "Coca-Cola",
        price: 5,
        type: "Soda",
        img: "img/soda.jpg"
    },
    {
        name: "Sprite",
        price: 6,
        type: "Soda",
        img: "img/soda.jpg"
    },
    {
        name: "Pilsner X",
        price: 6.2,
        type: "Beer",
        img: "img/beer.jpg"
    },

...  

    {
        name: "Captain Morgan",
        price: 7.75,
        type: "Rum",
        img: "img/rum.jpg"
    }
];

// group drinks by type, to display them grouped in "categories"
var drinkListByType = {};

for (var i = 0; i < drinkList.length; ++i) {
    var obj = drinkList[i];

    // create the "type key" if missing
    if (drinkListByType[obj.type] === undefined) {
        drinkListByType[obj.type] = [obj.type];
    }

    // pack the rest of the data to temporary object
    var tmp = {
        name: obj.name,
        price: obj.price,
        img: obj.img
    };

    drinkListByType[obj.type].push(tmp);
}

data = {
    pizzaList: pizzaList,
    drinkList: drinkList,
    drinkListByType: drinkListByType
};

module.exports = data;

Warto zwrócić uwagę na kod grupujący drinki w kategorie po parametrze „type”.

Pełny plik tutaj:

https://github.com/dominik-w/express-food-app/blob/master/data.js

Kolejny krok – aplikacja node.js (express)

Najpierw wczytanie potrzebnych modułów oraz zasobów (katalog public/):

var express = require('express');
var app = express();
var path = require('path');
var bodyParser = require('body-parser');

// assets
app.use(express.static(__dirname + '/public'));

// to process post requests
app.use(bodyParser.json());

Moduł bodyParser przyda się do bezbolesnej obsługi żądań typu POST.

W dalszej części kodu następuje wczytanie danych, które uprzednio zdefiniowaliśmy:


// load input test-data
var data = require('./data.js');
var pizzaList = data.pizzaList;
var drinkList = data.drinkListByType;
//console.log(pizzaList); console.log("\n"); console.log(drinkList);

Pora na routes – strona główna oraz podstrony:


// main - at http://localhost:8080
app.get('/', function (req, res) {
    res.sendFile(path.join(__dirname + '/index.html'));
});

// app routes
app.get('/pizzas/', function (req, res) {

    // adding some more pizzas
    var localList = pizzaList.slice(0);
    for (var i = 0; i < 30; i++) {
        localList.push({
            name: "Generic Pizza" + (i + 1),
            price: 30 + i,
            details: "Lorem ipsum " + (i + 1),
            img: "img/pizza.jpg"
        });
    }

    res.json(localList);
});

app.get('/drinks/', function (req, res) {
    res.json(drinkList);
});

W przypadku /pizzas/ dodaliśmy prosty kod, który w pętli generuje więcej danych testowych.

Na końcu definiujemy akcję submit (POST) oraz start serwera na porcie 8080:


// submit process
app.post('/submit', function (req, res) {

    // simply show order data; we can save them in DB,
    // send via API to our pizzeria or whatever we need
    console.log("New order:\n");
    console.log(req.body);

    res.json({msg: 'Success'});
});

// start the server 
app.listen(8080);

Obsługa wysłanego zamówienia, która następuje w akcji submit, ogranicza się do wyświetlenia każdego przychodzącego zamówienia w konsoli. W realnej aplikacji możemy zaimplementować tutaj zapisywanie danych w bazie, lub wysyłanie ich via API do pizzerii. Cokolwiek potrzeba 🙂

I tym samym nasz serwer jest gotowy, jednak nie startujmy go jeszcze. Potrzeba jeszcze index.html – strony, którą zaserwujemy.

Tym zajmiemy się już w części II.

Zapraszam!

Programista WWW i aplikacji mobilnych z wieloletnim doświadczeniem. Bloger 🙂 Anty-lewak 🙂 Pasjonat programowania, nowych technologii, a także sportu i motoryzacji.

Twitter LinkedIn Google+ Skype Xing 

Podaj dalej: Share on Facebook1Tweet about this on TwitterShare on Google+0Share on LinkedIn0Share on Tumblr0Digg thisEmail this to someonePin on Pinterest1
Możesz skomentować leave a response, lub podać trackback z własnej strony.