-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
151 lines (124 loc) · 6.16 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/********************************************************************************************************************
* What we'll learn:
* ----------------
* 1. Using external third-party API called fractional.
*
* We want to convert the recipe quantity (i.e., count) from decimal values (i.e., 4.5, 2.25, etc) into fractional
* values (i.e., 4 1/2, 2 1/4, etc). In order to do that, we use a 3rd party API called fractional.
* We install it using npm and save it as a code dependency because we will import the API in our code.
* Now, we implement the formatCount() method inside the recipeView module, where we will use the fractional API.
* Another important aspect is to keep the selected recipe from the .results__list highlighted.
* For that, we will implement another function in searchView module which will be called here, onto which the ID of
* the selected item is passed onto to the method. The method is called highlightSelected(). It is called inside
* the controlRecipe() method in this file.
*
*/
import Search from './models/Search';
import Recipe from './models/Recipe';
import * as searchView from './views/searchView';
import * as recipeView from './views/recipeView';
import { elements, renderLoader, clearLoader, elementStrings } from './views/base';
/**
* Global State of the app:
* - Search Object
* - Current Recipe Object
* - Shopping List Object
* - Liked Recipes -- Stored persistently. We'll know about JS local storage (i.e., persistent data) later.
*/
const state = {};
// SEARCH CONTROLLER
const controlSearch = async () => {
// 1. Get the search query from the view
// const query = 'pizza'; // for now, this is just a placeholder string.
const query = searchView.getInput(); // we get the search query from the searchView module that we imported
console.log(query); // testing purposes
if (query) {
// 2. If there's a query, then add it to the state as a search object.
state.search = new Search(query);
// 3. Prepare UI for results
// After we get the result, we have to clear the input form
searchView.clearInput();
searchView.clearResults();
try {
// We send in the .results class' element from the elements imported from base module
renderLoader(elements.searchRes);
// 4. Search for results
await state.search.getResult();
// 5. Render results on the UI //console.log(state.search.recipes);
clearLoader();
searchView.renderResults(state.search.recipes);
} catch (error) {
alert("Something went wrong with the search... \n Dev Note: Check the console for the error");
console.log(error);
clearLoader();
}
}
}
// Now we will get the data from ./src/index.html file, where we get the search query using the DOM event listener:
elements.searchForm.addEventListener('submit', event => {
// When we click the form's submit button, the page reloads. we don't want that, therefore we prevent the default action
event.preventDefault();
controlSearch();
});
// event to handle pagination in .results__page class' element.
elements.searchResPages.addEventListener('click', event => {
//console.log(event.target);
// event.target is not the actual button element that we want, but it will be whatever the user
// click onto that's inside the button, i.e., it can be the button element, or the Page number span,
// or it can be also be the left or right icon, depending on what the click on. Therefore, for that
// we use the closest() method which works on all the DOM elements. Look into Element.closest() MDN Docs to know
// more about closest() method. We will use the closest() method to get the closest ancestor element that
// we want to get from the triggered event.
const btn = event.target.closest(`.${elementStrings.pageButton}`);
//console.log(btn);
if (btn) {
const goToPage = parseInt(btn.dataset.goto, 10); // convert to base10 int
// clearing the buttons code is included inside the clearResults() method
searchView.clearResults();
searchView.renderResults(state.search.recipes, goToPage); // default is page 1
console.log(goToPage);
}
});
// RECIPE CONTROLLER
// Test Code:
// const r = new Recipe(47746);
// r.getRecipe();
// console.log(r);
const controlRecipe = async () => {
// Get the hash-link
const id = window.location.hash.replace('#', ''); //console.log(id);
// Check if we have an id, only then, we would go ahead and execute the following code
if (id) {
// Prepare the UI for changes
recipeView.clearRecipe();
renderLoader(elements.recipe);
// Highlight the selected recipe
if (state.search)
searchView.highlightSelected(id);
// Create new recipe object
state.recipe = new Recipe(id);
// window.r = state.recipe; // TEST CODE
try {
// Get the recipe data and parse ingredients
await state.recipe.getRecipe();
state.recipe.parseIngredients();
// Calculate servings of the recipe and time required to make the recipe.
state.recipe.calcServings();
state.recipe.calcTime();
// Render Recipe -- console.log(state.recipe);
clearLoader();
recipeView.renderRecipe(state.recipe);
} catch (error) {
clearLoader();
alert("Something went wrong with processing the recipe... \nDev Note: Check the developer console for the error");
console.log(error);
}
}
};
// // we have to render the recipes when there's hashchange event
// window.addEventListener('hashchange', controlRecipe);
// // we also have to render the recipes when the page reloads, to save the state of the recipe
// window.addEventListener('load', controlRecipe);
// Instead of adding the same event handler - controlRecipe() for two events on window, we can simply
// do it in a single line using the forEach() method as shown below.
['hashchange', 'load'].forEach(event => window.addEventListener(event, controlRecipe));