Daj Się Poznać #9 Ekran wynikowy, czyszczenie inputów


W tej serii tworzymy aplikację AngularJS służącą do sprawdzania swojej umiejętności obliczania makroskładników "na oko". Jesteśmy już na półmetku, ponieważ aplikacja jest już prawie ukończona. Dopracowujemy teraz detale, których zabrakło w poprzednich częściach. Zajmiemy się ekranem wynikowym naszej aplikacji, a później zastanowimy się, jak sprawić by nasze formularze nie były wypełnione po zmianie produktu. Zaczynajmy!

Jeśli pobrałeś już moje repozytorium z Githuba, co opisałem w poprzednim poście to możesz teraz przeskoczyć do kolejnego commita, który pokaże Ci kod z tego posta:
$ git checkout 18c28cdeaebca64473a1c0271544915bf66a0be1

# Wyświetlanie podsumowania gry

Jednym z zadań naszej gry, poza wyświetleniem wyniku po każdym pokazanym produkcie mogłoby być główne podsumowanie. Dlatego stworzyłem funkcję, która zbiera nasze dane przez cały quiz. Na końcu, w momencie kiedy widzimy ekran końcowy, ponad przyciskiem "play again" wyświetlimy tekst, który pokaże nasze łączne wyniki przez całą grę. Musimy się też zastanowić nad stylowaniem aplikacji w taki sposób, żeby tło ekranu końcowego nie utrudniało przeczytania tekstu.

Na początek, w pliku controller.js komponentu, w konstruktorze stworzymy sobie tablice wyników this.result, którą wypełnimy zerami, żeby bez problemu dodawać wyniki po kolejnych pytaniach.

 
constructor(productsList, GetJson) {
    "ngInject";
    this.productsList = productsList;
    this.GetJson = GetJson;

    this.id = 0;
    this.quizEnd = true;
    this.inProgress = false;
    this.Res = [];
    this.id = 0;
    this.name = "";
    this.kcal = "";
    this.protein;
    this.carb;
    this.fat;
    this.img = "";
    this.answerMode = false;
    this.result = [0,0,0,0];

    this.init();
  }

Musimy dodać kilka linijek do funkcji c.check(), która odpala się w momencie, kiedy wysyłamy nasz formularz:

 
<h2></h2>
<img ng-src="/assets/">
<p>Kcal:</p><input type="number" ng-model="c.macro1">
<p>Białko:</p><input type="number" ng-model="c.macro2">
<p>Węglowodany:</p><input type="number" ng-model="c.macro3">
<p>Tłuszcz:</p><input type="number" ng-model="c.macro4">
<button class="nextBtn" ng-click="isFlipped=!isFlipped; c.check();" ng-show="c.answerMode">Submit</button>

Funkcja c.check():

 
check(){
  let i = 0;
  let test = (modelData, viewData) => {
    if(!viewData) return "";
    if(modelData == viewData) return "idealnie!";
    this.result[i++] += viewData - modelData;
    return modelData > viewData ? modelData - viewData + " za mało" : viewData - modelData + " za dużo";
  };
  this.Res = [];
  this.answerMode = false;
  this.Res[0] = test(this.kcal, this.macro1);
  this.Res[1] = test(this.protein, this.macro2);
  this.Res[2] = test(this.carb, this.macro3);
  this.Res[3] = test(this.fat, this.macro4);
}

Ze zmian jakich dokonaliśmy w tym fragmencie kodu, najłatwiej można zauważyć linijkę kodu zaczynającą się this.result[i++], jednak zanim do niej przejdziemy, musimy stworzyć sobie zmienną lokalną, stworzoną przez let, zainicjalizowaną zerem, czyli pierwszym elementem tablicy. Następnie, kiedy wykona się ta linia kodu, komórka tablicy o wartości [i] zostaje zwiększona o daną wartość a następnie zmienna i zostaje zwiększona o jeden. Wartość, którą dodajemy do komórki, to wartość podana przez użytkownika, pomniejszona o prawdziwą wartość produktu.

Jednak musimy pamiętać o jeszcze jednej rzeczy. W tym momencie po wduszeniu przycisku "play again", wartość tablicy pozostawałaby taka sama, a powinniśmy ją wyzerować. Dlatego dodamy zerowanie do funkcji reset().

 
reset() {
  this.inProgress = false;
  this.score = 0;
  this.result = [0,0,0,0];
  this.start();
}

