Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Dobranie sę do zmiennej z pliku dołączanego dynamicznie
Forum PHP.pl > Forum > Po stronie przeglądarki > JavaScript
thek
Na początku napiszę, że problem mam rozwiązany "na okrętkę", ale podam go na końcu... Szukam bowiem rozwiązania ładniejszego ;)

Mam sobie klasę w JS, gdzie w prototypie stworzyłem funkcję do dynamicznego dołączania pliku w strukturę DOM. Standardowe utworzenie elementu script z określonym src i type a całość po utworzeniu walę jako appendChild. Coś w stylu:
[JAVASCRIPT] pobierz, plaintext
  1. var file = document.createElement('script');
  2. file.setAttribute("src", tu_sciezka);
  3. file.setAttribute("type", tu_info_iż_to_javascript);
[JAVASCRIPT] pobierz, plaintext

W dołączanym pliku mam zmienną
[JAVASCRIPT] pobierz, plaintext
  1. var zmienna = TU_STRUKTURA_JSON;
[JAVASCRIPT] pobierz, plaintext

i wszystko fajnie, ale plik ten jest dołączany dosłownie na chwilkę. Dołączam (to działa na bank bo obejście działa), chcę przechwycić zmienną z wewnątrz i odłączyć plik. Dla dołączanego pliku zdefiniowałem sobie zdarzenie
[JAVASCRIPT] pobierz, plaintext
  1. file.onload = function() {...}
[JAVASCRIPT] pobierz, plaintext

Próbowałem wewnątrz przechwycić var zmienna i przekazać ją wyżej do skryptu i tu jest problem, bo zasięgi widoczności sa takie, iż samą zmienną widzę, dopóki operacje wykonuję wewnątrz funkcji anonimowej (sprawdzane console.log - działa, zmienna jest ok i widoczna na tym poziomie), ale nie mogę wrzucić parametru (onload jako parametr przyjmuje event i nic innego :/), nie mogę użyć self (to mi daje hook na obiekt window) ani this (to mi daje hak na utworzony obiekt script ), a próba wejścia tam na pałę z globalną zmienna tymczasową i do niej przypisanie zawartości zmiennej z pliku kończy się oczywiście przywróceniem wartości z kontekstu globalnego zaraz po wyjściu z funkcji anonimowej. Myślałem o jakimś return wewnątrz funkcji anonimowej, ale do czego by ta wartość się przypisała? file.onload ? To po powrocie też sprawdzę (bo nie zrobiłem tego jeszcze - była 2 w nocy i chciałem już iść w kimę :D ), ale może ktoś do tego czasu mi podrzuci pomysł/wskazówkę/rozwiązanie. Może za bardzo zamotałem sobie życie lub byłem już za bardzo padnięty i zwyczajnie nie zauważyłem jakiegoś banalnego rozwiązania.

Zgodnie z adnotacją na początku: zrobiłem obejście (proste po uzupełnieniu klasy Storage o dwie metody, bo ta nie ma, według dokumentacji implementujących firm, możliwości przechowywania obiektów) z użyciem sessionStorage z html5, ale Storage i starsze IE (6, 7) to oczywiście "nieporozumienie". Po powrocie na chatę wrzucę kod tego co zrobiłem, by było widać gdzie konkretnie zmiany moim zdaniem należy przeprowadzić.

EDIT: Dorzucam wspomniany kod :)
[JAVASCRIPT] pobierz, plaintext
  1. var file=document.createElement('script');
  2. file.setAttribute("type","text/javascript");
  3. file.setAttribute("src","media/js/data/lang."+language+".js");
  4. var temp; /* tu próba zmiennej do przechwycenia */
  5. file.onload = function()
  6. {
  7. sessionStorage.setObject('storedLang', lang);
  8. temp = lang;
  9. console.log(lang); /* Pokazuje OK dane */
  10. console.log(this); /* rzuca oczywiście obiekt file */
  11. console.log(self); /* tu zaś obiekt window */
  12. return lang; /* Próba zwrotki */
  13. }
  14. if (typeof file!="undefined")
  15. {
  16. /* Adding element to DOM and extracting */
  17. document.getElementsByTagName("head")[0].appendChild(file);
  18. if(sessionStorage.storedLang)
  19. {
  20. this.translationTables[language] = sessionStorage.getObject('storedLang');
  21. this.storedLangs.push(language);
  22. sessionStorage.removeItem('storedLang')
  23. }
  24. console.log(file.onload); /* Zwróci treść funkcji onload niestety */
  25. console.log(temp); /* tu też kicha... */
  26. /* Remove file from DOM */
  27. document.getElementsByTagName("head")[0].removeChild(file);
  28. }
