Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> [AJAX][jQuery]dodanie pętli
phpuser88
post 6.05.2022, 20:48:08
Post #1





Grupa: Zarejestrowani
Postów: 66
Pomógł: 1
Dołączył: 4.05.2019
Skąd: PHP5.6

Ostrzeżenie: (0%)
-----


jQuery jest trudniejsze i bardziej skomplikowane niż się wydawało, a wydawało się naprawdę trudne... ohno-smiley.gif
Pomijam fakt, że w sieci brak zgrabnego gotowca (jQuery, AJAX, PHP5.6) najprostszego systemu głosowania +/- 1 dla np. komentarza. (albo nie umiem szukać)

Na podstawie kilkunastu różnych kodów z Internetu zlepiłem jeden funkcjonalny skrypt, który (po kliknięciu) ma za zadanie:
1. przyznać ocenę +1 (tj. zwiększyć zawczasu, sztucznie licznik aktualnej oceny +1)
a) wysłać ID_komentarza z rodzajem_oceny(+/-) do PHP i tam po weryfikacji zrobić Update SQL (po stronie PHP brak problemów)
2. sformatować kolorystycznie kliknięty button "plus" oraz usunąć możliwość kliknięcia w button "minus" za pomocą display:none;
3. wrzucić ocenionego komentarza (tj. ID_komentarza) do localStorage, żeby user wiedział co już ocenił.
4. sprawdzić ID_komentarza z localStorage i jeśli istnieje, to sformatować kolorystycznie na stałe. (tj. do czasu usunięcia pamięci lokalnej www)

Generalnie wszystko działa dla jednego komentarza. Siedziałem nad tym dwa dni i jestem pewny, że można to zrobić znacznie lepiej, ale składnia i jej logika mnie dobija więc będę wdzięczny za naprowadzenie w jaki sposób edytować kod, aby wrzucić w jakąś brzydal.gif pętle, która automatycznie pobiera i sprawdza (tj. formatuje jeśli oceniono) wszystkie wyświetlone komentarze (tj. ID_komentarza).

  1. $(document).ready(function() {
  2. $('.punkt').click(function () {
  3.  
  4. if ($(this).hasClass("current")) {
  5. // $("#1 .suma").text("Zagłosowano.");
  6. } else {
  7. var id_koment = $(this).parent("div").attr("id");
  8. var rodzaj = $(this).attr("class");
  9. var error = false;
  10.  
  11. //formatowanie
  12. if ($(this).hasClass("plus")) {
  13. $("#1 .1").css("color", "green");
  14. $("#1 .1").css("font-weight", "bold");
  15. $("#1 .0").css("display", "none");//likwiduje minusa
  16.  
  17. //plus jeden
  18. var suma = +$("#1 .sumai").val() + 1;
  19. $("#1 .sumai").val(suma);
  20.  
  21. //zapisanie na local
  22. localStorage.setItem('id_koment', id_koment);
  23.  
  24. //update
  25. $.ajax({
  26. type: "POST",
  27. url: "db.php",
  28. data: {
  29. id_koment: id_koment,
  30. rodzaj: rodzaj,
  31. csrf: <?php echo $_SESSION['key']; ?>
  32. }
  33. }).done(function (data) {
  34. console.log(data);
  35. });
  36.  
  37. }
  38.  
  39. else if($(this).hasClass("down")) {
  40. alert("głos -1");
  41. }
  42. //removes all the votes
  43. $(this).parent("div").children().removeClass("current");
  44.  
  45. if(!error) {
  46. $(this).addClass("current");
  47. } else {
  48. alert("jakis problem....");
  49. }
  50. }
  51. return false;
  52. });
  53. });
  54.  
  55. <div id="1" class="idkom1">
  56. <a class="punkt plus" href="#">
  57. <div class="1">plus +</div>
  58. </a>
  59.  
  60. <div class="suma">
  61. <input class="sumai" type="number" value="12">
  62. </div>
  63.  
  64. <a class="vote down" href="#">
  65. <div class="0">minus -</div>
  66. </a>
  67. </div>
  68.  
  69. var pobieramid = JSON.parse(localStorage.getItem("id_koment"));
  70. $("#"+pobieramid+" .plus").removeClass("plus"); //usuwam mozliwosc dodania kolejnej wartosci +1
  71. $("#"+pobieramid+" .0").css("display", "none");//likwiduje minusa
  72. $("#"+pobieramid+" .1").css("color", "red");
  73. $("#"+pobieramid+" .1").css("font-weight", "bold");
