Od provozovatele projektu Rychlost.CZ
WebDev.wiki > Návody pro webmastery a vývojáře > Díl 4 - načítání nejnovějších příspěvků

Díl 4 - načítání nejnovějších příspěvků - jQuery: Praktická webová aplikace

vydáno: 16.01.2017, seriál: jQuery: Praktická webová aplikace

Toto je 4. díl seriálu jQuery: Praktická webová aplikace, pokud se dostatečně neorientujete, zkuste předchozí díl či díl první.

V předchozím díle jsme dokončili přidávání příspěvků a připravili jsme si REST API server, který již umí i odesílat seznam nejnověji přidaných příspěvků. Pojďme se vrhnout na zobrazování těchto příspěvků v naší aplikaci.

Načítání příspěvků

V části app.stories našeho JavaScriptu v souboru app.js si vytvoříme funkci load(). Tato funkce se bude starat o stažení příspěvků z našeho REST API a o jejich zobrazení na hlavní stránce. Tuto funkci budeme volat:

  • při spuštění aplikace,
  • při přepnutí na hlavní stránku z jiné stránky,
  • periodicky pro zajištění neustálého zobrazení posledních příspěvků, i když je uživatel stále na hlavní stránce.

Funkce app.stories.load() bude také zobrazovat krátké upozornění viditelné pouze v době načítání příspěvků, aby uživatel věděl, že k takové akci dochází.