[JAVASCRIPT] pobierz, plaintext
kamil4u
A nie możesz po prostu tego:
[JAVASCRIPT] pobierz, plaintext
  1.  
  2. if(sessionStorage.storedLang)
  3. {
  4. this.translationTables[language] = sessionStorage.getObject('storedLang');
  5. this.storedLangs.push(language);
  6. sessionStorage.removeItem('storedLang')
  7. }
  8. console.log(file.onload); /* Zwróci treść funkcji onload niestety */
  9. console.log(temp); /* tu też kicha... */
[JAVASCRIPT] pobierz, plaintext


Wrzucić do onload?

Jeżeli tak, a jedyny problem to:
Cytat
this.translationTables[language] = sessionStorage.getObject('storedLang');

i słówko this to to się robi na dwa sposoby:

1. var that = this; i później użyć that
lub
2. użyć https://developer.mozilla.org/pl/Dokumentac...y/Function/call

Podsumowując - zrób to tak:
[JAVASCRIPT] pobierz, plaintext
  1. var file=document.createElement('script');
  2. file.setAttribute("type","text/javascript");
  3. file.setAttribute("src","media/js/data/lang."+language+".js");
  4. var that = this; /* <----- */
  5.  
  6. file.onload = function()
  7. {
  8. that.translationTables[language] = lang;
  9. }
  10.  
  11. if (typeof file!="undefined")
  12. {
  13. /* Adding element to DOM and extracting */
  14. document.getElementsByTagName("head")[0].appendChild(file);
  15. /* Tu wykona się onload i przypisze Ci do Twojej Tablicy dane z JSON, które później sobie obrobisz jak chcesz */
  16. document.getElementsByTagName("head")[0].removeChild(file);
  17. }
[JAVASCRIPT] pobierz, plaintext


Jeżeli to nie to, to przygotuj jakieś najprostsze demo i napisz co chcesz zrobić jeszcze z tymi danymi. Zawsze lepiej mi się myśli, gdy mogę wykorzystać metodę prób i błędów smile.gif

Pozdrawiam
thek
Jak widać takie podejście mi umknęło smile.gif Rozwiązaniem okazało się dokładnie to co zaproponowałeś jako przykładowy kod... Przypisanie do dodatkowej zmiennej this i pchnięcie go do wnętrza. Kombinowałem dobrze z dodatkową zmienną, ale zabrakło mi pomysłu jak to połączyć. W ten sposób omijam zabawę z sessionStorage, a właśnie o to mi chodziło. Zasłużony w pełni Pomógł ląduje.

Tak jeszcze w ramach wyjaśnienia... Fragment tego co dałem ma na celu otworzenie pliku z tłumaczeniami i pobranie jego wnętrza do obiektu tłumaczącego. JSON zawiera pary słowo -> tłumaczenie.
kukix
Witam. Podłacze się pod temat. aarambo.gif

Prosze mi rozjaśnić troszeczke, w jaki sposób mogę się dobrać do poszczególnych zmiennych w przypadku tego skryptu, jeżeli mój plik z danymi wygląda tak:

  1. print 'var config = {';
  2. print 'param_1: "'.$cfg['param_z_bazy_1'].'",';
  3. print 'param_2: "'.$cfg['param_z_bazy_2'].'",';
  4. print 'param_3: "'.$cfg['param_z_bazy_3'].'",';
  5. print '};';


W jaki sposób odwołać się do poszczególnej zmiennej? Czy ten skrypt ładuje je jakośpo kolei do tablicy that.translationTables[language] ?
Nie potafie wyświetlić tych danych a próbowałem na różne sposoby sad.gif
kamil4u
Cytat
W jaki sposób odwołać się do poszczególnej zmiennej?


Taki zapis zwie się JSON-em. W JS możesz się odwoływać do tych elementów za pomocą:
Kod
config['parm_1']
lub
Kod
config.parm_1


Cytat
Czy ten skrypt ładuje je jakoś po kolei do tablicy that.translationTables[language] ?

Nie koniecznie. Po prostu masz tablicę o nazwie translationTables. Teraz chcesz dodać coś do tej tablicy, więc tworzysz nowy indeks o nazwie takiej jaką ma zmienna language. Póżniej możesz się odwołać do niej np. tak:
Kod
this.translationTables[language]['parm_1']
//lub
this.translationTables[language].parm_1


Nie jestem pewien czy na pewno o to pytałeś smile.gif
kukix
Dzięki za podpowiedź, ale chyba coś robie nie tak.

