Przypsianie kilku zmiennym wartości z tablicy

1
  1. Chciałbym zapytać, czy ten kod ma jakiś cel obecnie?
let arrAnswerVaranty = ['a', 'b', 'c', 'd'];

Jeśli nie ma, to ja bym go usunął, żeby nie robić bałaganu. Później można go zawsze dodać.

  1. Myślę, że jeszcze jedna funkcja się nada. Od razu ją zaimplementujmy. Będzie ona podobna w założeniu do getRandomAnswers – będzie losować pytanie i je zwracać. Wiem, że już podobna była, ale napiszmy ją od początku, żeby wszystko było jasne.
    2.1. Niech nazywa się getRandomQuestion.
    2.2. Nie powinna mieć parametrów.
    2.3. Umieść w niej następujący kod. To nie jest nowy kod, już go wcześniej pisałeś. Zrobiłem tylko dwie zmiany: zmieniłem nazwę zmiennej randomQuestIndex na currentRandomIndex, żeby była bardziej intuicyjna, oraz przeniosłem deklarację tej zmiennej przed pętlę, żeby działanie kodu było bardziej intuicyjne:
var currentRandomIndex;
do {
    currentRandomIndex = Math.floor(Math.random() * questArr.length);
} while (currentRandomIndex === randomIndex);
randomIndex = currentRandomIndex;

2.4. Dodatkowo niech ta funkcja zwraca element tablicy questArr o indeksie currentRandomIndex.

0

A tą zmienną jslet oldQuestionIndex = -1; usunąć czy zmieniłeś jej nazwe na var currentIndex bez żadnej wartości?

0

To jest mój dotychczasowy kod https://jsfiddle.net/8hn2m4vz/. Nie jestem tylko pewien co do zmiennej js let oldQuestionIndex = -1 ponieważ nie wiem czy ją usunąłeś czy zmieniłeś jej nazwe?

1

Trochę się nie zrozumieliśmy. :)

  1. Sama zmienna currentRandomIndex nie jest nowa. Nazywała się tylko inaczej – randomQuestIndex. Ponadto w kodzie była deklaracja tej zmiennej wraz z inicjalizacją (w jednej linijce), a ja te dwie rzeczy rozdzieliłem. Stąd pojawiła się w kodzie ode mnie instrukcja var currentRandomIndex; – i powinieneś ją umieścić w funkcji getRandomQuestion, tak samo jak pętlę (a nie poza funkcją).
  2. Instrukcja let oldQuestionIndex = -1; powinna zostać na swoim miejscu, tak, jak była.
  3. Funkcja showRandomQuestion powinna zostać na swoim miejscu, tak, jak była (a widzę, że ją usunąłeś).
  4. Funkcja getRandomQuestion to powinna być nowa funkcja.
0

Czy teraz jest ok https://jsfiddle.net/74vj3ckf/?

1

Jeszcze nie do końca: w funkcji getRandomQuestion masz dwie zmienne, randomQuestIndex oraz currentRandomIndex. Chodzi o to, żeby była tylko jedna – currentRandomIndex. Powinieneś więc zamienić linijkę

var randomQuestIndex = Math.floor(Math.random() * answers.length);

na

currentRandomIndex = Math.floor(Math.random() * answers.length);
0

Brakuje jeszcze zwracania przez funkcję getRandomQuestion elementu tablicy questArr o indeksie currentRandomIndex. Zauważ, że nazwa funkcji zaczyna się na get, a to sugeruje, że powinna ona coś zwracać.

I jak to już zrobisz, to dalej zaimplementujmy funkcję showRandomQuestion:

  1. Wywołaj w niej funkcję getRandomQuestion i zapisz wynik tego wywołania do zmiennej (sam wymyśl nazwę; postaraj się, żeby była w miarę opisowa).
  2. Przypisz tę nowo utworzoną zmienną do właściwości innerHTML obiektu headerQuestion.
0
  1. Błąd – linijka:
currentRandomIndex = Math.floor(Math.random() * answers.length);

