Related
Here is the original code I wrote for a coffee calculator app
app.js
const express = require('express');
const bodyParser = require('body-parser');
const ejs = require("ejs");
const app = express();
let brewTypeResult = '';
let cupQuantityResult = '';
let gramsOfWater = 0;
let gramsOfCoffee = 0;
let grindType = '';
let stepOne = '';
let stepTwo = '';
let stepThree = '';
let stepFour = '';
let stepFive = '';
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static("public"));
app.get('/', function(req, res) {
res.render("input");
});
app.post("/", function(req, res) {
const brewType = req.body.brewType;
const cupQuantity = req.body.cupQuantity;
console.log("brew type: " + brewType);
console.log("cups: " + cupQuantity);
brewTypeResult = brewType;
cupQuantityResult = cupQuantity;
res.redirect("/results");
switch (brewTypeResult) {
case 'Filter':
grindType = 'Medium'
gramsOfWater = cupQuantity * 235
gramsOfCoffee = cupQuantity * 14
stepOne = 'f1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepTwo = 'f2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepThree = 'f3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFour = 'f4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFive = 'f5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
break;
case 'French Press':
grindType = 'Coarse'
gramsOfWater = cupQuantity * 350
gramsOfCoffee = cupQuantity * 30
stepOne = 'fp1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepTwo = 'fp2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepThree = 'fp3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFour = 'fp4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFive = 'fp5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
break;
case 'V60':
grindType = 'Medium-Coarse'
gramsOfWater = cupQuantity * 250
gramsOfCoffee = cupQuantity * 15
stepOne = 'v1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepTwo = 'v2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepThree = 'v3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFour = 'v4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFive = 'v5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
break;
case 'Aeropress':
grindType = 'Medium-Fine'
gramsOfWater = cupQuantity * 90
gramsOfCoffee = cupQuantity * 15
stepOne = 'a1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepTwo = 'a2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepThree = 'a3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFour = 'a4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFive = 'a5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
break;
case 'Cold Brew':
grindType = 'Extra-Coarse'
gramsOfWater = cupQuantity * 212
gramsOfCoffee = cupQuantity * 15
stepOne = 'cb1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepTwo = 'cb2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepThree = 'cb3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFour = 'cb4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
stepFive = 'cb5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.';
break;
default:
grindType = 'error'
}
});
// Make dropdown menu display selected text
// Doesn't work bc node doesn't have DOM
// $(".dropdown-menu li a").click(function(){
// $(this).parents(".dropdown").find('.btn').html($(this).text() + ' <span class="caret"></span>');
// $(this).parents(".dropdown").find('.btn').val($(this).data('value'));
// });
// Separate Page Results
app.get('/results', function(req, res) {
res.render('results', {
brewType: brewTypeResult,
cupQuantity: cupQuantityResult,
gramsOfWater: gramsOfWater,
gramsOfCoffee: gramsOfCoffee,
grindType: grindType,
stepOne: stepOne,
stepTwo: stepTwo,
stepThree: stepThree,
stepFour: stepFour,
stepFive: stepFive
});
});
app.post("/results", function(req, res) {
res.redirect("/");
});
app.listen(8000, function() {
console.log("Server is running on port 8000.");
});
input.ejs
<div class="container input-grid">
<div class="row">
<div class='col-lg-4 left-column'>
<div class="row">
<h1 class="title-blurb">Coffee Ratio Calculator</h1>
</div>
<div class="row">
<p class="title-blurb">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet. </p>
</div>
</div>
<div class="col-lg-8 right-column">
<div class="box">
<form class="calculator-input" action="/" method="post">
<div class="top-group">
<div class="row input-row">
<h2>Select Your Brew Method</h2>
</div>
<div class="row input-row brew-input">
<select class="brew-input" name="brewType" id="brewType">
<option>Filter</option>
<option>French Press</option>
<option>V60</option>
<option>Aeropress</option>
<option>Cold Brew</option>
</select>
</div>
</div>
<div class="input-row row">
<h2>How many cups?</h2>
</div>
<div class="row cup-input">
<input class="cup-input" type="number" id="quantity" name="cupQuantity" min="1" max="10">
</div>
<div class="button-row calc-button">
<button type="submit" class="btn btn-primary btn-lg buttons">Calculate</button>
</div>
</form>
</div>
</div>
</div>
<br>
</div>
<%-include('partials/footer')%>
results.ejs
<div class="container input-grid">
<div class="row">
<div class="col-lg-4 left-column">
<div class="row">
<h1 class="title-blurb">Coffee Ratio Calculator</h1>
</div>
<div class="row">
<p class="title-blurb">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet. </p>
</div>
</div>
<div class="col-lg-8 right-column">
<form action="/" method="post">
<div class="box">
<div class="results-data">
<div class="row results-row">
<div class="col-md-6">
<h2 class="results-title">Brew Method:</h2>
</div>
<div class="col-md-6">
<h2 class="results-right"><%= brewType %></h2>
</div>
</div>
<div class='row results-row'>
<div class="col-md-6">
<h2 class="results-title">Cup Quantity:</h2>
</div>
<div class="col-md-6">
<h2 class="results-right"><%= cupQuantity %></h2>
</div>
</div>
<div class="row results-row">
<div class="col-md-6">
<h2 class="results-title">Grind Type:</h2>
</div>
<div class="col-md-6">
<h2 class="results-right"> <%= grindType %> </h2>
</div>
</div>
<div class="row results-row">
<div class="col-md-6">
<h2 class="results-title">Grams of Coffee:</h2>
</div>
<div class="col-md-6">
<h2 class="results-right"><%= gramsOfCoffee %> g</h2>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h2 class="results-title">Grams of Water:</h2>
</div>
<div class="col-md-6">
<h2 class="results-right"> <%= gramsOfWater %> g</h2>
</div>
</div>
<%# Back Button %>
<div class="button-row">
Back
</div>
</div>
</div>
</form>
</div>
</div>
<div class="brewInstructions">
<h2 class="instructionsTitle"><%= brewType %> Coffee Instructions</h2>
<div class="instructions">
<ol>
<li>
<%= stepOne %>
</li>
<br>
<li>
<%= stepTwo %>
</li>
<br>
<li>
<%= stepThree %>
</li>
<br>
<li>
<%= stepFour %>
</li>
<br>
<li>
<%= stepFive %>
</li>
</ol>
</div>
</div>
<%-include('partials/footer')%>
I am confused on how to convert the app.post to react format and if I can still use the variables <%= %>. I am a beginner and trying to build my portfolio site through react and connect previous projects I have done. Thank you for any help!
I tried to create new react files and copy and paste code in as it seemed to work. I kept coming up with errors and am not sure where to go from here.
UI Only Solution
The data needed for your calculator (e.g. the steps) is hard-coded into your JS code. So you can do the calculation in the React UI without the need of a backend.
This is what the react component could look like:
import {useEffect, useState} from "react";
/** the React component */
export const CoffeeCalculator = () => {
/** the variables which were input to your calculator POST */
const [brewType, setBrewType] = useState('Filter');
const [cupQuantity, setCupQuantity] = useState(1);
/** the variables which will be set during the calucaltion */
const [grindType, setGrindType] = useState(null);
const [gramsOfWater, setGramsOfWater] = useState(null);
const [gramsOfCoffee, setGramsOfCoffee] = useState(null);
const [steps, setSteps] = useState([]);
/** gets executed everytime brewType or cupQuantity changes */
useEffect(() => {
// this is the same logic you had in your Node.js express POST
switch (brewType) {
case 'Filter':
setGrindType('Medium');
setGramsOfWater(cupQuantity * 235);
setGramsOfCoffee(cupQuantity * 14);
setSteps([
'f1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
])
break;
case 'French Press':
setGrindType('Coarse');
setGramsOfWater(cupQuantity * 350);
setGramsOfCoffee(cupQuantity * 30);
setSteps([
'f1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
]);
break;
case 'V60':
setGrindType('Medium-Coarse');
setGramsOfWater(cupQuantity * 250);
setGramsOfCoffee(cupQuantity * 15);
setSteps([
'f1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
]);
break;
case 'Aeropress':
setGrindType('Medium-Fine');
setGramsOfWater(cupQuantity * 90);
setGramsOfCoffee(cupQuantity * 15);
setSteps([
'f1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
]);
break;
case 'Cold Brew':
setGrindType('Extra-Coarse');
setGramsOfWater(cupQuantity * 212);
setGramsOfCoffee(cupQuantity * 15);
setSteps([
'f1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
'f5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet.',
]);
break;
default:
setGrindType('error');
}
}, [brewType, cupQuantity]);
return (
<>
<div className="container input-grid">
<div className="row">
<div className='col-lg-4 left-column'>
<div className="row">
<h1 className="title-blurb">Coffee Ratio Calculator</h1>
</div>
<div className="row">
<p className="title-blurb">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Eu volutpat odio facilisis mauris sit amet. </p>
</div>
</div>
<div className="col-lg-8 right-column">
<div className="box">
<form className="calculator-input" action="/" method="post">
<div className="top-group">
<div className="row input-row">
<h2>Select Your Brew Method</h2>
</div>
<div className="row input-row brew-input">
<select className="brew-input" name="brewType" id="brewType" value={brewType} onChange={event => setBrewType(event.target.value)}>
<option>Filter</option>
<option>French Press</option>
<option>V60</option>
<option>Aeropress</option>
<option>Cold Brew</option>
</select>
</div>
</div>
<div className="input-row row">
<h2>How many cups?</h2>
</div>
<div className="row cup-input">
<input className="cup-input" type="number" id="quantity" name="cupQuantity" min="1" max="10" value={cupQuantity} onChange={event => setCupQuantity(parseInt(event.target.value))} />
</div>
<div className="button-row calc-button">
<button type="submit" className="btn btn-primary btn-lg buttons">Calculate</button>
</div>
</form>
</div>
</div>
</div>
{/*The output - only show if there is a result*/}
<div className={'row'}>
<div className={'col'}>
<div className="box">
<div className="results-data">
<div className="row results-row">
<div className="col-md-6">
<h2 className="results-title">Brew Method:</h2>
</div>
<div className="col-md-6">
<h2 className="results-right">
{brewType}
</h2>
</div>
</div>
<div className='row results-row'>
<div className="col-md-6">
<h2 className="results-title">Cup Quantity:</h2>
</div>
<div className="col-md-6">
<h2 className="results-right">
{cupQuantity}
</h2>
</div>
</div>
<div className="row results-row">
<div className="col-md-6">
<h2 className="results-title">Grind Type:</h2>
</div>
<div className="col-md-6">
<h2 className="results-right">
{grindType}
</h2>
</div>
</div>
<div className="row results-row">
<div className="col-md-6">
<h2 className="results-title">Grams of Coffee:</h2>
</div>
<div className="col-md-6">
<h2 className="results-right">
{gramsOfCoffee} g
</h2>
</div>
</div>
<div className="row">
<div className="col-md-6">
<h2 className="results-title">Grams of Water:</h2>
</div>
<div className="col-md-6">
<h2 className="results-right">
{gramsOfWater} g
</h2>
</div>
</div>
</div>
</div>
</div>
</div>
{/*the steps*/}
<div className={'row'}>
<div className={'col'}>
<div className="brewInstructions">
<h2 className="instructionsTitle">
{brewType} Coffee Instructions
</h2>
<div className="instructions">
<ol>
{/*iterate through the steps to create a <li> element for each step*/}
{
steps.map(instruction => {
return (
<li>
{instruction}
</li>
)
})
}
</ol>
</div>
</div>
</div>
</div>
</div>
</>
)
}
The input and output of the calculator are all in one component. The output is recalculated every time the input changes.
Key differences to the EJS script are:
we are using React state hooks for all input and output variables (useState())
we are using React effect hooks for the actual calculation (useEffect()). This is executed every time brewType or setCupQuantity is changed.
We can deploy the state variables and any other javascript to the html by using curly braces: {grindType}.
UI + Backend Solution
In case you do need a backend integration you can use standard AJAX to retrieve the data from the backend.
For instance, you could save the steps to brew coffee in a backend database.
You can re-use your existing Node.js express app with the following changes:
Enable express to parse json:
app.use(bodyParser.json())
Modify the url of your endpoint to start with /api. This will allow us to host the React app and the express REST API on the same domain:
app.post("/api/calculate", function(req, res) {
const brewType = req.body.brewType;
const cupQuantity = req.body.cupQuantity;
console.log("brew type: " + brewType);
console.log("cups: " + cupQuantity);
let brewTypeResult = brewType;
let cupQuantityResult = cupQuantity;
res.redirect("/results");
switch (brewTypeResult) {
...
}
// return result as json
res.json({
grindType: grindType,
gramsOfWater: gramsOfWater,
gramsOfCoffee: gramsOfCoffee,
steps: stepsArray
});
}
Make sure that your React development server proxies all AJAX requests to /api to your express app. Add this to your React's package.json:
"proxy": "http://localhost:8080"
At last, you can use any AJAX library to fetch the data in your UI useEffect calculator function:
useEffect(() => {
fetch('/api/coffee-calculate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brewType: brewType,
cupQuantity: cupQuantity,
})
})
.then(async response => {
// parse the response's data to JSON
const json = await response.json();
// assign result to local state
setGrindType(json.grindType);
setGramsOfWater(json.gramsOfWater);
setGramsOfCoffee(json.gramsOfCoffee);
setSteps(json.steps);
})
.catch(error => {
// handle any AJAX errors
})
}, [brewType, cupQuantity])
this is what I ended up doing. i added a ternary statement attached to the onClick function for the button to render different results based on if the calculator had received input yet. big thanks for christoph for pointing me in the right direction!
import React from 'react';
import { useEffect, useState } from 'react';
//styles for grid
import { styled } from '#mui/material/styles';
import Box from '#mui/material/Box';
import Paper from '#mui/material/Paper';
import Grid from '#mui/material/Grid';
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: 'transparent',
boxShadow: '0px 0px 0px',
}));
function CoffeeCalculator() {
const [isCalculated, setIsCalculated] = useState(false);
const [brewType, setBrewType] = useState('Filter');
const [cupQuantity, setCupQuantity] = useState(1);
const [grindType, setGrindType] = useState(null);
const [gramsOfWater, setGramsOfWater] = useState(null);
const [gramsOfCoffee, setGramsOfCoffee] = useState(null);
const [steps, setSteps] = useState([]);
const handleClick = () => {
setIsCalculated(!isCalculated);
};
useEffect(() => {
switch (brewType) {
case 'Filter':
setGrindType('Medium');
setGramsOfWater(cupQuantity * 235);
setGramsOfCoffee(cupQuantity * 14);
setSteps([
'Filter step1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Filter step2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Filter step3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Filter step4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Filter step5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Filter step6- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
]);
break;
case 'French Press':
setGrindType('Coarse');
setGramsOfWater(cupQuantity * 350);
setGramsOfCoffee(cupQuantity * 30);
setSteps([
'French Press step1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'French Press step2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'French Press step3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'French Press step4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
]);
break;
case 'V60':
setGrindType('Medium-Coarse');
setGramsOfWater(cupQuantity * 250);
setGramsOfCoffee(cupQuantity * 15);
setSteps([
'V60 step1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'V60 step2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'V60 step3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'V60 step4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'V60 step5- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
]);
break;
case 'Aeropress':
setGrindType('Medium-Fine');
setGramsOfWater(cupQuantity * 90);
setGramsOfCoffee(cupQuantity * 15);
setSteps([
'Aeropress step1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Aeropress step2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Aeropress step3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
]);
break;
case 'Cold Brew':
setGrindType('Extra-Coarse');
setGramsOfWater(cupQuantity * 212);
setGramsOfCoffee(cupQuantity * 15);
setSteps([
'Cold Brew step1- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Cold Brew step2- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Cold Brew step3- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
'Cold Brew step4- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
]);
break;
default:
setGrindType('error');
}
}, [brewType, cupQuantity]);
function InputCoffeeCalc() {
return (
<Grid item lg={8} className='right-column'>
<Item>
<div className='box'>
<form
className='calculator-input'
action='/'
method='post'
>
<div className='top-group'>
<h2 className='input-row'>
Select Your Brew Method
</h2>
<select
className='brew-input'
name='brewType'
id='brewType'
value={brewType}
onChange={(event) =>
setBrewType(event.target.value)
}
>
<option>Filter</option>
<option>French Press</option>
<option>V60</option>
<option>Aeropress</option>
<option>Cold Brew</option>
</select>
</div>
<h2 className='input-row'>How many cups?</h2>
<input
className='cup-input'
type='number'
id='quantity'
name='cupQuantity'
min='1'
max='10'
value={cupQuantity}
onChange={(event) =>
setCupQuantity(parseInt(event.target.value))
}
/>
<div className='button-row'>
<button
type='submit'
className='buttons calc-button'
onClick={handleClick}
>
Calculate
</button>
</div>
</form>
</div>
</Item>
</Grid>
);
}
function ResultsCoffeeCalc() {
function ResultsRow(props) {
return (
<Grid container item spacing={0} className='results-row'>
<React.Fragment>
<Grid item md={8} sm={12}>
<Item>
<h2 className='results-left'>{props.data}</h2>
</Item>
</Grid>
<Grid item md={4} sm={12}>
<Item>
<h2 className='results-right'>
{props.results}
</h2>
</Item>
</Grid>
</React.Fragment>
</Grid>
);
}
return (
<div>
<div className='box'>
<Grid
item
// lg={12}
container
spacing={-20}
className='results-data'
>
<ResultsRow data='Brew Method:' results={brewType} />
<ResultsRow
data='Cup Quantity:'
results={cupQuantity}
/>
<ResultsRow data='Grind Type:' results={grindType} />
<ResultsRow
data='Grams of Coffee:'
results={gramsOfCoffee}
/>
<ResultsRow
data='Grams of Water:'
results={gramsOfWater}
/>
</Grid>
<div className='button-row'>
<button
type='submit'
className='buttons calc-button'
onClick={handleClick}
>
Back
</button>
</div>
</div>
<BrewInstructions />
</div>
);
}
function BrewInstructions() {
return (
<div className='brewInstructions'>
<h2 className='instructionsTitle'>
{brewType} Coffee Instructions
</h2>
<div className='instructions'>
<ol>
{/*iterate through the steps to create a <li> element for each step*/}
{steps.map((step) => {
return (
<div>
<li>{step}</li>
<br />
</div>
);
})}
</ol>
</div>
</div>
);
}
return (
<div>
<Box
sx={{ flexGrow: 1 }}
className='coffee-calculator-page input-grid'
>
<Grid container spacing={-20}>
<Grid item lg={4} className='left-column'>
<Item>
<h1 className='title title-blurb'>
Coffee Ratio Calculator
</h1>
<p className='title-blurb'>
Lorem ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Eu
volutpat odio facilisis mauris sit amet.{' '}
</p>
</Item>
</Grid>
{/* returns different results based on calculation input */}
<Grid item lg={8}>
<Item>
{isCalculated ? (
<ResultsCoffeeCalc />
) : (
<InputCoffeeCalc />
)}
</Item>
</Grid>
</Grid>
</Box>
</div>
);
}
export default CoffeeCalculator;
I've got a side scrolling / horizontal layout site I'm building. I use a function to test whether or not an element is in the viewport on "normal" vertical layout sites in order to add classes, animations, etc. once it comes into view.
I'm trying to get the same effect for the horizontal layout, but to no avail.
Here is the regular version of the function -
$.fn.isInViewport = function() {
if ( $(this).length ) {
var elementTop = $(this).offset().top;
}
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
And here is the way I tried it for horizontal layouts, which didn't work.
$.fn.isInViewport = function() {
if ( $(this).length ) {
var elementLeft = $(this).offset().left;
}
var elementRight = elementLeft + $(this).outerWidth();
var viewportLeft = $(window).scrollLeft();
var viewportRight = viewportLeft + $(window).width();
return elementRight > viewportLeft && elementLeft < viewportRight;
};
You call the function like so
$(".element").each(function() {
if ( $(this).isInViewport() ) {
$(this).addClass("animate-element");
}
});
Using jquery its pretty easy, All yo have to do is $(element).on('scroll',(--function--)) and then you can use $(this).offset().left to get the pixel on its left and when you get the offset of left, you can just do whatever you want. Check the snippet below for an working example. (if possible run in smaller screen like mobile)
$("#timeline").on('scroll', function() {
$("#timeline .each").each(function(){
let left = $(this).offset().left;
if(left >-50 && left< (window.innerWidth - 100)){
$(this).addClass('mvisible')
}
else{
if($(this).hasClass('mvisible')){
$(this).removeClass('mvisible')
}
}
});
});
.timeline{overflow-x:auto;width:100%}
.timeline .warp{display:flex;width:1600px;padding:50px 100px 50px 30px;}
.timeline .each{width:185px;}
.timeline .desc{padding:15px;border-radius:4px;background:#08f;color:#fff;width:100%;transform:translateY(50px);opacity:0;transition:0.4s}
.timeline .mvisible .desc{transform:translateY(0);opacity:1}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="timeline" id="timeline">
<div class="warp">
<div class="each mvisible">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each" >
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each" >
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</div>
</div>
As mentioned in the comments IntersectionObserver is a good place to start
const inViewObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// do stuff when in view
entry.target.classList.add('in-view')
document.body.dataset.log = 'Element in view - well done 😃'
} else {
// do stuff when not in view
entry.target.classList.remove('in-view')
document.body.dataset.log = 'Element not in view - try to find it 🔍'
}
})
}, { threshold: .5 })
const elm = document.querySelector('.element')
inViewObserver.observe(elm)
body {
/* trigger scroll in both directions */
width: 300vw;
height: 300vh;
display: grid;
place-items: center;
}
body::before {
content: attr(data-log);
position: fixed;
top: 0;
left: 0;
}
.element {
background: tomato;
width: 10rem;
height: 10rem;
transition: all 600ms 300ms;
transform: scale(0.25) rotate(360deg);
}
.in-view {
background: olive;
transform: none;
border-radius: 1rem;
}
<div class="element"></div>
I have an issue about the scroll in javascript. I made a toggle feature, but when I click on the button, I have an automatic scroll; and I don't want it when the button displays the content. I only want this automatic scroll when the button hides it. I use a tutorial from this website : https://css-tricks.com/using-css-transitions-auto-dimensions/
But I didn't find a solution. I tried somes with the scrollTop or the funcion ScrollTo(), but i doesn't work.
Another thing that I don't understand about this. When I'm on the top of the page and I click on the button, there is no automatic scroll, but I scroll down just a little, the automatic scroll is here. I don't know why.
Last point, tt's necessary that the button is after the div "desc collapsible", because the idea is to close immediately the block after reading it. If it's before, the user cannot do this; he has to scroll up before.
Here is my actual code.
function collapseSection(element) {
// get the height of the element's inner content, regardless of its actual size
var sectionHeight = element.scrollHeight;
var y = element.scrollTop;
// temporarily disable all css transitions
var elementTransition = element.style.transition;
element.style.transition = '';
// on the next frame (as soon as the previous style change has taken effect),
// explicitly set the element's height to its current pixel height, so we
// aren't transitioning out of 'auto'
requestAnimationFrame(function() {
element.style.height = sectionHeight + 'px';
element.style.transition = elementTransition;
// on the next frame (as soon as the previous style change has taken effect),
// have the element transition to height: 0
requestAnimationFrame(function() {
element.style.height = 0 + 'px';
});
});
// mark the section as "currently collapsed"
element.setAttribute('data-collapsed', 'false');
window.scrollBy(0,y)
}
function expandSection(element) {
// get the height of the element's inner content, regardless of its actual size
var sectionHeight = element.scrollHeight;
// have the element transition to the height of its inner content
element.style.height = sectionHeight + 'px';
// when the next css transition finishes (which should be the one we just triggered)
element.addEventListener('transitionend', function(e) {
// remove this event listener so it only gets triggered once
element.removeEventListener('transitionend', arguments.callee);
// remove "height" from the element's inline styles, so it can return to its initial value
element.style.height = 'auto';
});
// mark the section as "currently not collapsed"
element.setAttribute('data-collapsed', 'true');
}
document.querySelector('#toggle-button').addEventListener('click', function(e) {
var section = document.querySelector('.desc.collapsible');
var isCollapsed = section.getAttribute('data-collapsed') !== 'true';
if(isCollapsed) {
expandSection(section)
section.setAttribute('data-collapsed', 'true')
} else {
collapseSection(section)
}
});
.desc {
color: red;
overflow:hidden;
transition:height 0.3s ease-out;
height: 0;
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<div>
<div class="desc collapsible">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
<button id="toggle-button">Toggle collapse</button>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
Thanks by advance!
You need to place your button before that div "desc collapsible" to achieve your functionality
<button id="toggle-button">Toggle collapse</button>
<div class="desc collapsible">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
// remove this line <button id="toggle-button">Toggle collapse</button>
I have a HTML structure like this:
<div class="col-md-6">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
I need to get the text inside the div wrapped in <p> tag. I'm using the code below:
$('.col-md-6').contents().filter(function() {
return this.nodeType === 3;
}).each(function() {
this.nodeValue = $.trim(this.nodeValue);
}).wrap('<p></p>');
Which works fine IF there is no link (<a>) inside the text. The output with my jQuery code would be:
<div class="col-md-6"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod </p>tempor<p> incididunt ut labore et dolore magna aliqua.</p></div>
This is my desired result:
<div class="col-md-6"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p></div>
Is this possible?
Using html() and contents()
$('.col-md-6').html(function() {
return $('<p/>').html($(this).contents())
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-md-6">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
For multiple .col-md-6 with textNode
$('.col-md-6').each(function() {
$(this).contents().filter(function() {
return this.nodeType === 3;
}).siblings().addBack().wrapAll('<p></p>')
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-md-6">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="col-md-6"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p></div>
<div class="col-md-6">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
I have pages with HTML that look like this:
<div class="row">
<div class="col-md-12">
<h2>Some Title</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
Now I need to have the first Lorem ipsum text wrapped in <p></p> tags aswell. Is there a way to detect this and do it with regex?
I would be using regex to make these changes directly in the database.
Since your structure is fixed it's just a matter of
Finding the first non-empty TextNode
Creating a p element
Substituting the text node with the paragraph inside the parent node.
I made the paragraphs green so you can see the effect. Just click the "Wrap" button to see it in action.
function wrap() {
let div = document.querySelector('div.row>div.col-md-12'); // get the container
for (let i = 0; i < div.childNodes.length; i++) { // loop through children
let n = div.childNodes[i];
if (n.nodeName == "#text" && n.textContent.trim() !== '') { // children found!
let p = document.createElement('p'); // create a `p` element
p.textContent = n.textContent; // put the original text inside
n.parentNode.replaceChild(p, n); // swap!
break; // we're done here
}
}
}
p {
background-color: green;
}
<div class="row">
<div class="col-md-12">
<h2>Some Title</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
<button onclick="javascript:wrap()">Wrap</button>
I used regex search, and when find the string, make a child element of class col-md-12 and removed another string without elements!
<html>
<body>
<div class="row">
<div class="col-md-12">
<h2>Some Title</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</body>
<script>
var string = document.getElementsByTagName('html')[0].innerHTML;
var regex = /Lorem ipsum[a-zA-Z0-9_ _,_.]*/g;
var save = regex.exec(string)[0];
document.getElementsByTagName('html')[0].innerHTML = document.getElementsByTagName('html')[0].innerHTML.replace(save, "");
var first = document.createElement("p");
var text = document.createTextNode(save);
first.appendChild(text);
document.getElementsByClassName("col-md-12")[0].appendChild(first);
</script>
</html>