Musimy teraz wyświetlić naszą tablice na ekranie "play again".

 
<div class="container" ng-class="{ 'start__outer' : c.quizEnd }">
  <div ng-show="c.quizEnd" class="midButton midButton--fin">
    <div class="midButton--white">
      <h3>Twoje makro na koniec dnia:</h3>
      <p>Kalorie: { {c.result[0]} }</p>
      <p>Białko: { {c.result[1]} }</p>
      <p>Węglowodany: { {c.result[2]} }</p>
      <p>Tłuszcze: { {c.result[3]} }</p>
      <h1>Mistrz Makro</h1>
      <form ng-submit="c.reset()">
        <button>Play again</button>
      </form>
    </div>
  </div>
</div>

Do kodu wyświetlającego się po zakończeniu gry, dodaliśmy wyświetlanie łącznych wyników dla każdego makroskładnika i kalorii. Dodaliśmy także diva z klasą class="midButton--white", dzięki niemu, będziemy mogli stworzyć tło pod naszymi wynikami. Troszkę wyżej dodana jest też klasa class="midButton midButton--fin", dzięki której zmienimy margines, który domyślnie powinien być taki sam jak w ekranie tytułowym, jednak przeszkadzał by w wyświetlaniu wyników.

W pliku style.less, znajdującym się w folderze z komponentem nadajemy naszemu divowi style:

 
.midButton--white{
  background-color: rgba(255, 255, 255, 0.9);
  padding-top: 10px;
}
.midButton--fin{
  padding-top: 120px;
}

dla klasy .midButton--white nadajemy biały kolor tła o przezroczystości 0.9. Dodajemy także padding-top: 10px;, żeby nasze tło nie przylegało równo z tekstem.

Tak prezentuje się ekran końcowy:

Ekran końcowy play again

Wyniki oczywiście opisują rozbieżności w stosunku do zaplanowanej pulii kalorii i rozkładu makroskładników.

# Czyszczenie inputów

Wcześniej pisząc aplikację, nie dodaliśmy tagu form tam, gdzie wduszaliśmy przycisk oraz wysyłaliśmy wypełnione, bądź nie inputy.

 
<div class="face front"> 
  <form name="c.MacroForm">
    <h2></h2>
    <img ng-src="/assets/">
    <p>Kcal:</p><input type="number" ng-model="c.macro1">
    <p>Białko:</p><input type="number" ng-model="c.macro2">
    <p>Węglowodany:</p><input type="number" ng-model="c.macro3">
    <p>Tłuszcz:</p><input type="number" ng-model="c.macro4">
    <button class="nextBtn" ng-click="isFlipped=!isFlipped; c.check();" ng-show="c.answerMode">Submit</button>
  </form>
</div> 

Nasz formularz nazwalismy c.MacroForm.

Niestety, w tym momencie, wpisane przez nas makroskładniki nie znikają z inputów, dlatego musimy przy każdym nowym pytaniu najpierw je wymazać. Żeby to zmienić, stworzymy funkcję, która będzie ustawiała puste wartości w naszym formularzu. Funkcję nazwiemy formReset():

 
formReset(){
  this.MacroForm.$setPristine();
  this.macro1 = "";
  this.macro2 = "";
  this.macro3 = "";
  this.macro4 = "";
}

Formularz nazwany w pliku HTML c.MacroForm, obsługiwany w pliku js jest jako this.MacroForm. Ustawiamy wartość $pristine funkcją $setPristine, dzięki czemu wiemy że nasz formularz jest wyczyszczony, jednak nie daje to takich rezultatów jak byśmy chcieli. Musimy jeszcze przypisać do naszych wartości ng-model inputów pusty ciąg znaków. Dopiero po takim zabiegu, nasz formularz będzie wyczyszczony, kiedy pojawi się kolejne pytanie o produkt.

Funkcje formReset() moglibyśmy wywołać w funkcji check(), jednak na ekranie wynikowym, bezpośrednio po pytaniu, pojawiłyby się puste wartości. Jako że aktualne wartości formularza są nam nadal wtedy potrzebne, nie możemy wywołać tam tej funkcji.

Rozwiązaniem jest funkcja nextQuestion() wywołująca się po każdym pytaniu.

 
nextQuestion() {
  this.id++;
  this.formReset();
  this.getQuestion();
}

Zwiększamy id, żeby pobrać kolejny element z tablicy obiektów, czyścimy formularz i wywołujemy funkcję pobierającą nowy produkt.

Published: May 29 2017

blog comments powered by Disqus