From 090f3ec1ec882096c8bf1b4a4940536969dc6443 Mon Sep 17 00:00:00 2001 From: Mitchell Youngerman Date: Fri, 1 May 2020 15:42:41 -0400 Subject: [PATCH] Recipe loads from results list and is displayed on the UI The API returns inconsistent ingredient measurements. There is no standard format for each item, making splitting the strings into a quantity, unit of measurement, and item name almost impossible. --- dist/index.html | 183 +------------------------------------ dist/js/bundle.js | 48 ++++++++-- src/index.html | 70 +------------- src/js/index.js | 24 ++++- src/js/models/Recipe.js | 15 ++- src/js/views/recipeView.js | 59 ++++++++++++ src/js/views/searchView.js | 5 +- webpack.config.js | 3 +- 8 files changed, 143 insertions(+), 264 deletions(-) diff --git a/dist/index.html b/dist/index.html index aa81aeb1..9ca958b8 100644 --- a/dist/index.html +++ b/dist/index.html @@ -53,6 +53,7 @@

Pasta with Tomato ...

-
- - +
diff --git a/dist/js/bundle.js b/dist/js/bundle.js index 43285a7b..a953d112 100644 --- a/dist/js/bundle.js +++ b/dist/js/bundle.js @@ -3846,19 +3846,55 @@ eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn th /***/ (function(module, exports, __webpack_require__) { "use strict"; -eval("\n\nvar _test = __webpack_require__(/*! ./test */ \"./src/js/test.js\");\n\nvar _test2 = _interopRequireDefault(_test);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar x = 23; // Global app controller\n\nconsole.log('I imported ' + _test2.default + ' from another module, test.js! Variable x is ' + x);\n\n//# sourceURL=webpack:///./src/js/index.js?"); +eval("\n\nvar _Search = __webpack_require__(/*! ./models/Search */ \"./src/js/models/Search.js\");\n\nvar _searchView = __webpack_require__(/*! ./views/searchView */ \"./src/js/views/searchView.js\");\n\nvar _Recipe = __webpack_require__(/*! ./models/Recipe */ \"./src/js/models/Recipe.js\");\n\nvar _recipeView = __webpack_require__(/*! ./views/recipeView */ \"./src/js/views/recipeView.js\");\n\ndocument.querySelector('.search__btn').addEventListener('click', function (event) {\n event.preventDefault();\n (0, _Search.searchForRecipeAW)().then(function (data) {\n (0, _searchView.displaySearchResults)(data);\n });\n});\n\ndocument.querySelector('.results__pages').addEventListener('click', function () {\n if (event.target.className == 'btn-inline results__btn--next') {\n (0, _searchView.switchPage)('next');\n }\n if (event.target.className == 'btn-inline results__btn--prev') {\n (0, _searchView.switchPage)('prev');\n }\n});\n\ndocument.querySelector('.resultsPageNumber').addEventListener('click', function (event) {\n var listItems = document.querySelectorAll('li');\n var recipeID = '';\n\n event.preventDefault();\n for (var i = 0; i < listItems.length; i++) {\n if (listItems[i].contains(event.target)) {\n recipeID = listItems[i].querySelector('.results__link').getAttribute('href');\n }\n }\n\n (0, _Recipe.loadRecipeAW)(recipeID).then(function (recipeObj) {\n (0, _recipeView.displayRecipeDetails)(recipeObj);\n });\n});\n\n//# sourceURL=webpack:///./src/js/index.js?"); /***/ }), -/***/ "./src/js/test.js": -/*!************************!*\ - !*** ./src/js/test.js ***! - \************************/ +/***/ "./src/js/models/Recipe.js": +/*!*********************************!*\ + !*** ./src/js/models/Recipe.js ***! + \*********************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nconsole.log('Imported module');\nexports.default = 456;\n\n//# sourceURL=webpack:///./src/js/test.js?"); +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar loadRecipeAW = function () {\n var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(recipeID) {\n var result, recipeObj;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n _context.prev = 0;\n _context.next = 3;\n return fetch(\"https://forkify-api.herokuapp.com/api/get?rId=\" + recipeID);\n\n case 3:\n result = _context.sent;\n _context.next = 6;\n return result.json();\n\n case 6:\n recipeObj = _context.sent;\n\n console.log(recipeObj);\n return _context.abrupt(\"return\", recipeObj);\n\n case 11:\n _context.prev = 11;\n _context.t0 = _context[\"catch\"](0);\n\n console.log(\"Error: \" + _context.t0);\n\n case 14:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, this, [[0, 11]]);\n }));\n\n return function loadRecipeAW(_x) {\n return _ref.apply(this, arguments);\n };\n}();\n\nfunction _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step(\"next\", value); }, function (err) { step(\"throw\", err); }); } } return step(\"next\"); }); }; }\n\nexports.loadRecipeAW = loadRecipeAW;\n\n//# sourceURL=webpack:///./src/js/models/Recipe.js?"); + +/***/ }), + +/***/ "./src/js/models/Search.js": +/*!*********************************!*\ + !*** ./src/js/models/Search.js ***! + \*********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar searchForRecipeAW = function () {\n var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n var query, result, data;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n _context.prev = 0;\n query = document.querySelector('.search__field').value;\n _context.next = 4;\n return fetch('https://forkify-api.herokuapp.com/api/search?q=' + query);\n\n case 4:\n result = _context.sent;\n _context.next = 7;\n return result.json();\n\n case 7:\n data = _context.sent;\n return _context.abrupt('return', data);\n\n case 11:\n _context.prev = 11;\n _context.t0 = _context['catch'](0);\n\n console.log('Encountered an error: ' + _context.t0);\n\n case 14:\n case 'end':\n return _context.stop();\n }\n }\n }, _callee, this, [[0, 11]]);\n }));\n\n return function searchForRecipeAW() {\n return _ref.apply(this, arguments);\n };\n}();\n\nfunction _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step(\"next\", value); }, function (err) { step(\"throw\", err); }); } } return step(\"next\"); }); }; }\n\nexports.searchForRecipeAW = searchForRecipeAW;\n\n//# sourceURL=webpack:///./src/js/models/Search.js?"); + +/***/ }), + +/***/ "./src/js/views/recipeView.js": +/*!************************************!*\ + !*** ./src/js/views/recipeView.js ***! + \************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.displayRecipeDetails = displayRecipeDetails;\n\n\nvar recipe = document.querySelector('.recipe');\nvar recipeImage = document.querySelector('.recipe__fig').querySelector('.recipe__img');\nvar recipeTitle = document.querySelector('.recipe__title').querySelector('span');\nvar recipeCookTime = document.querySelector('.recipe__info-data recipe__info-data--minutes');\nvar recipeServings = document.querySelector('recipe__info-data recipe__info-data--people');\nvar recipePublisher = document.querySelector('.recipe__directions').querySelector('.recipe__by');\nvar recipePublisherSite = document.querySelector('.recipe__directions').querySelector('.recipe__btn');\nvar firstTimeDisplayingAnyRecipe = true;\n\nrecipe.style.display = 'none';\n\nfunction displayRecipeDetails(recipeObj) {\n var arrOfIngredients = recipeObj.recipe.ingredients;\n\n recipe.style.display = 'block';\n recipeImage.src = recipeObj.recipe.image_url;\n\n recipeTitle.textContent = recipeObj.recipe.title;\n recipePublisher.textContent = recipeObj.recipe.publisher;\n recipePublisherSite.href = recipeObj.recipe.source_url;\n\n if (firstTimeDisplayingAnyRecipe === false) {\n var previousItems = document.querySelector('.recipe__ingredient-list').querySelectorAll('li');\n for (var i = 0; i < previousItems.length; i++) {\n previousItems[i].remove();\n }\n }\n\n for (var _i = 0; _i < arrOfIngredients.length; _i++) {\n var ingredientString = arrOfIngredients[_i];\n /* let firstCharofString = ingredientString.charAt(0);\r\n let ingredientQuantity = '';\r\n let ingredientUnitAndName = '';\r\n let numAfterSlash = ingredientString.search('/') + 2;\r\n let numAfterHyphen = ingredientString.search('-') + 1;\r\n let numBeforeSpace = ingredientString.search(' ');\r\n \r\n console.log(ingredientString);\r\n console.log(`character at ${numAfterHyphen} is ${ingredientString.charAt(numAfterHyphen)}`);\r\n if (firstCharofString.match(/(\\d+)/)) {\r\n if (numAfterSlash != 1) {\r\n ingredientQuantity = ingredientString.substring(0, numAfterSlash); // Store the quantity, which probably ends at this index.\r\n ingredientUnitAndName = ingredientString.substring(numAfterSlash); // Get the remainder of the string.\r\n } else if (numAfterHyphen != 0) {\r\n ingredientQuantity = ingredientString.substring(0, (numAfterHyphen + 1));\r\n ingredientUnitAndName = ingredientString.substring(numAfterHyphen + 1);\r\n } else {\r\n ingredientQuantity = ingredientString.substring(0, numBeforeSpace);\r\n ingredientUnitAndName = ingredientString.substring(numBeforeSpace);\r\n }\r\n } else {\r\n ingredientQuantity = 1;\r\n } */\n document.querySelector('.recipe__ingredient-list').insertAdjacentHTML('beforeend', '
  • ' + ingredientString + '
  • ');\n }\n firstTimeDisplayingAnyRecipe = false;\n}\n\n//# sourceURL=webpack:///./src/js/views/recipeView.js?"); + +/***/ }), + +/***/ "./src/js/views/searchView.js": +/*!************************************!*\ + !*** ./src/js/views/searchView.js ***! + \************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.displaySearchResults = displaySearchResults;\nexports.previousBtn = previousBtn;\nexports.nextBtn = nextBtn;\nexports.switchPage = switchPage;\n\n\nvar currResultsPage = 0;\nvar previousBtn = document.querySelector('.results__btn--prev');\nvar nextBtn = document.querySelector('.results__btn--next');\nvar numDivs = 0;\n\npreviousBtn.style.display = 'none';\nnextBtn.style.display = 'none';\n\nfunction displaySearchResults(data) {\n var count = 0;\n var numRecipeResults = data.recipes.length;\n var numOfListItems = 0;\n\n for (count = 0; count < numRecipeResults; count++) {\n var currRecipe = data.recipes[count];\n var currListItem = 0;\n\n document.querySelector('.resultsPageNumber').insertAdjacentHTML('beforeend', '
  • \"Test\"

    Recipe Name

    Recipe Author

  • ');\n numOfListItems = document.querySelector('.resultsPageNumber').querySelectorAll('li');\n currListItem = numOfListItems[count];\n\n currListItem.querySelector('.results__link').href = currRecipe.recipe_id;\n currListItem.querySelector('img').src = currRecipe.image_url;\n currListItem.querySelector('.results__name').textContent = currRecipe.title;\n currListItem.querySelector('.results__author').textContent = currRecipe.publisher;\n }\n\n var currPage = 0;\n var parentDiv = 0;\n\n for (var i = 0; i < numRecipeResults; i += 10) {\n // Insert the div that will contain the next 10 results.\n numOfListItems[i].insertAdjacentHTML('beforebegin', '
    ');\n currPage += 1;\n }\n\n for (var j = 0; j < numRecipeResults; j++) {\n // Move the next 10 results into the current div.\n document.querySelector('.page' + parentDiv).append(numOfListItems[j]);\n if ((j + 1) % 10 === 0) {\n parentDiv += 1;\n }\n }\n\n numDivs = document.querySelectorAll('[class^=\"page\"]');\n\n for (var k = 1; k < numDivs.length; k++) {\n numDivs[k].style.display = 'none';\n }\n\n nextBtn.style.display = 'block';\n nextBtn.querySelector('span').textContent = 'Page 2';\n}\n\nfunction switchPage(pageToLoad) {\n var lastPage = numDivs.length - 1;\n var secondToLastPage = numDivs.length - 2;\n\n document.querySelector('.page' + currResultsPage).style.display = 'none';\n pageToLoad === 'next' ? currResultsPage += 1 : currResultsPage -= 1;\n document.querySelector('.page' + currResultsPage).style.display = 'block';\n\n if (pageToLoad === 'next') {\n previousBtn.style.display = 'block';\n }\n\n previousBtn.querySelector('span').textContent = 'Page ' + currResultsPage;\n nextBtn.querySelector('span').textContent = 'Page ' + (currResultsPage + 2);\n\n if (currResultsPage == lastPage) {\n nextBtn.style.display = 'none';\n } // Hide the next button if this is the last page.\n\n if (currResultsPage == secondToLastPage) {\n nextBtn.style.display = 'block';\n } // Show the next button if another page exists. \n\n if (currResultsPage == 0) {\n previousBtn.style.display = 'none';\n } // Hide the previous button if this is the first page.\n}\n\n//# sourceURL=webpack:///./src/js/views/searchView.js?"); /***/ }), diff --git a/src/index.html b/src/index.html index 7b54bb0f..37dcb7cf 100644 --- a/src/index.html +++ b/src/index.html @@ -89,8 +89,6 @@

    Pasta with Tomato ...

    - - +
    diff --git a/src/js/index.js b/src/js/index.js index 60e7e7b5..7ba04b33 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -3,6 +3,8 @@ import { displaySearchResults } from './views/searchView'; import { previousBtn } from './views/searchView'; import { nextBtn } from './views/searchView'; import { switchPage } from './views/searchView'; +import { loadRecipeAW } from './models/Recipe'; +import { displayRecipeDetails } from './views/recipeView'; document.querySelector('.search__btn').addEventListener('click', (event) => { event.preventDefault(); @@ -12,10 +14,22 @@ document.querySelector('.search__btn').addEventListener('click', (event) => { }); document.querySelector('.results__pages').addEventListener('click', () => { - if (event.target.className == 'btn-inline results__btn--next') { - switchPage('next'); - } - if (event.target.className == 'btn-inline results__btn--prev') { - switchPage('prev'); + if (event.target.className == 'btn-inline results__btn--next') { switchPage('next'); } + if (event.target.className == 'btn-inline results__btn--prev') { switchPage('prev'); } +}); + +document.querySelector('.resultsPageNumber').addEventListener('click', (event) => { + let listItems = document.querySelectorAll('li'); + let recipeID = ''; + + event.preventDefault(); + for (let i = 0; i < listItems.length; i++) { + if (listItems[i].contains(event.target)) { + recipeID = listItems[i].querySelector('.results__link').getAttribute('href'); + } } + + loadRecipeAW(recipeID).then(recipeObj => { + displayRecipeDetails(recipeObj); + }); }); \ No newline at end of file diff --git a/src/js/models/Recipe.js b/src/js/models/Recipe.js index a8212239..3be4defc 100644 --- a/src/js/models/Recipe.js +++ b/src/js/models/Recipe.js @@ -1 +1,14 @@ -const res = await axios(`https://forkify-api.herokuapp.com/api/get?rId=${this.id}`); \ No newline at end of file +export { loadRecipeAW }; + +async function loadRecipeAW (recipeID) { + // while the fetch is pending, display a loading spinner in the RecipeView module + try { + let result = await fetch(`https://forkify-api.herokuapp.com/api/get?rId=${recipeID}`); + let recipeObj = await result.json(); + console.log(recipeObj); + return recipeObj; + } catch(error) { + console.log(`Error: ${error}`); + } + +} \ No newline at end of file diff --git a/src/js/views/recipeView.js b/src/js/views/recipeView.js index e69de29b..e6cadec9 100644 --- a/src/js/views/recipeView.js +++ b/src/js/views/recipeView.js @@ -0,0 +1,59 @@ +export { displayRecipeDetails }; + +const recipe = document.querySelector('.recipe'); +let recipeImage = document.querySelector('.recipe__fig').querySelector('.recipe__img'); +let recipeTitle = document.querySelector('.recipe__title').querySelector('span'); +let recipeCookTime = document.querySelector('.recipe__info-data recipe__info-data--minutes'); +let recipeServings = document.querySelector('recipe__info-data recipe__info-data--people'); +let recipePublisher = document.querySelector('.recipe__directions').querySelector('.recipe__by'); +let recipePublisherSite = document.querySelector('.recipe__directions').querySelector('.recipe__btn'); +let firstTimeDisplayingAnyRecipe = true; + +recipe.style.display = 'none'; + +function displayRecipeDetails(recipeObj) { + let arrOfIngredients = recipeObj.recipe.ingredients; + + recipe.style.display = 'block'; + recipeImage.src = recipeObj.recipe.image_url; + + recipeTitle.textContent = recipeObj.recipe.title; + recipePublisher.textContent = recipeObj.recipe.publisher; + recipePublisherSite.href = recipeObj.recipe.source_url; + + if (firstTimeDisplayingAnyRecipe === false) { + let previousItems = document.querySelector('.recipe__ingredient-list').querySelectorAll('li'); + for (let i = 0; i < previousItems.length; i++) { + previousItems[i].remove(); + } + } + + for (let i = 0; i < arrOfIngredients.length; i++) { + let ingredientString = arrOfIngredients[i]; +/* let firstCharofString = ingredientString.charAt(0); + let ingredientQuantity = ''; + let ingredientUnitAndName = ''; + let numAfterSlash = ingredientString.search('/') + 2; + let numAfterHyphen = ingredientString.search('-') + 1; + let numBeforeSpace = ingredientString.search(' '); + + console.log(ingredientString); + console.log(`character at ${numAfterHyphen} is ${ingredientString.charAt(numAfterHyphen)}`); + if (firstCharofString.match(/(\d+)/)) { + if (numAfterSlash != 1) { + ingredientQuantity = ingredientString.substring(0, numAfterSlash); // Store the quantity, which probably ends at this index. + ingredientUnitAndName = ingredientString.substring(numAfterSlash); // Get the remainder of the string. + } else if (numAfterHyphen != 0) { + ingredientQuantity = ingredientString.substring(0, (numAfterHyphen + 1)); + ingredientUnitAndName = ingredientString.substring(numAfterHyphen + 1); + } else { + ingredientQuantity = ingredientString.substring(0, numBeforeSpace); + ingredientUnitAndName = ingredientString.substring(numBeforeSpace); + } + } else { + ingredientQuantity = 1; + } */ + document.querySelector('.recipe__ingredient-list').insertAdjacentHTML('beforeend', `
  • ${ingredientString}
  • `); + } + firstTimeDisplayingAnyRecipe = false; +} \ No newline at end of file diff --git a/src/js/views/searchView.js b/src/js/views/searchView.js index 89b492de..a9cdb9f3 100644 --- a/src/js/views/searchView.js +++ b/src/js/views/searchView.js @@ -33,12 +33,12 @@ function displaySearchResults (data) { let currPage = 0; let parentDiv = 0; - for (let i = 0; i < numRecipeResults; i += 10) { + for (let i = 0; i < numRecipeResults; i += 10) { // Insert the div that will contain the next 10 results. numOfListItems[i].insertAdjacentHTML('beforebegin', `
    `); currPage += 1; } - for (let j = 0; j < numRecipeResults; j++) { + for (let j = 0; j < numRecipeResults; j++) { // Move the next 10 results into the current div. document.querySelector(`.page${parentDiv}`).append(numOfListItems[j]); if ((j + 1) % 10 === 0) { parentDiv += 1; @@ -56,7 +56,6 @@ function displaySearchResults (data) { } function switchPage(pageToLoad) { - let lastPage = numDivs.length - 1; let secondToLastPage = numDivs.length - 2; diff --git a/webpack.config.js b/webpack.config.js index 09be0b9f..397eeba7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -8,7 +8,8 @@ module.exports = { filename: 'js/bundle.js' }, devServer: { - contentBase: './dist' // Where Webpack should serve our files from. + contentBase: './dist', // Where Webpack should serve our files from. + writeToDisk: true }, plugins: [ new HtmlWebpackPlugin({