Go to the top of the page
+Quote Post
aras785
post 6.05.2022, 23:23:58
Post #2





Grupa: Zarejestrowani
Postów: 859
Pomógł: 177
Dołączył: 29.10.2009

Ostrzeżenie: (0%)
-----


Cześć,

ja bym zrobił coś takiego: https://jsfiddle.net/nh584c7f/

  1. <div data-comment-id="1" data-element="comment" class="comment">
  2. <a class="comment_button" href="#" data-action="up">
  3. <div class="1">plus +</div>
  4. </a>
  5. <div class="suma">
  6. <input class="sumai" type="number" value="1">
  7. </div>
  8.  
  9. <a class="comment_button" href="#" data-action="down">
  10. <div class="0">minus -</div>
  11. </a>
  12. </div>
  13. <div data-comment-id="2" data-element="comment" class="comment">
  14. <a class="comment_button" href="#" data-action="up">
  15. <div class="1">plus +</div>
  16. </a>
  17. <div class="suma">
  18. <input class="sumai" type="number" value="1">
  19. </div>
  20.  
  21. <a class="comment_button" href="#" data-action="down">
  22. <div class="0">minus -</div>
  23. </a>
  24. </div>
  25. <div data-comment-id="3" data-element="comment" class="comment">
  26. <a class="comment_button" href="#" data-action="up">
  27. <div class="1">plus +</div>
  28. </a>
  29. <div class="suma">
  30. <input class="sumai" type="number" value="1">
  31. </div>
  32.  
  33. <a class="comment_button" href="#" data-action="down">
  34. <div class="0">minus -</div>
  35. </a>
  36. </div>


  1. .comment {
  2. background: #ccc;
  3. padding: 10px;
  4. margin-bottom: 20px;
  5. }
  6.  
  7. .commented [data-action] {
  8. font-weight: bold;
  9. color: green;
  10. }
  11.  
  12. .commented__down [data-action="up"] {
  13. display: none;
  14. }
  15.  
  16. .commented__up [data-action="down"] {
  17. display: none;
  18. }


Kod
$(document).ready(function() {
  //$('[data-element="comment"]:not(.commented) [data-action]') - coś mi ten not nie działa stąd IF niżej
  $('[data-element="comment"] [data-action]').off('click').on('click', function(commentEvent) {
    commentEvent.preventDefault();

    let currentComment = $(this).closest('[data-element="comment"]');

    if (!currentComment.hasClass('commented')) {
      let action = $(this).attr('data-action');

      //tutaj tymczosow zmieniamy liczbę ocen
      currentComment.find('input').val(parseInt(currentComment.find('input').val()) + (('up' === action) ? 1 : -1));
      currentComment.addClass('commented').addClass('commented__'+action);

      $.ajax({
        type: "POST",
        url: "https://httpbin.org/post",
        data: {
          id_koment: currentComment.attr('data-comment-id'),
          rodzaj: action,
          csrf: 'test'
        }
      }).done(function(data) {
        //zatwierdzamy liczbę ocen z danymi z backendu
        //currentComment.find('input').val(data);
        addCommentToLocalStorage(currentComment.attr('data-comment-id'), action);
      });
    }
  });
});

if (getCommentFromLocalStorage()) {
    $.each(getCommentFromLocalStorage(), function(index, comment) {
      $('[data-element="comment"][data-comment-id="'+comment.commentId+'"]')
        .addClass('commented')
        .addClass('commented__'+comment.action);
  });
}

function getCommentFromLocalStorage() {
  return JSON.parse(localStorage.getItem("id_koment"));
}


function addCommentToLocalStorage(commentId, action) {
  let comments = getCommentFromLocalStorage();
  if (comments === null) {
    comments = [{'action': action, 'commentId': commentId}];
  } else if (!comments.includes(commentId)) {
    comments.push({'action': action, 'commentId': commentId});
  }

  localStorage.setItem("id_koment", JSON.stringify(comments));
}





Pozdrawiam

Ten post edytował aras785 6.05.2022, 23:30:52
Go to the top of the page
+Quote Post
phpuser88
post 7.05.2022, 04:35:30
Post #3





Grupa: Zarejestrowani
Postów: 66
Pomógł: 1
Dołączył: 4.05.2019
Skąd: PHP5.6

Ostrzeżenie: (0%)
-----


woow! @aras785, wielkie dzięki za poświęcony czas! nie testowałem Twojego rozwiązania, ale na pierwszy rzut oka wygląda konkretnie w porównaniu do moich wypocin. Mój problem przed chwilą (raczej) rozwiązałem w taki sposób, że inaczej zapisuje na localStorage, a na końcu inaczej odczytuje i generalnie na pierwsze testy wszystko hula jak należy:
  1. var data = existing ? existing + id_koment : id_koment;
  2. localStorage.setItem('id_koment', data+',');
  3. // ...
  4. pobieramid = localStorage.getItem("id_koment");
  5. let ids = pobieramid.split(",");
  6. for(let id of ids)
  7. {
  8. $("#"+id + " .plus").removeClass("plus");
  9. $("#"+id + " .1").css("color", "red");
  10. $("#"+id + " .1").css("font-weight", "bold");
  11. $("#"+id + " .0").css("display", "none");
  12. }


Ze wstępnych oględzin amatora wygląda na to, że jedna klasa (.commented) obsługuje formatowanie końcowe dla obu kliknięć, co defacto będzie prowadziło do błędnego kolorowania dla plusa bądź minusa - będę musiał to rozszyfrować aby dodać drugą klase. worriedsmiley.gif Zapisujesz też więcej danych w tablicy co jest jak najbardziej spoko, bo można zamknąć się w jednym kluczu, a później łatwo zweryfikować ocenę komentarza bez dodatkowego kombinowania z dwoma kluczami(+/-):
  1. {action: "down", commentId: "1"}
  2. {action: "down", commentId: "2"}
  3. {action: "down", commentId: "3"}

moje rozwiązanie było lżejsze zważając na limit 5242878 znaków dla jednego klucza, ale musiałbym kombinować z dwoma kluczami. ^^
  1. 1,2,3

Skrócę Twoją formę do: {a:"d",i:"1"} i z przyjemnością przygarnę cały wzór pod grunt do budowy. biggrin.gif

A tak jeszcze z ciekawości odnośnie wydajności aplikacji po stronie SQL & PHP....
1. Lepiej za każdym razem Insertować na nowo i później pojedynczo zliczać każdą ocenę dla ID_kom
2. Czy lepiej Updatować jeden dany ID_kom o oceny?
Osobiście obstaje przy rozwiązaniu 2. ale wole się upewnić.
Niby insert jest szybszy i można do niego dodać id_usera, który głosował co jest na plus przy statystykach, ale z drugiej strony będzie więcej danych i trzeba będzie liczyć by uzyskać sume ocen, a to też będzie swoje kosztować.

Jeszcze raz wielkie dzięki!

Ten post edytował phpuser88 7.05.2022, 04:47:52
Go to the top of the page
+Quote Post
aras785
post 7.05.2022, 11:16:36
Post #4





Grupa: Zarejestrowani
Postów: 859
Pomógł: 177
Dołączył: 29.10.2009

Ostrzeżenie: (0%)
-----


Cześć,

jeśli chodzi o klase .commeted to dodałem jeszcze tam: .commented__up i .commented__down (zmienna action) smile.gif

Co do pytań to zdecydowanie nr. 2, a wydajnością się nie przejmuj, gwarantuje Ci, że przy takich prostych zliczeniach nic będzie to działało błyskawicznie. Zapisuj IP i jakieś nagłówki aby w przyszłości móc ew. blokować spam w komentarzach biggrin.gif


ps. wrzuciłem tez link do jsfiddle gdzie masz działający przyklad