Wstawiłem do skryptu JS na poczatku dokładnie taki kod:
  1. var file=document.createElement('script');
  2. file.setAttribute("type","text/javascript");
  3. file.setAttribute("src","config_ustaw_js.php");
  4. var that = this;
  5.  
  6. file.onload = function()
  7. {
  8. this.tablica_config[] = config;/// tutaj tez kombinowałem questionmark.gif
  9. }
  10.  
  11. if (typeof file!="undefined")
  12. {
  13. document.getElementsByTagName("head")[0].appendChild(file);
  14. document.getElementsByTagName("head")[0].removeChild(file);
  15. }
  16.  
  17. tutaj próbowałem na różne sposoby wyświetlić wartość któregoś parametru ale nie wyszło :/
  18. alert(this.translationTables[].param_1);


W Twoim przykładzie była linijka z kodem: that.translationTables[language] = lang; jednak nie wiem nawet skąd ta zmienna lang
thek
W moim przypadku zmienna lang jest wewnątrz pliku, który podpinałem... U Ciebie odpowiednikiem jest zmienna var config jeśli dobrze widzę... W moim kodzie jest jeszcze language, ale ta zmienna jest akurat parametrem, który zawiera 2-znakowy kod języka i staje się jednocześnie kluczem tablicy, której wartością jest to, co znajduje się w zmiennej lang w pliku smile.gif Przynajmniej taki zamysł był przy jego powstawaniu wink.gif
zegarek84
Cytat(kukix @ 18.04.2012, 17:54:04 ) *
  1. if (typeof file!="undefined")
  2. ...

myślisz "synchronicznie" - w kolejności pisania kodu, może nie od razu się przestawisz ale JS jest dobrą podstawą do programowania zdarzeniowego, do zrozumienia domknięć (przede wszystkim zasięgu klamerkowego) a przez to, że niemal wszystko jest referencją to przesiadka na np. C++ to nie problem ;]...

przy programowaniu zdarzeniowym musisz zapomnieć, że tam, gdzie podpinasz dane zdarzenie (funkcję, która ma się wykonać później), to kod występujący za daną funkcją jakby nie istniał (patrz przez "pryzmat" - zdarzenie będzie przed resztą kodu to tylko wtedy zdarzeniowa funkcja wykona się wcześniej - w przeciwnym wypadku zawsze później)... ale by nawiązać do cytatu... przecież if jeszcze nie jest poza zdarzeniem a zawsze będzie prawdziwy gdyż już na początku zadeklarowałeś zmienną "file=document.createElement('script');" - choć programuję tylko hobbystycznie to jednak uważam, iż zrozumienie kiedy co się, dzieje sporo ułatwia (w programowaniu zdarzeniowym if jest jakby oderwany od kodu i dana funkcja raczej wykona się później lub nigdy!!!)... jeśli coś nieraz musiałem wykonać wspierając się wątkami (w JS ich nie ma ;p), to i tak robiłem tylko część krytyczną na wątkach a resztę implementowałem na zdarzeniach...

może Ci coś pomoże stary temat a może nie - trochu teraz się podchmieliłem ale z powyższym jeśli przeczytasz z 3 razy to może zrozumiesz:
[JavaScript]Załączanie prototype poprzez js

...
ps.
a pro po tego cytatu i if'a gdyż nie do końca wytłumaczyłem i chyba nie ma sensu lepiej tłumaczyć puki nie zrozumiesz, co kiedy się dzieje, ale błędem jest konstrukcja synchronicznie wykonana w tym if'ie:
document.getElementsByTagName("head")[0].removeChild(file);
mogłeś to wykonać w funkcji asynchronicznej - aczkolwiek prywatnie uważam, iż to sprawa kosmetyczna, gdyż co miało trafić do obiektu window to trafiło i tam zostało zapamiętane a 1 element drzewa dom w porównaniu do reszty aż tyle pamięci nie odzyska... zresztą to co nieraz widziałem to śmiało można powiedzieć, iż szybkość rozwiązań zależy nie od języka programowania a od stylu programowania - widziałem kilka rozwiązań mniej zasobożernych wykonanych w php jak w c++ - oczywiście to wina nie wiedzy i każdy kiedyś się uczy, jednak jak o jednym wspomniałem tak też napiszę, iż nie ma sensu próbować za wszelką cenę coś optymalizować choćby kosztem czytelności (wszędzie są wyjątki od reguły)
thek
Jeśli to było do mnie, to mogę dodać, że akurat ten fragment jest częścią funkcji sparametryzowanej co może widać będzie w pełniejszej wersji:
[JAVASCRIPT] pobierz, plaintext
  1. Translator.prototype.loadLangFile = function(language)
  2. {
  3. //console.log(this);
  4. var file=document.createElement('script');
  5. file.setAttribute("type","text/javascript");
  6. file.setAttribute("src","media/js/data/lang."+language+".js");
  7. var temp = this;
  8. file.onload = function()
  9. {
  10. temp.translationTables[language] = lang;
  11. }
  12. if (typeof file!="undefined")
  13. {
  14. document.getElementsByTagName("head")[0].appendChild(file);
  15. document.getElementsByTagName("head")[0].removeChild(file);
  16. }
  17. }