powinna wyglądać tak:

currentRandomIndex = Math.floor(Math.random() * quizArr.length);
  1. Zapomniałem o jednej rzeczy w funkcji getRandomQuestion. Nie powinna ona zwracać "obiektu pytania" (bo nie ma to sensu dla jej obecnego przeznaczenia), tylko samo pytanie (ciąg znaków). Dlatego trzeba linjkę:
return quizArr[currentRandomIndex];

zamienić na:

return quizArr[currentRandomIndex].question;
  1. Literówka: instrukcję showRandomQuestions(); zamień na showRandomQuestion();
  2. Widzisz teraz pytanie po uruchomieniu kodu. :) Zmienia się ono na inne i losowe po naciśnięciu przycisku "Wyślij".

Przejdźmy od razu do implementowania funkcji getRandomVariants. Nie znalazłem kodu w tym wątku, który by odpowiadał dokładnie temu, co trzeba zrobić, więc od początku napiszemy:

  1. Funkcja powinna mieć jeden parametr – indeks "obiektu pytania".
  2. Losowanie odpowiedzi można zrobić na co najmniej dwa sposoby: 1) poprzez skopiowanie tablicy z odpowiedziami z obiektu pytania o podanym indeksie i w miarę losowania kolejnych odpowiedzi usuwanie z tej skopiowanej tablicy wylosowanych już odpowiedzi; 2) poprzez stworzenie pustej tablicy i w miarę losowania kolejnych odpowiedzi dodawanie ich do niej. Moim zdaniem lepiej wybrać wariant nr 2, bo jest mniej podatny na błędy (nie wiem, czy potrzebujesz uzasadnienie). Algorytm powinien przebiegać tak:
    2.1. Tworzysz pustą tablicę answersIndices.
    2.2. Dla każdej odpowiedzi pytania o danym indeksie: (2.2.1.) losujesz indeks odpowiedzi dotąd, aż nie będzie on już obecny w tablicy answersIndices; (2.2.2.) dodajesz ten indeks do tablicy answersIndices.
  3. Funkcja powinna zwracać tablicę answersIndices.

Zamieszczę tu kod całej funkcji, bo zdaję sobie sprawę, że powyższy algorytm jest niezbyt czytelny. Jak czegoś nie rozumiesz, pytaj:

function getRandomVariants(id) { // Punkt 1
    const answersIndices = []; // Punkt 2.1
    for (const a of quizArr[id].answers) { // Cała pętla for to punkt 2.2
        let r = -1;
        do {
            r = Math.floor(Math.random() * quizArr[id].answers.length);
        } while (answersIndices.includes(r)); // Cała pętla do-while to punkt 2.2.1
        answersIndices.push(r); // Punkt 2.2.2
    }
    return answersIndices; // Punkt 3
}

Warto wspomnieć, że funkcja getRandomVariants zwraca tablicę indeksów, a więc trochę nienajlepiej odpowiada to jej nazwie. Ja jestem zdania, że ważniejsza jest spójność kodu niż intuicyjność, więc na razie nie będziemy tego ruszać. Po skończeniu całości możemy się zastanowić nad zmianą nazw.

0

Tak to wygląda https://jsfiddle.net/ymuj2ca0/. Co dalej?

0

