Od provozovatele projektu Rychlost.CZ
WebDev.wiki > Návody pro webmastery a vývojáře > Díl 3 - přidávání příspěvků

Díl 3 - přidávání příspěvků - jQuery: Praktická webová aplikace

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

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

V minulých dílech už jsme zvládli udělat, aby naše webová aplikace byla schopna přepínat mezi jejími stránkami s krásným efektem. Je na čase dát jí nějakou užitečnou funkcionalitu. Začneme přidáváním příspěvků.

Serverová část

Cílem tohoto seriálu není zabývat se serverovou částí naší aplikace, nicméně pro úplnou představu a možnost si aplikaci prakticky vyzkoušet je nezbytné, abychom si řekli, jak bude fungovat serverová strana. Vycházíme z toho, že na našem serveru, jako na většině webových serverů, běží PHP a MySQL.

Struktura databáze

Naše MySQL databáze bude obsahovat pouze jednu tabulku a to tabulku příspěvků, pojmenujme ji třeba posts a dejme ji 4 sloupečky: ID, autor, text a čas vytvoření. Stačí na MySQL serveru vybrat vaši nově vytvořenou databázi pro účely naší webové aplikace a provézt v ní následující SQL kód, který se postará o tvorbu tabulky:

CREATE TABLE `posts` (
`id` int(11) NOT NULL,
`text` text NOT NULL,
`author` varchar(30) NOT NULL,
`created` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
ALTER TABLE `posts` ADD PRIMARY KEY (`id`);
ALTER TABLE `posts` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

PHP Skript

Dále si vytvoříme PHP skript ve stylu REST API, který bude odpovídat na AJAX dotazy naší webové aplikace. Tento skript bude obstarávat 3 typy dotazů:

  • Ukládání nových příspěvků.
  • Načtení seznamu posledních příspěvků se zkráceným textem.
  • Načtení celého textu vybraného příspěvku.

Následující PHP kód si uložíme do souboru, který pojmenujeme index.php. Je velmi jednoduchý a bude fungovat jako naše REST API. Přidáme k němu ještě soubor s názvem .htaccess s ještě níže uvedeným obsahem. Oba soubory si je nahrajte na váš Apache web server a nezapomeňte v index.php nastavit správné přístupové údaje k MySQL databázi.

Ukázka:
<?php
ini_set('display_errors', 1);
ini_set('error_reporting', 'E_ALL');
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
// Change DB access credentials here
$dbConnection = new MySQLi('localhost', 'your user', 'your password', 'your database name');
$dbConnection->set_charset('utf8');
//
// main switch, every request is then handled by individual functions
switch($_REQUEST['action'])
{
case 'posts':
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
if(isset($_REQUEST['text']) && isset($_REQUEST['author']))
addPost($_REQUEST['text'], $_REQUEST['author']);
else
error(422, "Both 'text' and 'author' parameters are required.");
}
if($_SERVER['REQUEST_METHOD'] == 'GET')
{
if(isset($_REQUEST['id']))
getPost($_REQUEST['id']);
else
listLatestPosts(30);
}
break;
default:
error(400, 'Unknown action.');
break;
}
// helper output function
function output($response)
{
http_response_code(200);
print json_encode($response);
}
// helper error function
function error($status, $message)
{
http_response_code($status);
print json_encode(array('message' => $message));
}
// function handling adding posts
function addPost($text, $author)
{
global $dbConnection;
$text = $dbConnection->real_escape_string($text);
$author = $dbConnection->real_escape_string($author);
$sql = "INSERT INTO `webdevwiki`.`posts` (`id`, `text`, `author`, `created`) VALUES(NULL, '{$text}', '{$author}', UNIX_TIMESTAMP());";
$result = $dbConnection->query($sql);
if($result)
output('');
else
error(500, $dbConnection->error);
}
// function returning latest posts
function listLatestPosts($amount)
{
global $dbConnection;
$amount = $dbConnection->real_escape_string($amount);
$sql = "SELECT * FROM `posts` ORDER BY `created` DESC LIMIT {$amount}";
$result = $dbConnection->query($sql);
if($result)
{
if($result->num_rows > 0)
{
$posts = array();
while(($post = $result->fetch_object()) != null)
{
$post = array(
'id' => $post->id,
'text' => substr($post->text, 0, 100).'...',
'author' => $post->author,
'created' => $post->created
);
$posts[] = $post;
}
output($posts);
}
else
error(404, 'There are no posts.');
}
else
error(500, $dbConnection->error);
}
// function returning a post's detail
function getPost($id)
{
global $dbConnection;
$id = $dbConnection->real_escape_string($id);
$sql = "SELECT * FROM `posts` WHERE `id` = {$id}";
$result = $dbConnection->query($sql);
if($result)
{
if($result->num_rows > 0)
{
$post = $result->fetch_object();
$post = array(
'id' => $post->id,
'text' => $post->text,
'author' => $post->author,
'created' => $post->created
);
output($post);
}
else
error(404, "This post({$id}) does not exist.");
}
else
error(500, $dbConnection->error);
}

