[JS] Zapisywanie tablic w cookies

0

Hej

Próbuję zapisać w ciastkach tablicę i nie do końca wiem jak. Np. mam jakiś przycisk i i dla tego przycisku wywołuję funkcję JavaScript, której zadaniem jest zapisanie kilku elementów. Pomyślałem, że najlepszym rozwiązaniem byłoby posłużenie się tablicami bo struktura danych wygląda mniej więcej tak:
wartość_1: ['tekst', int, 'tekst']
wartość_2: ['tekst', int, 'tekst']
wartość_3: ['tekst', int, 'tekst']
To jest tylko przykład, ale chodzi mi o to, że muszę przechować na komputerze klienta kilka zestawów informacji. W moim przypadku 'wartość1-n' jest dynamicznie generowana i muszę znać nazwę żeby odczytać ciastko więc pomyślałem, że dobrze by było 'zamknąć' to w tablicę:
cookie['moje_ciacho'] = wartość1],[wartość2],...[wartośćn

Chciałbym się oprzeć o javascript, żeby klient nie widział przeładowywania strony, ale też żeby nie obciążać serwera - tych wywołań pojedynczy klient może zrobić kilkanaście razy x klientów - mogło by to bardzo obciążyć serwer. Problem w tym, że nie wiem jak zapisać taką dwuwymiarową tablicę w ciastkach :( Z góry dzięki za wszelkie wskazówki.

Pozdrawiam

1

Użyj formatu JSON. Jest bardzo elastyczny.

var obj = {
"wartosc1": "lorem",
"wartosc2": "ipsum",
"wartosc3": 12,
"wartosc4": { "imie": "Zenek", "wiek": 40, "nazwisko": "Kowalski"},
"wartosc5": { "imie": "Waldek", "wiek": 19, "nazwisko": "yyy ze co?"}
};

I masz w pamięci taki obiekt, a potem jak chcesz zapisać go w ciasteczku serializujesz:

obj.toSource(); //zapisujesz wynik w ciastku

Potem jak odczytasz z ciasteczka:

var obj = eval('(' + to_co_wyczytales_z_ciacha + ')');
0
Demonical Monk napisał(a)

Użyj formatu JSON. Jest bardzo elastyczny.

var obj = {
"wartosc1": "lorem",
"wartosc2": "ipsum",
"wartosc3": 12,
"wartosc4": { "imie": "Zenek", "wiek": 40, "nazwisko": "Kowalski"},
"wartosc5": { "imie": "Waldek", "wiek": 19, "nazwisko": "yyy ze co?"}
};

I masz w pamięci taki obiekt, a potem jak chcesz zapisać go w ciasteczku serializujesz:

obj.toSource(); //zapisujesz wynik w ciastku

Potem jak odczytasz z ciasteczka:

var obj = eval('(' + to_co_wyczytales_z_ciacha + ')');

Wiem, że to może durne pytanie, ale czy mógłbyś zapisać to łącznie z zapisem i odczytem ciastka? - nie chce mi to działać i nie wiem czy ja coś porąbałem czy o czymś nie wiem.
I dodatkowe pytanie - nigdy nie używałem formatu JSON i nie do końca wiem z czym to się je, w związku z tym czy potrzebuję jakiejś biblioteki? Dzięki :)

0

Do ciasteczka zapisujesz to co jest w obj.toSource(). Tu masz przykłady używania ciasteczek: http://www.w3schools.com/JS/js_cookies.asp

U mnie działa:

document.cookie = 'ass=' + obj.toSource();

Taki najprostszy przykład.

0
Demonical Monk napisał(a)

Do ciasteczka zapisujesz to co jest w obj.toSource(). Tu masz przykłady używania ciasteczek: http://www.w3schools.com/JS/js_cookies.asp

U mnie działa:

document.cookie = 'ass=' + obj.toSource();

Taki najprostszy przykład.

Dzięki. To rozwiązuje problem - dokładnie o coś takiego mi chodziło :) A nie działało mi bo jak pierdoła nie zauważyłem błędu :)

0

To jednak nie koniec problemów :)

mam funkcję javascript:

Function SaveCookie(id, param1, param2, param3)
{
     //odczyt cookie jeżeli już jest
    var cookie = ReadCookie()
    var IDs = {id};
    var params = {};
    if(cookie != "")
    {
        var obj = eval('(' + cookie + ')'); 
        //tutaj odczytanie poszczególnych parametrów z obj i połączenie ich z parametrami przekazanymi do funkcji
       IDs = obj['IDs'] + {id};//dodanie id do listy już zapisanych
       params = obj['params'] + id:{"param1":param1, "param2":param2, "param3":param3};//to id to miałoby być jako etykieta
       
          //zapis obj do cookie
    }

}