[JAVASCRIPT] pobierz, plaintext
Oczywiście zawsze można poszerzyć o rzucanie wyjątków ale na razie "obciąłem" je. To co piszesz o "undefined" to od początku nie było tak planowane jak wspomniałeś, ale jako zabezpieczenie w razie gdyby coś poszło nie tak i obiekt file nie powstał. Stąd jego typeof, by nie dopinać do sekcji head obiektu, który jest w takim wypadku błędny. Rozumiem o czym piszesz bo moja nauka programowania to był początkowo Turbo Pascal, a potem C/C++, więc rozumiem o co Ci chodzi... Gdy tak patrzę na to, myślę że bezpieczniejsze było by owe removeChild(file) przenieść wprost do wnętrza onload jako removeChild(this), czyli przy onload wczytało by wnętrze i "odpięło się samo". Choć dla elastyczności byłoby lepiej miejsce wpinania przekazać podobnie jak that. No ale jak sam wspomniałeś - to już kosmetyka. Choć kod w stylu:
[JAVASCRIPT] pobierz, plaintext
  1. Translator.prototype.loadLangFile = function(language)
  2. {
  3. var file=document.createElement('script');
  4. file.setAttribute("type","text/javascript");
  5. file.setAttribute("src","media/js/data/lang."+language+".js");
  6. var temp = this;
  7. var hook = document.getElementsByTagName("head")[0];
  8. file.onload = function()
  9. {
  10. temp.translationTables[language] = lang;
  11. hook.removeChild(this);
  12. }
  13. if (typeof file!="undefined")
  14. {
  15. hook.appendChild(file);
  16. }
  17. }
[JAVASCRIPT] pobierz, plaintext

na pewno jest bezpieczniejszy jeśli chodzi o wycieki pamięci smile.gif Niemniej dziękuję za wskazanie miejsca do poprawki, nawet jeśli zrobiłeś to niezamierzenie i z innych powodów, które są bardziej natury kosmetycznej. Zawsze to jakaś luka mniej smile.gif
zegarek84
pisałem do @kukix by wskazać błąd myślowy i ogólnie chciałem opisać którędy program podąży... przy programowaniu zdarzeniowym kod programu nie jest wykonywany w kolejności występowania kodu, rozgałęzienia następują prawie jak na if'ach (nie wiem do czego to przyrównać) na zdarzeniach...

ale jak tak dzisiaj na trzeźwo patrzę tylko na fragment kodu to u @kukix najprawdopodobniej jest problem ze zrozumieniem this w JS - w kodzie przypisuje this do that i potem nigdzie nie wykorzystuje, jeśli fragment kodu nie jest częścią metody to this będzie oznaczało window... potem jest użycie this w funkcji onload gdzie to this będzie znaczyło element drzewa DOM czyli to samo co zmienna file

ps.
nie wiem dlaczego, chyba dla tego, że jeśli czasami kod komuś poprawiałem to ze zmiennymi przy długich funkcjach jeśli chodzi o zasięg klamerkowy czasami różne rzeczy się dzieją np. nagle ktoś podstawi inny obiekt (chyba, że to było zamiarem) lub całkiem usunie referencję, to takie elementy obiektów gdzie chcę mieć pewność, iż nikt ich nie nadpisze jakoś wolę przekazywać przez argument do funkcji anonimowej w stylu:
[JAVASCRIPT] pobierz, plaintext
  1. file.onload = (function(that){
  2. return function(){
  3. // mam pewność, że referencja do danego obiektu mi nie zginie przez przypadek przez inne operacje kodu
  4. }
  5. })(this);
[JAVASCRIPT] pobierz, plaintext

podobnie można robić z innymi obiektami nie tylko this
a jeśli gdzieś coś ma się zmieniać dynamicznie to np. przekazuję referencję do obiektu o jeden poziom wyżej i w kodzie funkcji anonimowej odwołuję się do zmiennych składowych danego obiektu...
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.