wynik POST na zewnątrz funkcji - Chrome

0

Problem brzmi banalnie ale jak na razie taki dla mnie nie jest. Wysyłam POST przez jquery i chcę otrzymany wynik przekazać do zewnętrznej funkcji jako parametr adresu strony do otworzenia. Kodowo wygląda to mniej więcej tak:

$.post(URL, { parametr: wartosc },
   function(data) {
   wynik = data;
//wyświetlenie nowego okna
   window.open(URL+wynik,"_blank");
   })
    .error(function() { alert('Wystapił błąd! Spróbuj ponownie.'); });

Problem polega na wyświetlaniu się tego nowe okna. Wszystko działa ok poza Chrome. Każda inna przeglądarka otwiera nowe okno jako nową kartę lub nowe okno, w Chrome okno otwiera się zamiast aktualnego... Zauważyłem, że wynika to w wykonania window.open wewnątrz $.post. Jeśli zrobię wywołanie przed albo po funkcji Chrome też wszystko prawidłowo wyświetla. Próbowałem deklarować globalne zmienne przed funkcją ale zmienna jakoś nie przekazuje wartości:

 
var wynik = null;
$.post(.....
wynik = data
....);
alert(wynik);

Daje w odpowiedzi null a nie wartość zwracaną przez POST.
Chciałem wywoływać okno przez nową funkcję jeszcze wewnątrz POST ale dalej otwiera w Chromie nowe okno na miejsce starego. Nie jest to na pewno problem błędnego wywołania window.open i parametrów. Chodzi wyłącznie o problem wywołania tej funkcji wewnątrz POST przez jquery. Przeszukałem sieć i żadne rozwiązanie u mnie nie działa. Potrzebuje pobrać dane z serwera (POST/GET) i wyświetlić stronę (zewnętrzną) z parametrem zwróconym z serwera. Jestem otwarty na wszelkie sugestie. Po kilku godzinach kombinowania ja się poddaję.

0

Daje w odpowiedzi null a nie wartość zwracaną przez POST.

może dlatego, że ajax wykonuje się asynchronicznie? ;)

nie wiem dlaczego w chromie tak to się otwiera (szczerze, to w ciągu 3 lat raz użyłem window.open)
(swoją drogą - a próbowałeś zostawić drugi parametr pusty? window.open zawsze chyba otwiera nowe okno [czy nie?])
może zrób sobie tak:

var wynik = null;
function zapiszWynik(s) { wynik = s; }
function otworzOkno() { window.open(wynik, "_blank"); }
$.post(.....
zapiszWynik(data);
otworzOkno();
....);
0
dzek69 napisał(a)

Daje w odpowiedzi null a nie wartość zwracaną przez POST.

może dlatego, że ajax wykonuje się asynchronicznie? ;)