Začněme nahrazením nezbytného HTML v elementu <div> vyhrazeném pro hlavní stránku (#page-stories):

Ukázka:
HTML
<div id="page-stories" class="page">
<div id="stories-loading" style="display: none;">
<div class="alert alert-info" role="alert">
<strong>Loading stories...</strong>
</div>
</div>
<div id="stories"></div>
</div>
Použité tagy: <div>, <strong>

Celý element #stories-loading je zpočátku schovaný a bude viditelný jen v době načítání příspěvků. Bootstrap CSS třídy alert a alert-info nám nastylují krásné upozorňovací okénko. Jakmile se příspěvky načtou, zobrazíme je všechny v elementu #stories.

Pojďme to celé definovat ve funkci app.stories.load():

Ukázka:
Javascript
// ...
stories: {
start: function()
{
app.stories.load();
},
load: function()
{
$('#stories-loading').show();
$.get('http://mk.e0.cz/s/webdev.wiki/app/posts', function(response)
{
$('#stories').html('');
if (response.length)
{
var html = '';
for (var i in response)
{
html += '<div class="card card-block">';
html += '<h4 class="card-title">' + response[i].author + '\'s story</h4>';
html += '<p class="card-text">' + response[i].text + '</p>';
html += '<p class="card-text"><small class="text-muted">' + new Date(response[i].created * 1000) + '</small></p>';
html += '<a href="#" onclick="app.story.display(' + response[i].id + ')" class="card-link" style="float: right;">Read it all</a>';
html += '</div>';
}
$('#stories').html(html);
}
else
$('#stories').html('No stories! Time to tell yours.');
})
.always(function()
{
$('#stories-loading').hide();
});
}
},
// ...

Relativně dlouhá funkce. Vysvětleme si postupně, co se v ní děje.

První řádek $('#stories-loading').show() zahájí nahrávání příspěvků tím, že zobrazí okénko s textem "Loading stories...". Následně se spustí samotné nahrávání příspěvků, tedy GET dotaz na adresu /posts bez parametrů pomocí jQuery funkce $.get(). Druhým parametrem této funkce je callback funkce, která se spustí v případě, že server odpoví bez chyby. Stane-li se tak, proměnná response bude obsahovat seznam příspěvků jako pole objektů.

Jakmile tedy přijde seznam příspěvků, prvně vymažeme aktuálně zobrazený seznam příspěvků (pokud nějaký existuje) pomocí řádku $('#stories').html(''). Poté nasbíráme celé HTML aktualizovaného seznamu příspěvků, který jsme právě přijali v proměnné response a uložíme celé to HTML do proměnné html. Pro každý příspěvek přidáme do této proměnné html celý její HTML kód, který obsahuje některé zkrášlovací Bootstrap CSS třídy:

card a card-block - zarámují příspěvek do "karty"

card-title - nastyluje titulek "karty"

card-text - nastyluje část obsahu "karty"

text-muted - obecně trochu zašedivuje text

card-link - nastyluje odkaz v "kartě".

Pro každý příspěvek do tohoto HTML vložíme specifický titulek, obsah, datum vytvoření a v odkaze už máme i pro událost kliknutí připravené volání funkce app.story.display(ID), kde ID bude číselný identifikátor příspěvku tak, jak jej máme uložený v databázi.

Cyklus for zařídí, aby se tohle všechno opakovalo pro každý přijatý příspěvek. Jakmile se nashromáždí všechno HTML všech příspěvků do proměnné html, vložíme příspěvky do elementu <div id="stories"> tento obsah a tím pádem příspěvky zobrazíme pomocí řádku $('#stories').html(html).

Pokud nám server vrátil prázdné pole příspěvků (pokud žádný není v databázi), jinými slovy pokud response.length je 0, zobrazíme místo HTML příspěvku jen text "No stories! Time to tell yours.".

V každém případě po dokončení načítání opět schováme okénko s textem "Loading stories..." a to tak, že za $.get() připojíme $.always(callback) a uvnitř její callback funkce zavoláme $('#stories-loading').hide().

Všimněte si také, že ve funkci app.stories.start() máme volání app.stories.load(). Jelikož funkce start() se volá při zobrazení jakékoli stránky, která tu funkci start() má definovanou (toto chování jsme programovali v článku o přepínání stránek). Zařídíme tím, aby se příspěvky načítaly:

  • při přepnutí na stránku stories (například po úspěšném přidání nového příspěvku),
  • při spuštění aplikace, jelikož při spuštění aplikace se automaticky přepne na stránku stories.

Zbývá už jen zařídit, aby se občasně periodicky načítaly příspěvky, pokud uživatel celou dobu jen zírá na hlavní stránku.

Periodická aktualizace příspěvků

Příspěvky na hlavní stránce budeme aktualizovat jednou za 5 minut a použijeme pro to funkci window.setInterval(), která bude jednoduše jednou za 5 minut spouštět funkci app.stories.load(). Takto nastavenou funkci window.setInterval() bude tedy třeba spustit jen jednou a to při spuštění aplikace, ona se pak sama postará o spouštění app.stories.load(). Přidáme ji tedy do funkce spouštějící naši aplikaci app.init():

Ukázka:
Javascript
// ...
init: function()
{
app.goTo('stories');
window.setInterval(app.stories.load, 1000 * 60 * 5);
},
// ...

Funkce window.setInterval(callback, interval) spouští callback funkci jednou za časový interval, který se udává v milisekundách. Pokud jako druhý argument zadáme 1000 milisekund * 60 * 5, bude se callback spouštět jednou za celkem 5 minut.

Rekapitulace

Naše webová aplikace už zvládá přidávání příspěvků a zobrazování posledních příspěvků na hlavní stránce. Příště doděláme poslední plánovanou funkctionalitu - zobrazování celého příspěvku.

Momentálně by celý kód naší aplikace měl vypadat následovně:

Ukázka:
CSS
.page {
display: none;
padding: 24px;
margin-top: 54px;
}
Použité vlastnosti: display, padding, margin-top
Javascript
window.app = {
stories: {
start: function()
{
app.stories.load();
},
load: function()
{
$('#stories-loading').show();
$.get('/posts', function(response)
{
$('#stories').html('');
if (response.length)
{
var html = '';
for (var i in response)
{
html += '<div class="card card-block">';
html += '<h4 class="card-title">' + response[i].author + '\'s story</h4>';
html += '<p class="card-text">' + response[i].text + '</p>';
html += '<p class="card-text"><small class="text-muted">' + new Date(response[i].created * 1000) + '</small></p>';
html += '<a href="#" onclick="app.story.display(' + response[i].id + ')" class="card-link" style="float: right;">Read it all</a>';
html += '</div>';
}
$('#stories').html(html);
}
else
$('#stories').html('No stories! Time to tell yours.');
})
.always(function()
{
$('#stories-loading').hide();
});
}
},
story: {
},
add: {
post: function()
{
var text = $('#add-text');
var author = $('#add-author');
if (text.val() && author.val())
{
$.post('/posts', {text: text.val(), author: author.val()}, function(response)
{
text.val('');
author.val('');
app.goTo('stories');
});
}
else
alert('It is necessary to fill both text and your nickname.');
}
},
init: function()
{
app.goTo('stories');
window.setInterval(app.stories.load, 1000 * 60 * 5);
},
goTo: function(page)
{
if (!app[page])
page = 'stories';
if (page == app.currentPage)
return;
if (app.currentPage)
{
$('#page-'+app.currentPage).fadeOut(250, function()
{
$('#page-'+page).fadeIn(250);
});
}
else
$('#page-'+page).fadeIn(250);
app.currentPage = page;
if (app[page].start)
app[page].start();
$('nav li.active').removeClass('active');
$('nav a[onclick="app.goTo(\'' + page + '\')"]').parent().addClass('active');
}
}
$(document).ready(app.init);
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>The Wall</title>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="screen.css">
</head>
<body>
<nav class="navbar navbar-fixed-top navbar-dark" style="background-color: #0083ff;">
<a class="navbar-brand" href="#">The Wall</a>
<ul class="nav navbar-nav float-xs-right">
<li class="nav-item active">
<a class="nav-link" href="#" onclick="app.goTo('stories')">Stories</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="app.goTo('add')">Add</a>
</li>
</ul>
</nav>
<div id="page-stories" class="page">
<div id="stories-loading" style="display: none;">
<div class="alert alert-info" role="alert">
<strong>Loading stories...</strong>
</div>
</div>
<div id="stories"></div>
</div>
<div id="page-story" class="page">Story detail</div>
<div id="page-add" class="page">
<div class="col-xs-12" style="text-align: center;">
<h1>What's on your mind?</h1>
</div>
<div class="col-xs-12 col-md-6">
<label for="add-text">Your thoughts</label>
<textarea id="add-text" class="form-control" rows="5"></textarea>
</div>
<div class="col-xs-12 col-md-6">
<label for="add-author">Your nickname</label>
<input id="add-author" type="text" class="form-control" maxlength="30">
</div>
<div class="col-xs-12" style="text-align: center; margin: 24px;">
<button class="btn btn-primary" onclick="app.add.post()">Share</button>
</div>
</div>
<script type="text/javascript" src="bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
JavaScript: návody a průvodce
jQuery: návody a průvodce

Seriál jQuery: Praktická webová aplikace

Přejít na následující kapitolu:Díl 5 - detail příspěvku >

Seznam všech článků seriálu: