Ładowanie danych z serwera

W kolejnej części przygody z Knockout’em, dziś poruszę temat związany z wysyłaniem i odbieraniem danych z serwera za pomocą AJAX. Do pobierania danych można użyć wiele różnych JavaScriptowych frameworków którę potrafią wysyłać i odbierać dane w postaci JSON tutaj zostawię dowolność, ja posłużę się zapytaniami jQuery $.getJSON() i $.post().

Tworzę nowy plik HTML do integracji Knockout.js/AJAX.

<html>
 <head>
    <title>Dane z zewnątrz</title>
    <meta charset='utf-8' />
    <link rel='stylesheet' href='style.css' />
 </head>
 <body>
   <h1>Dane z zewnątrz</h1>
   <form action="#" method="post">
     <p>First name: <input data-bind='value: firstName' /></p>
     <p>Last name: <input data-bind='value: lastName' /></p>
     <div> Ulubione jedzenie:
       <select data-bind='options: activities, value: favoriteHobby'></select>
     </div>
     <p>
       <button data-bind='click: loadUserData'>Wczytaj dane</button>
     </p>
   </form>
   <script type='text/javascript' src='knockout-2.1.0.js'></script>
   <script type='text/javascript' src='jquery-1.7.2.js'></script>
   <script type='text/javascript'>
   function PersonViewModel() {
     var self = this;
     self.firstName = ko.observable("");
     self.lastName = ko.observable("");
     self.activities = ko.observableArray([]); 
     self.favoriteHobby = ko.observable(""); 
   }
   ko.applyBindings(new PersonViewModel());
   </script>
 </body>
</html>
 

Jest to prosty formularz, który pozwoli wysyłać dane i je otrzymywać z serwera. Pamiętać należy o dołączeniu biblioteki JQuery.

Wczytanie danych z serwera

W pliku HTML widać, że wartości observables są puste dlatego w tej części, będziemy ładować dane z serwera za pomocą metody $.getJSON() aby mogły one wyświetlić informacje.
Dla przycisku „wczytaj dane” dodajmy kod JavaScript, który wyślę żądanie do serwera, poniżej kod:

self.loadUserData = function() {
  $.getJSON("get-user-data", function(data){
    alert(data.firstName);
  });
}

Łańcuch znaków „get-user-data” powinien być ścieżką do skryptu. Tak długo, jak do pobierania danych będziemy używać JSON, możemy użyć dowolnego języka, który potrafi wysyłać I pobierać żądania do serwera. Dla naszego wyniku powinniśmy otrzymać wartość JSON, która wygląda następująco:

{
  "firstName":"Przemek",
  "lastName":"Nyweron",
  "activities":
  [
    "Banan",
    "Karkówka",  
    "Naleśnik"
  ],
  "favoriteHobby":"Piłka nożna" 
}

Metoda $.getJSON() automatycznie przetłumaczy łańcuch znaków w obiekt JavaScript. Zaktualizujmy nasz ViewModel:

self.loadUserData = function() {
  $.getJSON("/get-user-data", function(data) {
    self.firstName(data.firstName);
    self.lastName(data.lastName); 
    self.activities(data.activities);
    self.favoriteHobby(data.favoriteHobby);
  });
}

Aby powyższe wczytywanie danych zadziałało, ja użyłem programu xampp aby uruchomić lokalny serwer.
Po kliknięciu „wczytaj dane” $.getJSON() załaduje dane z serwera i użyje tych danych do zaktualizowania zmiennych observerable w ViewModel. Knockout.js automatycznie aktualizuję pola.

Zapisz dane

Aby zapisać dane w postaci JSON, użyjemy metody $.post(). Warto zwrócić uwagę na to, że nie można użyć standardowego serializera JSON, aby z konwertować obiekt do łańcucha znaków, ponieważ ViewModel używa observable zamiast normalnych właściwości JavaScript. Warto pamiętać, że observables są funkcjami, więc próba serializacji ich i wysyłanie wyniku do serwera może powodować nie oczekiwane wyniki. Na szczęście Knockout.js dostarcza proste rozwiązanie tego problemu ko.toJSON() zamienia wszystkie właściwości obiektu observable z ich obecnymi wartościami i zwraca łańcuch znaków w postaci JSON.

Teraz utworzymy inny przycisk na stronie i nazwiemy go „Zapisz dane”, połączymy go z metodą saveUserData() pochodzącym z ViewModel. Teraz zobaczymy JSON wygenerowany przez ko.toJSON():

self.saveUserData = function() {
  alert(ko.toJSON(self));
}

Klikając przycisk zobaczymy obecne dane w polach przekształcone na łańcuch znaków JSON. Teraz pozbędziemy się wszystkich naszych observables, i wyślemy dane do serwera:

self.saveUserData = function() {
  var data_to_send = {userData: ko.toJSON(self)};
  $.post("/save-user-data", data_to_send, function(data) {
    alert("Saved data in server");
  });
}

Powyższy kod wysyła dane w postaci JSON w podanej ścieżce do pliku albo bazy danych, albo gdziekolwiek po stronie serwera, to już zależy od nas.

Mapowanie danych do ViewModels

Mechanizm wczytywania i zapisywania danych w powyższych dwóch przykładach przedstawia wszystko, czego potrzebujemy do tworzenia strony, pozwalającej zarządzać danymi po stronie serwera. Ale mapowanie danych ręcznie do observable może być nieco żmudne, jeżeli mamy do dyspozycji zdecydowanie więcej danych niż tylko kilka właściwości.

Knockout.js dostarcza mapowanie, które rozwiązuje problem ręcznego przypisywania. Dzięki mapping Knockout.js automatycznie mapuje obiekty JSON ładowane z serwera do ViewModel observables. Esencją tego podejścia jest generyczna wersja naszej metody odczytu.

Aby użyć mapping trzeba dołączyć odrębny skrypt z knockout.mapping-latest.js

<script type='text/javascript' src='knockout.mapping-latest.js'></script>

Teraz przekształcimy nasz PersonViewModel. Metoda jQuery $.getJSON() pobiera dane z serwera, a następnie generuję dynamiczne mapowanie observables.

<script type='text/javascript'>
$.getJSON("/test/load.json", function(data) {
  var viewModel = ko.mapping.fromJS(data);
  ko.applyBindings(viewModel);
}
</script>

Po uruchomieniu aplikacja załaduje dane natychmiastowo, wysyłając żądanie AJAX inicjalizując dane. Powyższa wersja powinna zwrócić taki sam wynik jak pierwsza wersja „Wczytanie danych z serwera”. Raz wczytane dane są tworzone jako ViewModel przez ko.mapping.fromJS(). Odpowiada to, za tworzenie czystego obiektu JavaScript generowanego przez skrypt zamieniając każdą właściwość na observable. Poniżej pełny kod automatycznego ładowania danych i mapowania.

<html>
<head><meta charset='utf-8' /></head>
<body>
    <form action="#" method="post">
        <p>First name: <input data-bind='value: firstName' /></p>
        <p>Last name: <input data-bind='value: lastName' /></p>
        <div> Ulubione jedzenie:
            <select data-bind='options: activities, value: favoriteHobby'></select>
        </div>
    </form>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js'></script>
    <script type='text/javascript' src='knockout.mapping-latest.js'></script>
    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
	
<script type='text/javascript'>
$.getJSON("/test/load.json", function(data) {
	var viewModel = ko.mapping.fromJS(data);
	ko.applyBindings(viewModel);
});		
function PersonViewModel() {
	var self = this;
	self.firstName = ko.observable("");
	self.lastName = ko.observable("");
	self.activities = ko.observableArray([]); 
	self.favoriteHobby = ko.observable("");
	self.saveUserData = function() {
}
</script>
</body>
</html>

 
Pozdro 🙂
 

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

*