Co do obecnego kodu:

  1. Zmieniłbym nazwę parametru funkcji getRandomVariants na questionIndex; uważam, że obecna nie jest intuicyjna; wolałbym uniknąć późniejszych pomyłek.
  2. Nazwa zmiennej powinna być answerIndices, a nie answerIndicies (zauważ brak ostatniej litery i; "indices" to jedna z form liczby mnogiej rzeczownika "index" -> https://www.diki.pl/slownik-angielskiego?q=index).
  3. Literówka w jednym miejscu: powinno być answersIndicies, a nie answerIndicies (zauważ literkę s po ciągu znaków answer).

Zanim zaczniemy wyświetlać odpowiedzi, trzeba poprawić dwie rzeczy:

  1. Funkcja getRandomQuestion powinna zwracać zmienną currentRandomIndex. Wiem, że wcześniej napisałem co innego, ale teraz uważam, że dla spójności kodu trzeba to zmienić. Z nazwą co prawda będzie taki sam problem, jak przy funkcji getRandomVariants (o czym wcześniej pisałem), ale nie ma co się teraz tym przejmować (spójność nad intuicyjność).
  2. Kod HTML: masz nieodpowiednie elementy oznaczone jako "etykiety". Żeby było intuicyjnie, to zrób tak, żeby elementy <label> miały tę wartość atrybutu id, co obecnie elementy <input>, a elementy <input> żeby miały tę wartość atrybutu id, co obecnie elementy <label>. Poza tym wartość atrybutu for elementów label trzeba zmienić na wartość atrybutu id elementów <input> po zmianie opisane w poprzednim zdaniu. Czyli, przykładowo:
<input type="radio" id="label-answer_A" name="answer" class="answer">
  <label id="a" for="label-answer_A"></label>

trzeba zmienić na

<input type="radio" id="a" name="answer" class="answer">
  <label id="label-answer_A" for="a"></label>
0

https://jsfiddle.net/s9bf21yv/ chyba coś jest nie tak?

2
  1. return answersIndicies; zmień na return answersIndices; (zauważ usunięcie ostatniej litery "i").
  2. Rzeczywiście jest nie tak, o tyle, że zapomniałem wcześniej powiedzieć, że za zmianą wartości zwracanej z funkcji getRandomQuestion powinna iść zmiana kodu w funkcji showRandomQuestion. A więc:
    2.1. Nazwę zmiennej displayQuestQiz zmień na displayQuestQizIndex.
    2.2. Stwórz nową zmienną questionObject i przypisz jej wyrażenie quizArr[displayQuestQizIndex].
    2.2. Właściwości innerHTML przypisz wyrażenie questionObject.question.

I po poprawieniu tych rzeczy możesz przejść do wyświetlania odpowiedzi:

  1. Stwórz nową zmienną variants.
  2. Właściwości innerHTML każdego z obiektów labelAnswerA, labelAnswerB, labelAnswerC i labelAnswerD przypisz wyrażenie questionObject.answers[variants[X]];, gdzie X zmieniaj na kolejne liczby: 0, 1, 2 oraz 3.
  3. Powinny wyświetlać się odpowiedzi, co kończyłoby nasz kod; podane wymagania funkcjonalne zostały zaimplementowane. :) (Przypomnę: tutaj są opisane -> Przypsianie kilku zmiennym wartości z tablicy). Jeśli będziesz mieć jeszcze pytania, pytaj.
0

Coś nie działa https://jsfiddle.net/5k17ghnw/. I czy mogę usunąć tą tablice arrAnswerVaranty bo i tak nigdzie jej nie wykorzystuje

0
  1. Zapomniałem napisać, że przedostatnie 2 punkty powinny zostać wykonane w funkcji showRandomQuestion (czyli zarówno przypisanie do zmiennej variants, jak i przypisanie do właściwości innerHTML).
  2. Zapomniałem napisać, że zmiennej variants trzeba przypisać wynik wywołania funkcji getRandomVariants z argumentem displayQuestQizIndex.

PS

  1. Jak najbardziej możesz usunąć tablicę arrAnswerVaranty. Okazała się nam nieprzydatna.
1

Tak to powinno wyglądać?https://jsfiddle.net/s6ocqh59/1/

0

Chciałem cie zapytać o ten kod https://jsfiddle.net/gvk5urzs/5/. Bo chce napisać pewną fukcjonalność że jeżeli użytkownik mi nie zaznaczy żadnej odpowiedzi to nie pozwalam mu przejść do następnego pytania. Po zaznaczeniu przechodzi dalej. Ja napisałem tylko taki poglądowy kod na temat jak ja to widze. Wiem że to jest jedna z prostszych funkcjonalności w tej aplikacji ale dla mnie każda linijka kodu jest niezwykle ważna nawet jeżeli wydaje się błacha i chce zapytać po prostu o rade czy taki kod nadaje się do tego co chce zaimplementować czy raczej nie bardzo. Czy byś coś dodał, zmienił badź ewentualnie coś usnął