trochę mi to nie działa ;) Chodziło mi o to żeby trzymać w "tablicy" wszystkie id które trzeba zapisać, a które później posłużą mi do odczytania params, gdzie etykietami kolejnych "tablic" zawierających konkretne informacje byłoby właśnie id. Jakby ktoś kompetentny mógł na to zerknąć i powiedzieć co jest nie tak lub jak to zrobić inaczej to byłbym wdzięczny :)

0

Co to za konstrukcja {id}? Co to ma być? Albo coś takiego: id: {"param1":param1 ... } dodawane jako string (?) do obiektu params, którego potem nie używasz...? Czemu masz tam Function pisane z wielką literą na początku? Powinno być: function.

Prawdę mówiąc, to ten kod zawiera błędy składni i w ogóle nie będzie interpretowany jako JavaScript. Funkcja SaveCookie nie zostanie nawet zdefiniowana. Nie wiem, może to kwestia literówek -- może nie masz edytora z kolorowaniem składni i stąd te dziwactwa w stringach. Jeśli tak, to koniecznie sobie taki edytor spraw, bo nawet tu na forum błędy widać jak na dłoni.

Jeśli faktycznie po prostu nie znasz składni JavaScript, to polecam się jej nauczyć zamiast próbować pisać przypadkowo w języku, którego się nie zna -- bo "a nuż zadziała". W książce "JavaScript -- Mocne strony" Douglasa Crockforda jest to ładnie i zwięźle opisane.

Jeśli chcesz dodać do params własnośc id, która będzie obiektem z własnościami param1, param2 i tak dalej, to robi się to tak:

params.id = {
  param1: param1,
  param2: param2
};

Nazwy własności param1 i param2 mogą być w cudzysłowach, ale nie muszą. Musiałyby być w cudzysłowach lub apostrofach gdyby zawierały np. spacje czy inne znaki specjalne. O takich rzeczach wyczytasz we wspomnianej przeze mnie książce.

0

błędy składni wystąpiły po części z tego, że nie wkleiłem funkcji z edytora a pisałem z palca jako kod poglądowy, a część błędów wyszła ponieważ nie znam javascript na takim poziomie, żeby nie szukać pomocy na forum u osób, które potrafią i chcą pomóc. A jeżeli chcę napisać prostą funkcję to ciężko poświęcić mnóstwo czasu na naukę czytając książki. Tak przy okazji ciekawe czy Ty nigdy nie pytałeś o banały na forum ponieważ nie był czasu na naukę? Tak czy inaczej wiem, że coś jest nie tak z moim kodem i wynika to z mojej niewiedzy i właśnie dlatego proszę o pomoc. A Twoja odpowiedź nie do końca mi pomogła.

0
Stefan12 napisał(a)

błędy składni wystąpiły po części z tego, że nie wkleiłem funkcji z edytora a pisałem z palca jako kod poglądowy, a część błędów wyszła ponieważ nie znam javascript

Zwykle lepiej jednak wkleić kod, na pewno lepsze wklejanie (i ew. usuwanie nieistotnych fragmentów) niż przepisywanie. Również dlatego, że -- jak sam mówisz -- masz problemy z JavaScriptem. Skąd my mamy wiedzieć, który z bugów to zwykła literówka, a który popełniłeś świadomie, z powodu niedostatecznej znajomości języka? Tak czy siak, warto przynajmniej zaznaczyć, że podajesz przykładowy, pisany z palca kod i np. prosisz o skupienie się na algorytmie, a nie na literówkach. Ale w Twoim przypadku sam język też może być przecież problemem.

Stefan12 napisał(a)

Tak przy okazji ciekawe czy Ty nigdy nie pytałeś o banały na forum ponieważ nie był czasu na naukę?

Nie, nigdy. Nie przypominam sobie bym zabierał się za dość skomplikowany problem programistyczny nie mając wielkiego pojęcia o języku i pytał się o kolejne konstrukcje językowe na forum. To takie dziwne?

Ja w ogóle bardzo staram się nie używać profesjonalnie technologii i technik, których nie znam i na których poznanie nie mam czasu. Wydaje mi się to nieprofesjonalne. Uczyć się czegoś przy projekcie można (o ile zleceniodawca wie, że się przy okazji uczymy), ale do nauki też trzeba podejść poważnie i trochę poczytać.