Soubor .htaccess bude obsahovat:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ([^\/]+$) index.php?action=$1 [QSA,L]
</IfModule>

API

Řekněme, že jste si oba zmíněné soubory nahráli do vašeho webového serveru, například na adresu http://vašedoména/api/ nebo http://localhost/jqueryapp/. O této vaší adrese se nyní budeme bavit jako o adrese /, ale budeme mít vždy na mysli celou adresu, tedy například /posts by u vás mohlo být například http://localhost/jqueryapp/posts.

Náš předpřipravený REST API skript nám teď dává k dispozici 3 operace:

  • Pokud nyní vytvoříme GET dotaz na server bez parametru id na adresu /posts, server nám odpoví seznamem posledních příspěvků a jejich texty budou zkráceny na 100 znaků.
  • Pokud vytvoříme GET dotaz na server s parametrem id na adresu /posts, server nám odpoví detailem jednoho příspěvku s kompletním textem.
  • Pokud vytvoříme POST dotaz na server s parametry text a author na adresu /posts, server přidá do databáze nový příspěvek.

V budoucnu bychom mohli samozřejmě do našeho REST API serveru přidávat další aspekty naší aplikace. Pokud bychom například chtěli pracovat s uživateli, vyhradili bychom si pro ten účel adresu /users nebo pokud bychom chtěli mít u příspěvků tagy/štítky, bylo by vhodné s nimi pracovat na adrese /tags. Ale nyní už máme vše připravené k tomu, abychom v naší webové aplikaci mohli implementovat přidávání příspěvků.

Formulář příspěvků

V souboru index.html si najdeme <div> určený pro stránku přidávání příspěvku (#page-add) a změníme jeho obsah tak, aby vypadal následovně:

Ukázka:
HTML
<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>

Máme zde opět několik Bootstrap CSS tříd, které nám značně usnadňují práci a zkrášlují naši aplikaci:

col-xs-12 - na malých obrazovkách (na mobilech) roztáhne daný element (a jeho obsah) na celou šířku.

col-xs-12 col-md-6 - na malých obrazovkách (na mobilech) roztáhne daný element (a jeho obsah) na celou šířku, na středně velkých obrazovkách a větích na polovinu šířky obrazovky.

form-control - zkrášlí a zlepší vstupní pole

btn btn-primary - zkrášlí tlačítko

Pokud nyní v naší webové aplikaci v menu liště klikneme na odkaz Add, zobrazí se nám stránka s formulářem pro přidání příspěvku. Pojďme udělat poslední nezbytnou věc k tomu, aby celé přidávání příspěvků fungovalo.

Funkce na přidávání příspěvků

Jak jste si pravděpodobně všimli, připravili jsme si při kliknutí na tlačítko Share volání funkce app.add.post(). Tato funkce dosud neexistuje, je čas ji vytvořit v našem JavaScriptovém souboru app.js v části app.add:

Ukázka:
Javascript
// ...
add: {
post: function()
{
}
},
// ...

Funkce post() se spustí při kliknutí na tlačítko Share. Nejdříve v ní zjistíme, jestli uživatel zadal jak příspěvek, tak svoji přezdívku. Následně vytvoříme POST dotaz na náš REST API server s parametry text a author, které uživatel zadal. Při úspěšném odeslání příspěvku vyčistíme políčka formuláře a přesměrujeme uživatele na seznam příspěvků, kde později uvidí svůj příspěvek.

Ukázka:
Javascript
// ...
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.');
}
},
// ...

Nezapomeňte změnit adresu /post na celou adresu k vašemu REST API serveru.

Rekapitulace

Tímto máme přidávání příspěvků hotové. Zda-li vše funguje jak má si můžete jednoduše zkontrolovat náhledem do databáze.

Příště zajistíme, aby se na hlavní stránce naší webové aplikace zobrazovaly poslední přidané příspěvky.

Celý kód naší aplikace by nyní 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()
{
console.log('Stories');
}
},
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');
},
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">Latest stories</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