Pozdrawiam
Go to the top of the page
+Quote Post
phpuser88
post 10.05.2022, 17:05:35
Post #5





Grupa: Zarejestrowani
Postów: 66
Pomógł: 1
Dołączył: 4.05.2019
Skąd: PHP5.6

Ostrzeżenie: (0%)
-----


Cześć,

Taaaak specool.gif dotarłem do tego z godzine po opublikowaniu posta:
  1. .commented__down [data-action="down"] {
  2. color:red;
  3. }


Potencjalne problemy z DDoS'em przy głosowaniu/pisaniu planuje rozwiązać wprowadzając twardy i miękki limit w taki sposób, że stworze osobną tabele z id_user, id_kom, timestamp
Miękki limit: to możliwość oddania 20 głosów na każdą godzinę bez problemów, a każdy kolejny głos >20 będzie można oddać 1x/min.
Twardy limit: to max. 60 głosów na godzine.
Później w ramach rozwoju dorzucę jeszcze sprawdzanie jaki user często osiąga limity żeby sprawdzić != BOT.

Twoje rozwiązanie jest jak Graal, którego szukałem przed napisaniem tematu. Konkretne i dość zrozumiałe dla amatora jQuery. Świetny przykład do nauki na start, który rozwiązuje w lepszy sposób aktualne zadanie, dziękówa! thumbsupsmileyanim.gif

Dopisano 10.05.22 & 18:20:

Nie wydaje mi się aby był sens tworzenia nowego tematu, skoro kolejne dwa pytania dotyczą tematu. Więc pozwolę sobie dopytać tu (najwyżej @nospor mnie rozstrzela^^).
1. Czy powinienem obawiać się wstrzyknięcia kodu z localStorage do jQuery, który odbiera i później powierzchownie przetwarza zawartość?
  1. if (getCommentFromLocalStorage()) {
  2. $.each(getCommentFromLocalStorage(), function(index, comment) {
  3. $('[data-element="comment"][data-comment-id="'+comment.commentId+'"]')
  4. .addClass('commented')
  5. .addClass('commented__'+comment.action);
  6. });
  7. }
  8. function getCommentFromLocalStorage() {
  9. return JSON.parse(localStorage.getItem("id_koment"));
  10. }

Czytałem że niby obróbka json'em jest bezpieczna, ale nie siedzę w JS i nie wiem czy nie trzeba dla pewności czymś dodatkowym tego przefiltrować. Obstawiam że nie trzeba i kilka prób potwierdziło to przekonanie, ale wole zadać głupie pytanie niż później żałować.

2. Rozterka wydajnościowa, przykładowo User klika "plus" i PHP za pomocą Ajax'a robi UPDATE - jeżeli jest zalogowanych 1000 Userów i każdy z nich zacznie updatować baze kilkanaście razy z rzędu, to raczej racjonalnym wydaje się być założenie przymulenia hostingu, mam rację? Czy można ten problem jakoś obejść? istnieją jakieś sposoby? przeszło mi przez myśl by "wysłane głosy" odczytywać z localStorage 1x/10min i robić zbiorowy update, ale to raczej nie rozwiąże problemu. Ostatnio gdzieś czytałem o mechanizmie składowania memory w mysql - może lepiej jest robić tego typu update w tabeli memory, a następnie 1x/24h z tabeli memory do zwykłej(właściwej) tabeli, gdy ma się do dyspozycji 1Ghz + 2GB RAM? doświadczone osoby z pewnością znają odpowiedź, a ja chętnie skorzystam z możliwie jak najwydajniejszego sposobu kosztem wyświetlania aktualnych danych dla usera z opóźnieniem. Tutaj jeszcze rozważam wykupienie kolejnego hostingu i korzystania z dwóch osobnych baz danych na jednym hostingu, gdzie jedna(zewnętrzna) baza będzie odpowiadać za aktualne update i wyświetlanie "ocen" w trybie natychmiastowym, a druga baza odpowiadałaby za inne działania - czy przyniesie to znacznie lepszy rezultat jak się wydaje i czy taka hybryda ma racje bytu?

Ten post edytował phpuser88 10.05.2022, 17:20:06
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 28.04.2024 - 00:37