Jak renderovat snippety na cizích webech?

Chuchy
Člen | 77
+
0
-

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)

chemix
Nette Core | 1296
+
0
-

Ahoj @Chuchy

  1. jak renderujes formular? Jelikoz vidim jen odkaz na JS soubor? Takze renderujes form pomoci JS? Snippety jsou vazane na html id.
  2. co vidis za chyby nebo odpovedi v dev konzoli
  3. je to cele nekde videt?
Chuchy
Člen | 77
+
0
-

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)

chemix
Nette Core | 1296
+
0
-

@Chuchy nette aplikace nic nevraci po odeslani formulare? Nejak v te konzoli nemuzu nic najit?

Chuchy
Člen | 77
+
0
-

chemix napsal(a):

@Chuchy nette aplikace nic nevraci po odeslani formulare? Nejak v te konzoli nemuzu nic najit?

vrací již pouze html
response

chemix
Nette Core | 1296
+
0
-

Tak tam je chyba, mel by vracet json response se snippetem k prekresleni

Chuchy
Člen | 77
+
0
-

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
+
0
-

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
+
0
-

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?

chemix
Nette Core | 1296
+
0
-

@Chuchy a opravdu se to posila pres XHR? Nette to pozna a lze pak pouzit jen dotaz na isAjax() a pak dat redrawControl. Tenhle kus kodu si sem neposlal jak zpracovavas form. Nahod

Chuchy
Člen | 77
+
0
-

Tohle to vrací při použítí třídy ajax na formuláři

console

xhr

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
+
0
-

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 | 1296
+
0
-

@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

Chuchy
Člen | 77
+
0
-

@chemix ahoj, ne i s nette.ajax se to pošle pomocí XHR, jen v hlavíčce requestu chybí X-Requested-With XMLHttpRequest, což zapříčiní, že to nette nevezme jako ajaxou operaci.

Preview, když to posílám na přímo vrací spracovaný dotaz a kompletní stránku (HTML) nikoliv JSON

chemix
Nette Core | 1296
+
0
-

@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 | 1028
+
0
-

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
+
0
-

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)

chemix
Nette Core | 1296
+
0
-

@Chuchy imho nittro je na tohle kanon na vrabce…

Chuchy
Člen | 77
+
0
-

@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..

dokáže mi někdo říct, kam tohle nasadit?

chemix
Nette Core | 1296
+
0
-

@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
+
0
-

@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..

dva dotazy

chemix
Nette Core | 1296
+
0
-

@Chuchy tak to je super, jen zjistit proc… zkus si krokovat JS kdo posila ten druhej, nezapomel jsi tam nejakej starej kod?

Chuchy
Člen | 77
+
0
-

@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 | 1296
+
+1
-

Nittro ma sve forum na https://forum.nittro.org

Ani nevim ze se onchange vola na formu, jen na inputu ne?

Chuchy
Člen | 77
+
0
-

@chemix někde jsem to tak vygooglil :)

chemix
Nette Core | 1296
+
0
-

@Chuchy link? Me to prijde prave divne

jiri.pudil
Nette Blogger | 1028
+
+2
-

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.

Chuchy
Člen | 77
+
0
-

Ahoj, updatoval jsem apliakci na nette 3.0 a místo ajaxového volání nastává redirect na pravou stránku? proběhla nějaká změna v nette ohledně crossite?

Marek Bartoš
Nette Blogger | 1166
+
0
-

@Chuchy Přibyla @crossorigin anotace

Presenter: signal must be sent from the same origin unless they have annotation @crossorigin (BC break)

https://github.com/…s/tag/v3.0.0

Chuchy
Člen | 77
+
0
-

musel jsem nastavit u formuláře, díky všem za pomoc :)

$form = new Form();
$form->disableSameSiteProtection();
Andy3
Člen | 15
+
0
-

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)