Nie wiem, czy dobrze ogarniam to, co chcesz zrobić. Nie pomagają mi ogólne nazwy identyfikatorów, które masz w kodzie -- takie jak obj czy params. Żeby to było w pełni zrozumiałe to musiałbyś to solidnie opisać i/lub solidnie napisać algorytm. A tak, jak np. przypisujesz coś do ogólnie brzmiącej zmiennej params, a potem nigdzie jej nie używasz, to naprawdę nie mam jak się skapnąć, do czego to ustrojstwo służy ;).

Zakładam, że w funkcji chcesz odczytać obiekt zapisany w ciasteczku, zmodyfikować kilka własności tego obiektu (ewentualnie dodając niektóre lub wszystkie z tych własności), a następnie zapisać zaktualizowany obiekt do ciasteczka. Zakładam też, że funkcję SaveCookie można wywołać kilka razy z tym samym ID -- bo możemy chcieć zaktualizować wartości zapisane dla danego ID. To wprowadza do kodu trochę komplikacji, bo ciasteczko może, ale nie musi zawierać już jakieś dane związane z danym ID:

function SaveCookie(id, param1, param2, param3)
{
    var cookie = ReadCookie();

    // jeśli ciasteczko nie istniało, ustawiamy cookieData na nowy, pusty obiekt
    var cookieData = eval('(' + cookie + ')') || {};

    // jeśli do cookieData nie zostały wcześniej zapisane żadne ID do pola IDs,
    // to ustawiamy pole IDs na pustą tablicę
    cookieData.IDs = cookieData.IDs || [];

    // jeśli do cookieData nie zostały zapisane informacje pod danym id,
    // tworzymy pusty obiekt (puste pole) dla tych informacji
    cookieData[id] = cookieData[id] || {};

    // podstawiamy dla wygody, żeby nie musieć pisać cookieData.IDs
    // (to zwiększa wydajność, zmniejsza rozmiar kodu po kompresji,
    // ułatwia utrzymywanie bo nazwę własności IDs mamy w mniejszej ilości miejsc)
    var cookieDataIDs = cookieData.IDs;

    var cookieDataContainsCurrentID = false;
    for (var i = 0; i < cookieDataIDs.length; i++) {
        if (cookieDataIDs[i] === id) {
            cookieDataContainsCurrentID = true;
            break;
        }
    }
    
    // zapisujemy id do listy, jeśli nie ma tego id na liście zapisanych
    if (!cookieDataContainsCurrentID) {
        cookieDataIDs.push(id);
    }

    // ponownie: podstawiamy sobie dla wygody
    var cookieDataForCurrentID = cookieData[id];

    cookieDataForCurrentID.param1 = param1;
    cookieDataForCurrentID.param2 = param2;
    cookieDataForCurrentID.param3 = param3;
 
    // i tu ma nastąpić zapisanie obiektu cookieData do ciasteczka
    // użyjesz cookieData.toSource() zgodnie z tym o czym dyskutowałeś z Demonical Monkiem

}

(kod poglądowy -- pisany z palca, nie testowany)

Jeśli masz gwarancję, że SaveCookie będzie wywoływane za każdym razem z nowym ID, to możesz ominąć parę rzeczy. Np. sprawdzanie, czy dane ciasteczka zawierają już bieżące ID.

Trochę głupio to wygląda, że tłumaczę w komentarzach konstrukcje typu zmienna = zmienna || domyślna wartość. W komentarzach używam słowa "jeśli", a w instrukcji przypisania nie ma żadnego if-a. Wydaje się to więc nieczytelne, skoro muszę to tłumaczyć. Jednak w JavaScripcie użycie operatora || zamiast if-a jest jednym z prostych idiomów, które po prostu trzeba opanować (nie wprowadzałem już innych idiomów, takich jak wydajniejszy zapis pętli for, coby Ci nie mącić).

Osobiście jestem praktycznie pewien, że nie potrzebujesz zapisywać do ciasteczka tablicy IDs. W JavaScripcie istnieje pętla for-in, która pozwala przetworzyć wszystkie własności danego obiektu. Nie musisz mieć tych własności spisanych w tablicy IDs.

Zauważ proszę, że jeśli tej funkcji przekażesz jako pierwszy parametr ciąg 'IDs', to zniszczy to zapisywaną tablicę ID. Nie rozwiązałem tego problemu w tym kodzie coby Ci nie gmatwać, ale jak chcesz, to mogę Ci wytłumaczyć obejście (po wyeliminowaniu tablicy IDs to w ogóle nie będzie już problemem).

