Skip to content

Commit 5245474

Browse files
committed
190 Forkify: Likes View (Front-End)
- Added 7.7.17 named as "Building the Likes View (Front-End)"
1 parent b62129c commit 5245474

File tree

5 files changed

+102
-19
lines changed

5 files changed

+102
-19
lines changed

Modern-JS-ES6-NPM-Babel-Webpack/forkify_project/src/js/index.js

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
/********************************************************************************************************************
2-
* We make the controller for the likes in here. The event for liking an item happens inside the
3-
* .recipe class.
4-
* Therefore, we handle the event again at the .recipe class, where we only catch the event that pertains to the
5-
* 'click' event occurring on the like button, which is the button with .recipe__love class under the
6-
* .recipe class generated dynamically, and this is the reason we use event delegation.
2+
* Now we will handle the UI for the likes. Whenever the user clicks on the love button for a recipe,
3+
* the love button has to be shown as it is a clicked love button. For that, we add logic inside the recipeView
4+
* Module found at ./src/js/views/recipeView.js.
5+
*
6+
* Also, the love button should be persistent, it means that even if we reload the page, the recipe should be liked
7+
* and that love button should show that the recipe was liked. We also implement that functionality
8+
* by changing the recipeView module where we modify the renderRecipe() method. Note that the recipe won't be rendered
9+
* when we reload and that's because state.likes object is not available at the time of the call of renderRecipe()
10+
* inside the controlRecipe() controller. For that reason, we simply use a global state.likes object for testing
11+
* purposes. We can see that global state.likes object on top of the actual Likes Controller which is controlLikes()
12+
* controller method.
13+
*
14+
* Also, we don't want to show the heart icon at the top right of the webapp if there are no recipes that are liked
15+
* by the user yet. Therefore, we will implement the functionality to hide the heart icon at the top right in the
16+
* likesView Module.
17+
*
18+
* As the final step, we will render the likes into the heart icon's list when we hover over it.
19+
* Implementation of the method related to rendering the likes can be found in the likesView Module.
720
*/
821

922
// Import Data Models
@@ -16,6 +29,7 @@ import Likes from './models/Likes';
1629
import * as searchView from './views/searchView';
1730
import * as recipeView from './views/recipeView';
1831
import * as listView from './views/listView';
32+
import * as likesView from './views/likesView';
1933

