Daj Się Poznać #4 OOP. Model w AngularJS


W poprzednich częściach projektu Mistrz Makro, pisanego w AngularJS stworzyliśmy wstępny szablon projektu, wyjaśniliśmy jak korzystać z Gita, zrozumieliśmy czym jest i do czego służy JSON, dowiedzieliśmy się co to MVC i zaimplementowaliśmy kontroler oraz serwis, które pozwoliły wyświetlić nam odebrane z JSON dane w konsoli. W dzisiejszej, czwartej już części, skupimy się na tym żeby umieścić nasze dane w modelu, żeby w kolejnej części dyrektywa tworząca quiz mogła z nich swobodnie korzystać. Zaczynajmy!
$ git checkout 1b3cb2d8eee6994d93ad28fd3f6ce037b0b6a771
# Tworzymy model dla makroskładników
AngularJS to framework MVC, czyli Model, Widok oraz Kontroler. Zajmiemy się tym razem Modelem, czyli przechowywaniem danych aplikacji. Na początek, musimy stworzyć serwis, w którym będzie zapisany pojedyńczy produkt:
(function() {
'use strict';
angular
.module('quizProject')
.service('Macro', MacroModel);
function MacroModel() {
var Macro = function(id, name, kcal, protein, carb, fat, img) {
this.id = id || 0;
this.name = "";
this.kcal = kcal || 0;
this.protein = protein || 0;
this.carb = carb || 0;
this.fat = fat || 0;
this.img = img || "";
}
Macro.prototype = {
setId: function(id) {
this.id = id;
},
setName: function(name) {
this.name = name;
},
setKcal: function(kcal) {
this.kcal = kcal;
},
setProtein: function(protein) {
this.protein = protein;
},
setCarb: function(carb) {
this.carb = carb;
},
setFat: function(fat) {
this.fat = fat;
},
setImg: function(img) {
this.img = img;
},
};
return Macro;
}
})();
Na wzór klasy tworzymy funkcję prototypową, która posiada takie parametry jak id
, name
, kcal
, protein
, carb
, fat
, img
i nadaje im wartości domyślne:
var Macro = function(id, name, kcal, protein, carb, fat, img) {
this.id = id || 0;
this.name = "";
this.kcal = kcal || 0;
this.protein = protein || 0;
this.carb = carb || 0;
this.fat = fat || 0;
this.img = img || "";
}
Wszystkie te parametry odpowiadają tym z naszego pliku answers.json
:
{
"questions":[
{
"id": "1",
"name": "bułka",
"kcal": 600,
"protein": 30,
"carb": 60,
"fat": 6,
"img": "img1.jpg"
},
{
"id": "2",
"name": "pizza",
"kcal": 900,
"protein": 20,
"carb": 80,
"fat": 20,
"img": "img2.jpg"
}
]
}
Do prototypu tej funkcji, dodajemy funkcje, które będą dostępne w każdym utworzonym obiekcie. Dzięki nim, będziemy mogli przypisać nasze dane pobrane z serwisu do odpowiednich parametrów. Rozbiliśmy to na kilka pomniejszych funkcji, które pobrany parametr przypisują do zmiennej aktualnego obiektu, co wskazuje this.
:
Macro.prototype = {
setId: function(id) {
this.id = id;
},
setName: function(name) {
this.name = name;
},
setKcal: function(kcal) {
this.kcal = kcal;
},
setProtein: function(protein) {
this.protein = protein;
},
setCarb: function(carb) {
this.carb = carb;
},
setFat: function(fat) {
this.fat = fat;
},
setImg: function(img) {
this.img = img;
},
};
# Tworzymy model dla produktów
Kolejnym krokiem będzie stworzenie drugiego modelu, który będzie pełnił rolę listy obiektów z modelu makroskładników.
(function() {
'use strict';
angular
.module('quizProject')
.service('ProductModel', ProductModel);
function ProductModel() {
var _list = [];
return {
addItem: function(model) {
return _list.push(model);
},
listOfItems: function(){
return _list;
},
}
}
})();
Serwis, który widzimy posiada prywatną tablicę, na której manipulacje możemy wykonywać za pomocą utworzonych metod. W tym przypadku jest to addItem
oraz listOfItems
. W pierwszym przypadku, addItem
pozwala dodać obiekt stworzony przez MacroModel
do tablicy. listOfItems
zwraca nam całą listę aktualnych obiektów.
# Kontroler czyli łączymy modele oraz serwis
Nasz kontroler z poprzedniego posta po drobnych modyfikacjach, wygląda w taki sposób:
(function() {
'use strict';
angular
.module('quizProject')
.controller('MainController', MainController);
function MainController($scope, GetJson, $http, Macro, ProductModel) {
var promiseAnswers = GetJson.getData();
var Model = new Macro();
$scope.Model = Model;
promiseAnswers.then(function(data){
data.questions.forEach(function(answer) {
$scope.Model.setId(answer.id);
$scope.Model.setName(answer.name);
$scope.Model.setKcal(answer.kcal);
$scope.Model.setProtein(answer.protein);
$scope.Model.setCarb(answer.carb);
$scope.Model.setFat(answer.fat);
$scope.Model.setImg(answer.img);
ProductModel.addItem($scope.Model);
console.log(ProductModel.listOfItems());
$scope.Model = new Macro();
});
});
};
})();
Na początku zaczynamy od wstrzykiwania zależności, które opisywałem w poprzedniej cześci. Dzięki temu zabiegowi, będziemy mogli odwoływać się do naszych modeli z poziomu kontrolera.
function MainController($scope, GetJson, $http, Macro, ProductModel) {
Dodaliśmy Macro
oraz ProductModel
, czyli nazwy serwisów, dzięki czemu możemy teraz wykonać operację new Macro();
:
var Model = new Macro();
$scope.Model = Model;
W ten sposób tworzymy nowy obiekt dla makroskładników jednego z produktów i nazywamy go Model
.
promiseAnswers.then(function(data){
data.questions.forEach(function(answer) {
$scope.Model.setId(answer.id);
$scope.Model.setName(answer.name);
$scope.Model.setKcal(answer.kcal);
$scope.Model.setProtein(answer.protein);
$scope.Model.setCarb(answer.carb);
$scope.Model.setFat(answer.fat);
$scope.Model.setImg(answer.img);
ProductModel.addItem($scope.Model);
console.log(ProductModel.listOfItems());
$scope.Model = new Macro();
});
});
Nasza funkcja z poprzedniego posta, która pozwoliła wyświetlić promise, wysłany z serwisu GetJson
jest teraz zmieniona w taki sposób, żeby odebrane dane dodawać do obiektu model. Odwołujemy się do Modelu i jego metod takich jak setId
.
ProductModel.addItem($scope.Model);
console.log(ProductModel.listOfItems());
$scope.Model = new Macro();
Następnie dodajemy model do tablicy obiektów znajdującej się w ProductModel
za pomocą metody addItem
. Wyświetlamy całość listy obiektów i ponownie tworzymy nowy obiekt, który wypełnimy kolejnymi danymi.
W taki sposób powinna wyglądać konsola po uruchomieniu aplikacji. Wyświetlona jest tablica zawierająca dwa obiekty, których każdy parametr odpowiada tym z answers.json
.