To był przykład w którym zmiennej przypisałem null, dlatego się tak wyświetliło a nie ze względu na asynchroniczność.
Drugi parametr był pusty, były miliony kombinacji z parametrami typu rozmiar okna itp. z tym samym efektem. Tak jakby rodzicem dla okna była ta wewnętrzna funkcja z POST.
Zaproponowany kod daje ten sam efekt - okno otwiera się na miejsce obecnego. Musze wywołać window.open po zakończeniu POST-u. Niestety nie mogę tego zrobić wewnątrz procedury np. na zdarzenia .complete(function() bo dalej okno otwiera się na miejsce starego. Wywołując natomiast nowe okno po zakończeniu procedury z POST-em nie otrzymuję zwracanej wartości bo jak zauważyłeś mam asynchroniczne zapytanie i zanim dojdzie odpowiedź, to nowe okno chce wyskakiwać bez wymaganej zmiennej.
Jakieś inne pomysły?

0

@Clarc:
Gdyby nie asynchroniczność, tj. gdyby $.post() działała synchronicznie, zmienna wynik miałaby w miejscu alerta odpowiednią wartość, a nie null. Także jednak to jest "wina" asynchroniczności.

To zachowanie Chrome'a wygląda odrobinę dziwnie, ale pamiętaj, że nie masz i nie będziesz miał formalnej gwarancji co do tego, gdzie przeglądarka otworzy nowe okno. Zależy to od ustawień użytkownika.

Troszkę poeksperymentowałem i chyba już wiem jak działa Chrome.

Rozwiązanie, które wstawił @dzek69, nie działa i nie ma prawa działać, bo tak naprawdę absolutnie niczego nie zmienia i nie widzę jak by mogło zmieniać. Nie może mieć znaczenia, czy dorzucimy do window.open jeszcze jedną funkcję otaczającą, czy nie. Bo przecież gdy korzystamy z jQuery, przeglądarka i tak nie odpala naszych funkcji bezpośrednio -- nasze funkcje są owinięte przez funkcje wewnętrzne jQuery.

Z moich obserwacji wynika, że Chrome otwiera nową kartę w odpowiedzi na akcję użytkownika. Czyli wywołań window.open z funkcji obsługującej kliknięcie przycisku, a okno zostanie otwarte w nowej karcie.

W Twoim przypadku, window.open nie znajduje się w kodzie "bezpośrednio" wywołanym przez akcję użytkownika. Tzn. może i to żądanie ajaxowe jest wywoływane przez jakieś kliknięcie, ale to tyle -- window.open jest wywoływane asynchronicznie, w zupełnie innym momencie, "po przyjściu odpowiedzi". A nie "po kliknięciu".

Wygląda na to, że moja hipoteza może być prawdziwa. Zobacz na ten kod, pseudo-działający:

http://jsbin.com/efonom/edit#javascript,html,live

Zamiast żądania asynchronicznego w funkcji $.post(), używam brzydkiego, synchronicznego $.ajax(). I jest git. Kliknięcie powoduje, że wykonywany jest blok kodu. Blok wysyła żądanie, ale robi to synchronicznie. Po przyjściu odpowiedzi, blok kodu wywoływany jest dalej. I otwierane jest okienko. W nowej karcie, bo wciąż jesteśmy w "kodzie wywołanym przez akcję użytkownika".

To niby działa, ale używa synchronicznego pseudo-ajaxu. To coś bardzo, bardzo złego. Nigdy nie należy tego robić.

Tutaj jednak, pośrednio, "pomaga". Zmień flagę async z false na true i zobacz, że nagle "przestanie działać", tj. Chrome otworzy nowe okno, a nie nową kartę.

Można poeksperymentować ze sztucznym wywołaniem zdarzenia click (za pomocą DOM Events). Jak chcesz, pogooglaj. Mi się nie chce, bo też sądzę, że prawdopodobnie nie da się tak łatw oszukać Chrome'a. Gdyby się dało, każdy spamer wywoływałby sztuczne kliknięcia. Z drugiej strony... Chrome i tak i tak otwiera te popupy, więc może to nie do końca zabezpieczenie antyspamowe?

Przyznaję, że nie rozumiem do końca tej sytuacji. Nie jest ona z całą pewnością związana z samym językiem JavaScript lub nawet samą biblioteką jQuery.

0

Faktycznie mój błąd w tą wartością zmiennej. Kilka godzin temu doszedłem jednak do wniosku, że nie uda mi się zrobić dokładnie tego co chciałem. Wymyśliłem więc inne rozwiązanie, które robi to co chce. Podczas testów wszystko działa ale na gotowej stronie przestało :) Będę musiał jeszcze powalczyć. A odnośnie tego otwierania stron w Chromie to zgłoszę 'nieprawidłowe działanie' i może poprawią coś w kolejnych wydaniach. Poza szybkością działania Chrome i paroma fajnymi funkcjami ta przeglądarka zaczyna mi podpadać jak IE. Już wcześniej znalazłem i inne problemy z nią które powodowały m.in. wywalanie całej przeglądarki... Dzięki za pomoc. Temat chyba wyczerpany jak na razie.

0

hm, pewnym rozwiązaniem jeszcze może być zrobienie:

$.post(URL, { parametr: wartosc },
   function(data) {
   wynik = data;
   setTimeout(function(){
      window.open(URL+wynik,"_blank");
   }, 50);
   })
    .error(function() { alert('Wystapił błąd! Spróbuj ponownie.'); });

Chrome ma sporo bugów, kiedyś miał problemy z dziedziczeniem wartości, dziś np nie potrafi poprawnie wyświetlić tabelki, jeżeli opływa inny element i ma zdefiniowaną szerokość na sztywno ;] Żadnego buga w sumie nie zgłaszałem, jeden jest poprawiony, reszty nie sprawdzałem :P

a to co Ci sie tu dzieje to pewnie jakis domyślny popup blocker - spróbuj powyłączać takie coś - powinno zadziałać.

0

@dzek69:
Testowałeś to z setInterval?

Jeśli moja hipoteza jest prawdziwa, to nie powinno działać.

I mi nie działało, a sprawdzałem coś bardzo podobnego gdy chciałem wyeliminować możliwość, że za inne zachowanie odpowiedzialny jest "kontekst ajaxowy". Testowałem nawet wtedy rozwiązanie z setInterval z pollingiem, w którym wywołanie window.open było zupełnie niezależne od ajaxa. Też nie działało, dlatego odrzuciłem możliwość, że ajax jest w nasze problemy jakkolwiek zamieszany. I uznałem, że chodzi o kliknięcie.