1
  1. Jeśli chodzi o kod HTML, to widzę, że opuściłeś znaczniki <body> oraz </body>. Co prawda zgodnie z dokumentacją MDN jest to dopuszczalne (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body), ale myślę, że mógłbyś rozważyć, czy jednak nie pisać tych znaczników – dla czytelności.
  2. Jeśli chodzi o kod JavaScript, to kilka rzeczy:
    2.1. @szatkus wspomniał w komentarzu o zawężeniu selektora w wywołaniu metody document.querySelector do input[type="radio"]. Mógłby być zawężony; moim zdaniem jeszcze lepiej pobierać po klasie albo po ID. Niemniej w tym kodzie nie ma to znaczenia i rozumiem, że zrobiłeś tak dla prostoty kodu.
    2.2. @szatkus wspomniał w komentarzu o rozróżnieniu między metodami document.querySelector, a document.querySelectorAll. Ta pierwsza metoda pobiera pierwszy dopasowany element, ta druga pobiera wszystkie. W tym kodzie nie ma znaczenia, której użyjesz; ale ogólnie pamiętaj, że pobieranych elementów może być więcej niż jeden, a wtedy trzeba będzie użyć tej drugiej metody.
    2.3. Dla czytelności zmieniłbym nazwę zmiennej inputForm na input. Słowo "form" jest dla mnie zbyt ogólne, a poza tym samo słowo "input" pasuje do użytego selektora (którym jest właśnie input). W szczególności może się kiedyś zdarzyć, że będziesz mieć na stronie kilka formularzy, a w każdym z nich kilka elementów INPUT, i w takiej sytuacji być może każdy element trzeba będzie nazwać inaczej. Moim zdaniem nawet w tak prostym kodzie warto zawsze zmienne nazywać jak najbardziej czytelnie.
    2.4. Dla czytelności zmieniłbym nazwę funkcji checkValidate na validateIfChecked. W pierwszym przypadku można przeznaczenie funkcji odczytywać: "funkcja ma sprawdzać jakieś 'validate'", a w drugim: "funkcja ma walidować, czy coś jest 'checked'". A Tobie, jak myślę, chodzi o to drugie znaczenie.
0

Jaki jest problem że nie działa https://jsfiddle.net/16kpq7fu/? W złym miejscu daje return true i false?

1

Jest kilka błędów:

  1. Warunek sprawdzający zaznaczenie powinien wyglądać w ten sposób: input[i].checked === true (tzn. brakuje Ci odwołania do konkretnego elementu tablicy).
  2. Instrukcja return true jest umieszczona w dobrym miejscu. Natomiast w złym miejscu jest umieszczona instrukcja return false. Nie powinna być umieszczona w pętli, tylko zaraz za nią. Dlaczego? Ogólnie jeśli jest umieszczona w pętli, to pętla zostanie przerwana, zanim się zakończy. W Twoim przypadku logika działania funkcji validateIfChecked powinna być taka: "dla każdego elementu input[i] sprawdź, czy ten element jest zaznaczony; jeśli tak, zwróć true, a jeśli nie, kontynuuj sprawdzanie".
  3. W handlerze kliknięcia używasz operatora przecinka. Ten operator powoduje u Ciebie wykonanie obu funkcji i zwraca wartość ostatniej (zobacz jego dokumentację -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator). Jest to niepoprawne; poprawnie powinno być tak, że uzależniasz wyświetlenie następnego pytania od tego, co zwróci funkcja validateIfChecked, czyli kod podobny do poniższego:
if (validateIfChecked() === true) {
    // Wyświetl następne pytanie
} else {
    // Powiedz użytkownikowi, że musi coś zaznaczyć
}
0

