Jak renderovat snippety na cizích webech?
- Chuchy
- Člen | 77
Ahoj,
už jsem bezradný, tak se obrací na forum.
mám přes nette vygenerované formuláře, který vkládám na cizí weby zhruba takto
<script src="http://forms.local:8888/api/form-js/?hash=1bdc342cf4bea96018a0274d7c2b1f80"></script>
Formulář se mi vždycky na webu vykreslí, fungují i js a validace, dokonce se mi formulář podaří i odeslat a uložit, nicméně problém nastává při překreslení snippetů, ke kterému vůbec nedojde a ajax response mi vrátí již vyrenderovanou stránku.
Takhle vypadá můj presenter, na který se formuláře odkazují
public function startup()
{
parent::startup();
Debugger::$showBar = false;
Debugger::$productionMode = false;
$httpResponse = $this->getHttpResponse();
$httpResponse->addHeader("Access-Control-Allow-Origin", "*");
}
Vytvoření formuláře
/**
* @return FormControl
* @throws InvalidLinkException
*/
public function createComponentFormControl(): FormControl
{
$formControl = $this->formControl;
$formControl->setFormLink($this->createLinkToForm($this->formForm->getHash()));
$formControl->setFormForm($this->formForm);
$formControl->setDefaultValues((array)$this->sessionSection->default);
$formControl->onSuccessForm[] = function (Form $form) {
$this->showForm = true;
$values = $form->getHttpData(1);
$this->formService->saveFormForm($values, $this->formForm);
$this->sessionSection->limit--;
$this->sessionSection->default = $this->formService->deleteFileValues($values, $this->formForm);
$this->flashMessage("Formulář byl odeslán!");
$this->redrawControl("formFormSnippet");
$this->redrawControl("flash");
};
$formControl->onErrorForm[] = function (Form $form) {
$this->submittedFormErrors($form);
$this->redrawControl("formFormSnippet");
$this->redrawControl("flash");
};
return $formControl;
}
a latte
{snippet flash}
<div class="m-section m-section--c-gray">
<div class="container">
<div n:foreach="$flashes as $flash" class="alert alert-{$flash->type}">
{$flash->message}
</div>
</div>
</div>
{/snippet}
{snippet formFormSnippet}
{control formControl}
{/snippet}
Pro odesílání používám klasický nette.ajax.js
Editoval Chuchy (9. 9. 2019 9:08)
- Chuchy
- Člen | 77
1, formulář renderuji přes takovou prasárnu, která mi byla doporučená
public function renderJsData(string $hash)
{
$htmlFile = file_get_contents($this->createLinkToForm($hash));
foreach (explode("\n", $htmlFile) as $row) {
echo "document.write('" . str_replace("'", "\'", $row) . "');";
echo "\r\n";
}
$this->terminate();
}
2, v konzoli nejsou žádné chyby
console
console2
3, není, mám to zatím na localu
Editoval Chuchy (9. 9. 2019 9:29)
- Chuchy
- Člen | 77
Tak to už trošku vím, spíš nevím, jak tomu „podstrčit“, že se jedná o ajax. Myslím si, že bych měl ještě něco přidat do hlavičky requestu, aby nette vědělo, že se jedná o ajax, aby mohlo poslat json response
předpokládám, že bude potřeba nastavit/vypnout JSON-P v odesílání ajaxu, ale u nette.ajax.js to jde?
Editoval Chuchy (9. 9. 2019 10:32)
- CZechBoY
- Člen | 3608
Stačí se podívat jak Nette zjišťuje, že se jedná o ajax http
požadavek:
https://github.com/…/Request.php#L253
- Chuchy
- Člen | 77
CZechBoY napsal(a):
Stačí se podívat jak Nette zjišťuje, že se jedná o ajax http požadavek:
https://github.com/…/Request.php#L253
Nejedná, jelikož to vrací false, nicméně to, ale stále posílám přes „ajax“ a to by mělo i na straně serveru poznat, že to přes něj posílám? takže musím asi upravit nějak hlavičky nette.ajax?
- Chuchy
- Člen | 77
Tohle to vrací při použítí třídy ajax na formuláři
to vytváření už jsem posílal
/**
* @return FormControl
* @throws InvalidLinkException
*/
public function createComponentFormControl(): FormControl
{
$formControl = $this->formControl;
$formControl->setFormLink($this->createLinkToForm($this->formForm->getHash()));
$formControl->setFormForm($this->formForm);
$formControl->setDefaultValues((array)$this->sessionSection->default);
$formControl->onSuccessForm[] = function (Form $form) {
$values = $form->getHttpData(1);
$this->formService->saveFormForm($values, $this->formForm);
$this->showForm = true;
$this->sessionSection->limit--;
$this->sessionSection->default = $this->formService->deleteFileValues($values, $this->formForm);
$this->flashMessage("Formulář byl odeslán!");
if ($this->isAjax()) {
$this->redrawControl("formFormSnippet");
$this->redrawControl("flash");
} else {
$this->redirect("this");
}
};
$formControl->onErrorForm[] = function (Form $form) {
$this->submittedFormErrors($form);
$this->redrawControl("formFormSnippet");
$this->redrawControl("flash");
};
return $formControl;
}
Editoval Chuchy (9. 9. 2019 13:39)
- Chuchy
- Člen | 77
Ještě jsem přišel na to, že při použití klasického ajaxu
<script defer>
document.addEventListener("DOMContentLoaded", function(event) {
$('.form-sender').on('submit', function (e) {
let form = $(this);
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
alert("as");
}
else {
}
};
xhttp.open("POST", form.attr('action'), true);
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhttp.send(form.serialize());
return false;
});
});
</script>
takže je potřeba nějak dostat do nette.ajax volání XMLHttpRequest
vyvolá ajax a vrací response json
console
json
nicméně se mi stále nepřekreslí snippet, věděl by někdo, kde může být ještě chyba?
- chemix
- Nette Core | 1310
@Chuchy ahoj, chapu to spravne, ze tedy s tim nette.ajax.js to neposila formualre pomoci XHR ?
A co se ti vraci v preview, kdyz to posilas pres XHR naprimo ? JSON s invalidovanejma snippetama? ?
PS: nette.ajax.js je uz obsolote, pro tenhle drobny use case doporucuju Naja.js neni zavisla na jQuery
PSS: na obrazky je super https://cloudup.com
- chemix
- Nette Core | 1310
@Chuchy to je divne ze to posle xhr ale neda tam tu hlavicku a nette to pak nepochopi… :-/ s tim neporadim …
jinak custom implementace snippetu by nemela byt obtizna, defakto si projdes ten json co se ti vraci, a vsechny snippety podle html id najdes a nahradis jim html obsah. A mas danou vec a nepotrebujes nette.ajax.js
- jiri.pudil
- Nette Blogger | 1029
Trochu hádám, protože CORS je ohromně komplexní, ale není potřeba
hlavičky nad rámec nějakého minima (tnz. i X-Requested-With
)
explicitně whitelistovat pomocí Access-Control-Allow-Headers
v odpovědi?
- Chuchy
- Člen | 77
Tak jsem se po těžkém boji rozhodl, že místo nette.ajax rozjedu, nittro, mělo by umět všechno co potřebuji, jen nevím, kde mám změnit allowOrigins?
Pro info mi to přes nittro neposílá přes xhr, ale other. ale to bude určitě nějakým nastavením.
Editoval Chuchy (10. 9. 2019 13:54)
- Chuchy
- Člen | 77
@chemix to asi je, ale využiju ho i na dalších částech aplikace a když už se zbavím nette.ajax, tak at mám nějaký lepší nástroj..
- chemix
- Nette Core | 1310
@Chuchy bud si to muzes nakonfigurovat online na https://www.nittro.org/download nebo se nechat inspirovat na https://github.com/nittro/forum a zbuidlit si custom verzi pomoci gulpu
- Chuchy
- Člen | 77
@chemix ahoj, tak už mi to „funguje“, jen nechápu, proč se mi odesílají dva requesty naráz? to asi není očekávaná vlastnost..
- Chuchy
- Člen | 77
@chemix starej kod tam už není, ještě to budu muset projít hold no, důležité je, že to není správné, že to posílá 2 requesty, s čím už si nějak poradím :D
btw. když už tady píšu ohledně toho nittra.., jakým způsobem se dá odeslat formulář při změně? přes jquery jsem používal
$(document).on('change', '.formOverviewSearchForm', function () {
$(this).submit();
});
pro nittro mám napsáno něco takového, jenže to mě nikam nepustí
_context.invoke(function(di) {
var frm = di.getService('formLocator').getForm('frm-agreementSearchForm');
frm.on("change", function () {
console.log(frm);
});
});
- chemix
- Nette Core | 1310
Nittro ma sve forum na https://forum.nittro.org
Ani nevim ze se onchange vola na formu, jen na inputu ne?
- jiri.pudil
- Nette Blogger | 1029
Tip od boku: zobraz si v dev tools i metodu požadavku. Pokud je to
cross-origin, je naopak velmi správné, že to posílá dva requesty po sobě.
Klient totiž posílá nejprve tzv. preflight request metodou
OPTIONS
, pomocí které zjistí, jestli vůbec může požadavek
poslat (na základě Access-Control
hlaviček v odpovědi), a až
když usoudí, že může, reálně posílá původní požadavek původní
metodou.
Takže je třeba dát pozor na to, aby OPTIONS
request nevykonal
samotnou požadovanou akci. Úplně postačí, když pošle patřičné
Access-Control
hlavičky a vrátí prázdnou odpověď se stavem
204 No Content
.
- Marek Bartoš
- Nette Blogger | 1263
@Chuchy Přibyla @crossorigin
anotace
Presenter: signal must be sent from the same origin unless they have annotation @crossorigin (BC break)
- Andy3
- Člen | 15
Ahoj, jinak ta anotace je:
/**
* @crossOrigin
*/
Moc nechapu proc je to jen na handlach a ne i na renderu.
A nemelo by to na vyvoji neco zarvat nez dat jen redirect? Dost me vytrapilo
nez jsem na to prisel. Zajimave, ze pres Postmana mi to redirect nedavalo
i presto, ze jsem tam dal vsechny hlavicky co posilal browser vcetne
X-Requested-With:XMLHttpRequest(to uz jsem nezkoumal).
<?php
public function checkRequirements($element): void
{
if (
$element instanceof \ReflectionMethod
&& substr($element->getName(), 0, 6) === 'handle'
&& !ComponentReflection::parseAnnotation($element, 'crossOrigin')
&& !$this->getPresenter()->getHttpRequest()->isSameSite()
) {
$this->getPresenter()->detectedCsrf();
}
}
?>
Editoval Andy3 (20. 7. 2020 16:37)