2034
// Import Common Code Base
2135
import { elements, renderLoader, clearLoader, elementStrings } from './views/base';
@@ -130,7 +144,10 @@ const controlRecipe = async () => {
130144

131145
// Render Recipe -- console.log(state.recipe);
132146
clearLoader();
133-
recipeView.renderRecipe(state.recipe);
147+
recipeView.renderRecipe(
148+
state.recipe,
149+
state.likes.isLikedItem(id)
150+
);
134151

135152
} catch (error) {
136153
clearLoader();
@@ -193,9 +210,13 @@ elements.shopping.addEventListener('click', event => {
193210
});
194211

195212

196-
// LIKE CONTROLLER
213+
214+
// LIKES CONTROLLER
215+
state.likes = new Likes(); // TESTING
216+
likesView.toggleLikeMenu(state.likes.getNumberOfLikedItems()); // TESTING
217+
197218
const controlLike = () => {
198-
if (!state.likes) state.likes = new Likes();
219+
// if (!state.likes) state.likes = new Likes();
199220
const currentID = state.recipe.id;
200221

201222
// If a recipe is liked, then we have to include it in state.likes map, otherwise we don't.
@@ -207,23 +228,27 @@ const controlLike = () => {
207228
const newLike = state.likes.addLikedItem(currentID, state.recipe.title, state.recipe.author, state.recipe.img);
208229

209230
// Toggle the love button
210-
231+
likesView.toggleLikeBtn(true);
211232

212233
// Add like to the UI, i.e., add the liked recipe to the liked list
213-
214-
console.log(state.likes); // TESTING
234+
likesView.renderLike(newLike);
235+
// console.log(state.likes); // TESTING
215236

216237
} else { // when the current recipe is liked
217238
// Remove like from the state
218239
state.likes.deleteLikedItem(currentID);
219240

220241
// Toggle the love button
242+
likesView.toggleLikeBtn(false);
221243

222244
// Remove like from the UI, i.e. from the liked list
223-
224-
225-
console.log(state.likes); // TESTING
245+
likesView.deleteLike(currentID);
246+
// console.log(state.likes); // TESTING
226247
}
248+
249+
likesView.toggleLikeMenu(
250+
state.likes.getNumberOfLikedItems()
251+
);
227252
};
228253

229254

Modern-JS-ES6-NPM-Babel-Webpack/forkify_project/src/js/views/base.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export const elements = {
88
searchRes: document.querySelector('.results'),
99
searchResPages: document.querySelector('.results__pages'),
1010
recipe: document.querySelector('.recipe'),
11-
shopping: document.querySelector('.shopping__list')
11+
shopping: document.querySelector('.shopping__list'),
12+
likesMenu: document.querySelector('.likes__field'),
13+
likesList: document.querySelector('.likes__list')
1214
};
1315

1416

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { elements, elementStrings } from './base';
2+
import { limitRecipeTitle } from './searchView';
3+
4+
5+
export const toggleLikeBtn = isLiked => {
6+
/**
7+
* <button class="recipe__love">
8+
<svg class="header__likes">
9+
<use href="img/icons.svg#icon-heart-outlined"></use>
10+
</svg>
11+
</button>
12+
*/
13+
14+
// we have to change 'icon-heart-outlined' to 'icon-heart'
15+
const iconString = isLiked ? 'icon-heart' : 'icon-heart-outlined';
16+
17+
// change the href of the .recipe__love button, for which we select the use element inside the
18+
// .recipe__love class as follows: document.querySelector('.recipe__love use') and then change the
19+
// href attribute to the one we want.
20+
// document.querySelector('.recipe__love use').setAttribute('href', `img/icons.svg#${iconString}`)
21+
22+
document.querySelector(`.${elementStrings.loveButton} use`).setAttribute('href', `img/icons.svg#${iconString}`);
23+
};
24+
25+
// called inside the controlLike() method at ./src/js/index.js, which is the controller for the likes.
26+
export const toggleLikeMenu = numLikes => {
27+
elements.likesMenu.style.visibility = numLikes > 0 ? 'visible' : 'hidden';
28+
};
29+
30+
31+
export const renderLike = like => {
32+
// Taken from ./src/index.html under the .likes__list class
33+
// console.log(like); // TESTING
34+
35+
const markup = `
36+
<li>
37+
<a class="likes__link" href="#${like.id}">
38+
<figure class="likes__fig">
39+
<img src="${like.value.img}" alt="${like.value.title}">
40+
</figure>
41+
<div class="likes__data">
42+
<h4 class="likes__name">${limitRecipeTitle(like.value.title)}</h4>
43+
<p class="likes__author">${like.value.author}</p>
44+
</div>
45+
</a>
46+
</li>
47+
`;
48+
49+
elements.likesList.insertAdjacentHTML('beforeend', markup);
50+
};
51+
52+
53+
export const deleteLike = id => {
54+
const el = document.querySelector(`.likes__link[href="#${id}"]`).parentElement;
55+
if (el) el.parentElement.removeChild(el);
56+
};

Modern-JS-ES6-NPM-Babel-Webpack/forkify_project/src/js/views/recipeView.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const createIngredient = ingredient => `
4747
</li>
4848
`;
4949

50-
export const renderRecipe = recipe => {
50+
export const renderRecipe = (recipe, isLiked) => {
5151
// we get the markup under .recipe class in index.html
5252
const markup = `
5353
<figure class="recipe__fig">
@@ -91,7 +91,7 @@ export const renderRecipe = recipe => {
9191
9292
<button class="recipe__love">
9393
<svg class="header__likes">
94-
<use href="img/icons.svg#icon-heart-outlined"></use>
94+
<use href="img/icons.svg#icon-heart${isLiked ? '': '-outlined'}"></use>
9595
</svg>
9696
</button>
9797

Modern-JS-ES6-NPM-Babel-Webpack/forkify_project/src/js/views/searchView.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ export const highlightSelected = id => {
3333
});
3434

3535
// highlight the selected recipe from .results__list class
36-
document.querySelector(`a[href="#${id}"]`).classList.add('results__link--active');
36+
document.querySelector(`.results__link[href="#${id}"]`).classList.add('results__link--active');
3737
};
3838

3939

4040
// function to limit the recipe name in the .results__list class
41-
const limitRecipeTitle = (title, limit = 17) => { // 17 is the sweet spot for limiting the no. of letters
41+
export const limitRecipeTitle = (title, limit = 17) => { // 17 is the sweet spot for limiting the no. of letters
4242
let newTitle = [];
4343
if (title.length > limit) {
4444
title.split(' ').reduce((acc, curr) => {

0 commit comments

Comments
 (0)