Można to zresztą sprawdzić, odpalając popup natychmiast, w zwykłym skrypcie na końcu strony. Otworzy się "niepoprawnie", tj. w nowym oknie, a nie w nowej karcie. Bo to nie jest kod wykonywany w odpowiedzi na akcję użytkownika. (Trzeba uważać testując to na JSBin, bo gdy klikamy na Render lub zaznaczamy Real Time Preview, to już jest to akcja użytkownika -- kliknięcie -- i nasz kod magicznie i przypadkowo zdaje się działać).

dzek69 napisał(a)

Chrome ma sporo bugów, kiedyś miał problemy z dziedziczeniem wartości

Jakie to były problemy?

Nie kojarzę takowych.

Pytam, bo staram się zbierać prawdziwe błędy dobrych silników JS-owych i jednocześnie usilnie eliminować te wyimaginowane, spowodowane brakiem kompetencji użytkowników czy przesądami. Na co drugiej rozmowie kwalifikacyjnej (dosłownie, myślę że to co najmniej 50%) słyszę jakieś mega dziwne i po prostu fałszywe przesądy. Nie twierdzę, że ludzie biorą to z powietrza -- może rzeczywiście "coś gdzieś wyczytali". Tyle że w necie można wyczytać taką ilość bzdur o JavaScripcie, że szkoda gadać... Strasznie nie lubię powtarzania tych bzdur i zawsze staram się je weryfikować i ewentualnie demaskować.

Ciekawe jak jest z tym "dziedziczeniem wartości". V8 to dobry silnik JS-owy. Jak najbardziej może mieć bugi i zapewne jakieś ma, ale zdawało mi się, że dziedziczenie prototypowe udało im się akurat opanować ;) A może to był po prostu "feature" JavaScriptu? Lub rzecz "zależna od implementacji"? Czy jednak rzeczywisty bug? Nie udało mi się wygooglować.

0

Nie testowałem nic, napisałem, bo generalnie funkcje z setTimeout (a w zasadzie masz rację @bswierczynski - lepsze byłoby setInterval) są już wykonywane jakby w innym wątku - może tam nie będą już "pamiętały" "kontekstu".

[OT]
O dziedziczeniu to mówię o cssach :D Tamto z dziedziczeniem czegoś (za cholerę nie pamiętam czego, wiem tylko, że się menu przez to sypało tylko pod Chromem) to było 2-3 lata temu, więc trochę nieaktualne. To z floatowaniem tabelek pewnie dalej "działa" (znalazłem podobnego bugreporta gdzieś na jakichś grupach dyskusyjnych googla [?] - i chyba po nim poprawili tylko floatowanie tablek z width: auto, te ze stałą szerokością się sypią (konkretniej to najeżdzają na opływany element)), w jakiejśtam aplikacji którą piszę (jeszcze tego nie badałem, takie durne bugi zostawiam na koniec) absolutnie pozycjonowany przycisk (input typu submit) z bottom: 0 jest jeden piksel za wysoko, innych też już nie pamiętam niestety (jeszcze ze 2 były)

Do chromowego JS nic nie mam, póki co mi się nie rzucił. Zresztą JS to taki boski język, że tu mnie dużo jeszcze zdziwi. Ale i tak póki co najfajniej mi się w JS pisze (i node.js ftw :D).

0

Dzięki za wszystko pomysły i odpowiedzi. Próbowałem z setInterval (nie wiadomo czemu po pierwszej iteracji samo się wyłączało bez wywołania clearInterval), próbowałem z zapętlonym setTimeout wywołać nowe okno za pokończeniu POST-u. W Chrome zawsze nowe okno wyskakiwało na miejsce obecnego. Problemem okazało się blokowanie okien przez Chrome które niestety nie działa... Jak odblokuje wyskakujące okna to wszystko działa prawidłowo. Z blokowaniem pop-upów na chwilę pojawia się informacja w pasku adresu po czym otwiera się blokowana strona :] Mam zrobiony mechanizm wykrywania blokowania pop-upów, żeby user mógł sobie to odblokować jeśli zostanie to wykryte ale w Chromie nawet nie ma jak tego zastosować. Niby blokuje okna a przepuszcza. Kwestię rozszerzeń wykluczyłem bo są powyłączane. Jedyny powód to sam Chrome. Ta niby świetna przeglądarka zaczyna mnie dobijać.
Chrome 16

1 użytkowników online, w tym zalogowanych: 0, gości: 1