Vícenásobné rychlé stisknutí tlačítka Enter způsobí opakované spuštění kódu formuláře
- Karel Chramosil
- Člen | 114
Dobrý den,
(NetteFramework-2.0.10-PHP5.3)
mám jednoduchý formulář pro určení slevy pro každý desátý produkt,
který je označen kódem. Při zadání kódu se insertem uloží kód do
tabulky karta. Mám problém, že po rychlém stisknutí tlačítka Enter se
kód uloží několikrát a né jednou, ale podle počtu stisknutí. Opakované
stisknutí tlačítka Enter může realizovat snadno obsluha programu. Prosím
o radu jak zajistit pro jeden zadaný kód jedno uložení dat.
<?php
use Nette\Application\UI\Form;
use Nette\Security as NS;
/**
* SkladList presenter.
*
* @author Karel Chramosil
* @package Sleva
* Presenter, který zajišťuje evidenci kódů z tabulky karta.
*/
class KartaListPresenter extends SecuredPresenter
{
public $SLEVAPOCET = 10;
public function actionDefault($sLike)
{
// nechci vypsat žádný řádek
//$this->template->skartas = $this->context->createKartas()->order('datum_zapsal ASC')->limit(10);
$pocetkodu = $this->context->createKartas()->where('kod LIKE ?', $sLike)->count('*');
$offset = $pocetkodu - $this->SLEVAPOCET;
if ($offset < 0) $offset = 0;
$this->template->skartas = $this->context->createKartas()->
where('kod LIKE ?', $sLike)->order('id ASC')->
limit($this->SLEVAPOCET,$offset );
}
protected function createComponentEditaceForm()
{
$form = new Form();
$form->addText('kod', 'Kód slevy:', 15, 15)
->setDefaultValue('');
$form->addSubmit('set', 'Ulož');
$form->onSuccess[] = callback($this, 'editaceFormSubmitted');
return $form;
}
public function editaceFormSubmitted(Form $form)
{
$values = $form->getValues();
$user = $this->getUser();
$strKod = $values->kod;
if (($values == NULL ) OR ($strKod === '')) {
// nechci vypsat žádný řádek
$this->template->skartas = $this->context->createKartas()->order('datum_zapsal ASC')->limit(0);
} else {
try {
// potřebuji, aby po stisknutí rychle 3x enter se provedl izert jen jednou
$this->context->createKartas()->insert(array(
'kod'=>$values->kod,
'remonte_host'=> $_SERVER['REMOTE_ADDR'],
'remonte_port'=> $_SERVER['REMOTE_PORT'],
'zakazan'=>0,
'user_id'=>$user->id,
'datum_zapsal'=>new DateTime()
));
//$this->flashMessage('Flag enter = '.$this->flegEnter , 'success');
$strKodLike = '%'.$strKod.'%';
$maxid = $pocetkodu = $this->context->createKartas()->where('kod LIKE ?', $strKodLike)->max('id');
$pocetkodu = $this->context->createKartas()->where('kod LIKE ?', $strKodLike)->count('*');
$sleva = $pocetkodu % $this->SLEVAPOCET; // každý desátý je sleva
// echo $sleva;
if ($sleva == 0) { //je sleva
$this->context->createKartas()->where('id = ?', $maxid)->update(array(
'datum_slevy'=>new DateTime(),
));
$this->flashMessage('Občan má nárok na slevu', 'success');
} else { //není sleva
}
$this->redirect('KartaList:',$strKodLike);
} catch (PDOException $e) {
$form->addError('Zadaný řetězec není správný.');
}
}
}
}
{var $title = 'Zadání kódu'}
{block content}
{form editaceForm}
<div class="editace-form">
{control $form errors}
<div class="pair">
{label kod /}
<div class="input">{input kod, autofocus => TRUE} </div>
<br>
<div class="pair">
<div class="input">{input set}</div>
</div>
{/form}
<table>
<thead>
<tr>
<th>Kód</th>
<th>Oběd datum</th>
<th>Sleva datum</th>
<th>Host</th>
<th>Port</th>
<th>Zapsal</th>
</tr>
</thead>
<tbody>
{foreach $skartas as $skarta}
{? $userRow = $skarta->ref('user')}
<tr class="odd">
<td>{$skarta->kod}</td>
<td>{$skarta->datum_zapsal|date:'j. n. Y'}</td>
<td>{$skarta->datum_slevy|date:'j. n. Y'}</td>
<td>{$skarta->remonte_host}</td>
<td>{$skarta->remonte_port}</td>
<td>{$userRow->prijmeni}</td>
</tr>
{/foreach}
</tbody>
</table>
{/block}
Děkuji za radu.
- Karel Chramosil
- Člen | 114
Jan Tvrdík napsal(a):
Nejsnáze asi JS zablokovat ty opakovaná odeslání.
Přiznám se že JS moc neovládám. Opakované stisknutí Enter je obecnější problém, protože jsem zkoušel jiní formulář na tabletu a tam k opakovanému stisknutí tlačítka odeslat může nastat velice snadno.
- Tomáš Kolinger
- Člen | 136
Přidat do tabulky sloupec time, kde budeš ukládat čas v sekundách – unix time. Potom vytvořit unikátní klíč nad časem a uživatelem – user_id.
Takže ti sama databáze ošetří, že uživatel může získat kód jednou za vteřinu, což ti vůbec nevadí a v případě „rychlého entru“ vyhodí databáze exception, kterou můžeš chytit a říct uživateli, že už slevu dostal.
Přes JS by to taky šlo ale když si vypnu JS, tak je bug zpátky.
Editoval Tomáš Kolinger (15. 3. 2014 20:11)
- Karel Chramosil
- Člen | 114
Dobrý nápad, ale formulář vesele počká na databázi. Nebo mám někde chybu.
CREATE TABLE IF NOT EXISTS karta
(
id
int(11) NOT NULL AUTO_INCREMENT,
kod
varchar(15) COLLATE utf8_czech_ci NOT NULL,
datum_slevy
date DEFAULT NULL,
remonte_host
varchar(30) COLLATE utf8_czech_ci DEFAULT NULL,
remonte_port
int(11) DEFAULT NULL,
zakazan
tinyint(1) DEFAULT ‚0‘,
user_id
int(11) NOT NULL DEFAULT ‚1‘,
time_zapsal
time DEFAULT NULL,
datum_zapsal
date NOT NULL,
PRIMARY KEY (id
),
UNIQUE KEY user_id
(user_id
,time_zapsal
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci
AUTO_INCREMENT=367 ;
Řeším dotaz, který odpoví nějakým příznakem, že neuběhlo 20 s. Zatím neúspěšně.
$timemaxids = $this->context->createKartas()->where('id = ?', $maxid)->where('time_zapsal + "00:00:20" < ?', new DateTime ); //Další
- Tomáš Kolinger
- Člen | 136
Používáš špatný formát pro ten sloupec time. Musí to být unix time. Tj. počet vteřin od roku 1970… Klidně tam dej bigint(40) a hodnotu získáš pomocí PHP funkce time().
K čemu potřebuješ ten dotaz? Pokud se stane, že uživatel odešle formulář vícekrát, tak se při druhém zápisu vyhodí výjimka a data se do databáze neuloží. Tudíž nemusíš řešit tohle v PHP, protože to za tebe udělá databáze.
- Karel Chramosil
- Člen | 114
Díky za radu, ale řešení jsem nenašel. Po třech stisknutí Enter se kód třikrát uložil po vteřině.
Kód Oběd datum Oběd čas Sleva datum Host Port Zapsal
ab 16. 3. 2014 02. 54. 47 10.0.0.200 54316 Chramosil
ab 16. 3. 2014 02. 55. 04 10.0.0.200 54325 Chramosil
ab 16. 3. 2014 02. 55. 05 10.0.0.200 54327 Chramosil
ab 16. 3. 2014 02. 55. 07 10.0.0.200 54328 Chramosil
CREATE TABLE IF NOT EXISTS karta
(
id
int(11) NOT NULL AUTO_INCREMENT,
kod
varchar(15) COLLATE utf8_czech_ci NOT NULL,
datum_slevy
date DEFAULT NULL,
remonte_host
varchar(30) COLLATE utf8_czech_ci DEFAULT NULL,
remonte_port
int(11) DEFAULT NULL,
zakazan
tinyint(1) DEFAULT ‚0‘,
user_id
int(11) NOT NULL DEFAULT ‚1‘,
time_zapsal
bigint(40) DEFAULT NULL,
datum_zapsal
date NOT NULL,
PRIMARY KEY (id
),
UNIQUE KEY user_id
(user_id
,time_zapsal
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci
AUTO_INCREMENT=386 ;
try {
if (TRUE) {
$this->context->createKartas()->insert(array(
'kod'=>$values->kod,
'remonte_host'=> $_SERVER['REMOTE_ADDR'],
'remonte_port'=> $_SERVER['REMOTE_PORT'],
'zakazan'=>0,
'user_id'=>$user->id,
'time_zapsal'=> time(),
'datum_zapsal'=>new DateTime()
));
}
//$this->flashMessage('Flag enter = '.$this->flegEnter , 'success');
$maxid = $this->context->createKartas()->where('kod LIKE ?', $strKodLike)->max('id');
$pocetkodu = $this->context->createKartas()->where('kod LIKE ?', $strKodLike)->count('*');
$sleva = $pocetkodu % $this->SLEVAPOCET; // každý desátý je sleva
// echo $sleva;
if ($sleva == 0) { //je sleva
$this->context->createKartas()->where('id = ?', $maxid)->update(array(
'datum_slevy'=>new DateTime(),
));
$this->flashMessage('Občan má nárok na slevu', 'success');
} else { //není sleva
}
$this->redirect('KartaList:',$strKodLike);
} catch (PDOException $e) {
$form->addError('Zadaný řetězec se neuložil.');
}
- Karel Chramosil
- Člen | 114
Díky za pomoc. Nakonec pomohlo zpoždění 4 vteřiny.
// potřebuji, aby po stisknutí rychle 3x enter se provedl izert jen jednou
$maxid = $this->context->createKartas()->where('kod LIKE ?', $strKodLike)->max('id'); //Poslední id kódu.
$timemaxids = $this->context->createKartas()->where('id = ?', $maxid)->where('time_zapsal + 4 < ?', time()); //Další záznam až po 4 vteřinách
$flegEnter = FALSE;
foreach($timemaxids as $timemaxid) {
if ($timemaxid->time_zapsal > 0) {
$flegEnter = TRUE;
//$this->flashMessage('Kód se zapíše. Time_zapsal maxid = '.$timemaxid->time_zapsal , 'success');
}
}
if ($flegEnter == FALSE) {
//$this->flashMessage('Kód nebyl uložen!!!', 'success');
}
if ($flegEnter == TRUE) {
$this->context->createKartas()->insert(array(
'kod'=>$values->kod,
'remonte_host'=> $_SERVER['REMOTE_ADDR'],
'remonte_port'=> $_SERVER['REMOTE_PORT'],
'zakazan'=>0,
'user_id'=>$user->id,
'time_zapsal'=> time(),
'datum_zapsal'=>new DateTime()
));
}