O coś takiego Ci chodziło, czy źle zrozumiałem?

0

Bardzo dziękuję za tak wyczerpującą odpowiedź. Wcześniej pisałem, że nie znam javascript, a nie że nie umiem programować więc wiem co to jest instrukcja for, if itd :) Brakowało mi wiedzy dotyczącej obiektów i ich obsługi w javascript. Tym niemniej masz rację, że powinienem uprzedzić, że kod jest poglądowy.

0

Jeszcze jedno. Coś mi to nie chce działać wyświetlanie. Czy mógłbyś napisać for'a w którym wyświetlisz wartości param1 dla wszystkich elementów? nie wiem czy źle się odwołuję czy coś innego pokręciłem.
I rzeczywiście jeżeli można wyświetlić to w taki sposób to nie potrzebuję przechowywać IDs :)

1

Generalnie for-in wygląda tak:

for (var nazwaWłasności in obiekt) {
  alert('We własności o nazwie ' + nazwaWlasności + ' jest wartość: ' + obiekt[nazwaWlasności]);
}

W Twoim przypadku, for-in wyglądałby tak:

for (var id in cookieData) {
  var param1 = cookieData[id].param1;
  alert(param1);
}

W praktyce, z pewnych powodów trzeba zastosować jedną sztuczkę. Otóż pętla for-in iteruje po wszystkich własnościach obiektu. Nie tylko tych, które dodał sobie programista (czyli poszczególnych ID, u Ciebie), ale również niektórych z tych zdefiniowanych w języku oraz wszystkich tych, które dodał programista do tzw. prototypu danego obiektu. Wytłumaczenie tego jest w książce, ale w uproszczeniu chodzi o to, że dla obiektu { foo: 123, bar: 456 } pętla for-in iterowałaby nie tylko po własnościach foo oraz bar, ale mogłaby również iterować po metodach obiektu, takich jak clone(), toString() itp. To nie do końca tak, bo metody i własności obiektu dodawane przez język chronione są przez wewnętrzną własność isPropertyEnumerable, ale to już są bardziej zaawansowane kwestie.

W każdym razie, możesz się przed tym zabezpieczyć używając metody obiekt.hasOwnProperty(nazwaWłasności). Metoda ta zwróci true, jeśli bezpośrednio do obiektu obiekt programista wsadził własność o nazwie nazwaWłasności. Jeśli własność ta jest metodą obecną w języku JavaScript lub własność ta została zdefiniowana przez programistę w prototypie obiektu, czyli nie bezpośrednio w obiekcie, to metoda hasOwnProperty zwróci false.

Koniec końców, używa się tego, by zbudować kuloodporną pętlę for-in:

for (var id in cookieData) {
  if (cookieData.hasOwnProperty(id)) {
    var param1 = cookieData[id].param1;
    alert(param1);
  }
}

Osobiście, podczas używania pętli for-in polecam zapisać wartość bieżącej własności w osobnej zmiennej. Dobrze widać to na przykładzie, gdy obiekt traktujemy jako mapę z parami klucz/wartość, bo w istocie obiekty w JavaScripcie są mapami. Wtedy wygląda to tak (pomijam hasOwnProperty dla czytelności):

for (var key in map) {
  var value = map[key];
  alert('Pod kluczem ' + key + ' siedzi wartość ' + value);
}

W Twoim przypadku, podsumowując to wszystko, mielibyśmy:

for (var id in cookieData) {
  if (cookieData.hasOwnProperty(id)) {
    var cookieDataForCurrentId = cookieData[id];
    var param1 = cookieDataForCurrentId.param1;
    var param2 = cookieDataForCurrentId.param2;
    alert('Parametr pierwszy: ' + param1 + ', parametr drugi: ' + param2);
  }
}

JavaScript posiada kilka błędów i dlatego właśnie polecam tę nieszczęsną książkę. Ten język jest inny niż większość innych, ma dziedziczenie prototypowe, jest prostym -- ale potężnym -- językiem funkcyjnym. Zapis literałów obiektowych i tablic (czyli te {} oraz []) jest świetny (z drobnym wyjątkiem) i stanowi podstawę do języka opisu danych JSON. Ogólnie da się z tego wszystkiego wygodnie i sprawnie korzystać, ale jeśli próbujesz to zrobić wyrywkowo to możesz trafić na niezrozumiałe utrudnienia. Ja staram się jakoś wytłumaczyć np. czemu używamy hasOwnProperty, ale od tego posty się trochę wydłużają... ;)

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