Chciałbym jeszcze zaimplementować funkcjonalność że po odświeżeniu nie wyświetla się następne pytanie i że pole input type radio jest puste po odświeżeniu strony

0

Napisałem tak ale nie działa https://jsfiddle.net/pf4maowq/

0

To jest to https://jsfiddle.net/L5ukq69o/. Chce jeszcze popracować nad tym żeby po przeładowaniu strony nie zmieniało się pytanie i napisać sobie licznik i to by było na tyle jeśli chodzi o ten projekt

0

@piotrek1998: jeśli chcesz, by po przeładowaniu strony nie zmieniało się ostatnie pytanie, to kod musi wiedzieć, czy którykolwiek element input był zaznaczony. Wystarczy wartość boolean. Ale trzeba ją zapisywać gdzieś, np. w localStorage. Nie jestem jednak pewien, czy jest możliwe skorzystanie z localStorage w JSFiddle.

0

@piotrek1998: powinno to wyglądać w ten sposób, że:

  1. Zmieniasz kod
const displayQuestQizIndex = getRandomQuestion();

na następujący kod

let displayQuestQizIndex = -1;
if (sessionStorage.getItem('selected') === 'false') {
    displayQuestQizIndex = sessionStorage.getItem('lastQuestionIndex');
} else if (sessionStorage.getItem('selected') === 'true') {
    displayQuestQizIndex = getRandomQuestion();
    sessionStorage.setItem('lastQuestionIndex', displayQuestQizIndex);
    sessionStorage.setItem('selected', 'false');
}
  1. Poza tym trzeba dodać handler zdarzenia click dla każdego elementu o klasie answer, a w nim wywołać następujący kod:
sessionStorage.setItem('selected', 'true');

Możesz opakować powyższe wywołania metod obiektu sessionStorage w funkcje, ale zauważ, że trzeba ustawić dwie różne rzeczy w sessionStorage. W takim wypadku trzeba napisać dwie funkcje, każdą dla jednej rzeczy. Wyglądałoby to jakoś tak:

function setSSSelected(value) {
    sessionStorage.setItem('selected', value); // JSON.stringify jest niepotrzebne
}
function setSSLastQuestionIndex(value) {
    sessionStorage.setItem('lastQuestionIndex', value); // JSON.stringify jest niepotrzebne
}
0

To o czym piszesz tutaj Poza tym trzeba dodać handler zdarzenia click dla każdego elementu o klasie answer, a w nim wywołać następujący kod: to mogę wywołać w tym handlerze

btnSubmit.addEventListener('click', function() {
	
	if (validateIfChecked() === true) {
		showRandomQuestion();
		return true;
	}
	return false;
});

czy musze robić nowy?

1

W zasadzie powinienem był napisać: do każdego elementu przechowywanego w tablicy input.

Następujący kod:

input[i](sessionStorage.setItem('selected', 'true'));

jest niepoprawny. Oznacza on: "wywołaj funkcję input[i]" – a przecież input[i] nie jest u Ciebie funkcją. Poza tym to, o czym pisałem, należy zrobić w zasięgu globalnym, a nie w handlerze kliknięcia na przycisk.

W związku z powyższym, kod powinien wyglądać tak:

for (let i = 0; i < input.length; i++) {
    input[i].addEventListener('click', function() {
        sessionStorage.setItem('selected', 'true');
    });
}

i powinien być umieszczony tuż przed ostatnią linijką (tą z wywołaniem showRandomQuestion()).

Poza tym usuń instrukcje return true i return false z handlera kliknięcia w przycisk (tylko z tego handlera). Nie są one poprawne w tamtym miejscu. PS A dlaczego nie są poprawne w tym handlerze? Dlatego, że nigdzie nie wykorzystujesz tej zwróconej wartości. Innymi słowy, w tym kodzie ten handler nie powinien nic zwracać.

0

Wszystko ładnie tylko z jakiegoś powodu otrzumuje komunikat quizArr[questionIndex] is undefiend

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