please why do i see this error when adding pagination, using slice - pagination

i want to add a pagenation to my product and i got an error message that looks like this :
*Unexpected Application Error!
Cannot read properties of null (reading 'slice')
TypeError: Cannot read properties of null (reading 'slice')
at FeaturedProducts (http://localhost:3000/static/js/bundle.js:997:26)
at renderWithHooks (http://localhost:3000/static/js/bundle.js:43746:22)
at mountIndeterminateComponent (http://localhost:3000/static/js/bundle.js:48322:17)
at beginWork (http://localhost:3000/static/js/bundle.js:49780:20)
at beginWork$1 (http://localhost:3000/static/js/bundle.js:54597:18)
at performUnitOfWork (http://localhost:3000/static/js/bundle.js:53795:16)
at workLoopSync (http://localhost:3000/static/js/bundle.js:53709:9)
at renderRootSync (http://localhost:3000/static/js/bundle.js:53678:11)
at recoverFromConcurrentError (http://localhost:3000/static/js/bundle.js:53087:24)
at performSyncWorkOnRoot (http://localhost:3000/static/js/bundle.js:53333:24)
💿 *
These are my codes:
feature.js
import React, { useState } from "react";
import Card from "../Card/Card";
import "./FeaturedProducts.scss";
import useFetch from "../../hooks/useFetch";
import Pagination from "../pagination/Pagination";
const FeaturedProducts = ({ type }) => {
const { data, loading, error } = useFetch(
`/products?populate=*&[filters][type][$eq]=${type}`
);
const [currentPage, setCurrentPage] = useState(1);
const [postPerPage, setPostPerPage] = useState(3);
const indexOfLastPage = currentPage * postPerPage;
const indexOfFirstPage = indexOfLastPage - postPerPage;
const firstPage = data.slice(indexOfFirstPage, indexOfLastPage);
// //change page function
const paginate = (pageNumber) => setCurrentPage(pageNumber);
return (
<div className="featuredProducts">
<div className="top">
<h1>{type} products</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Quis ipsum
suspendisse ultrices gravida. Risus commodo viverra maecenas accumsan
lacus vel facilisis labore et dolore magna aliqua. Quis ipsum
suspendisse ultrices gravida. Risus commodo viverra maecenas.
</p>
</div>
<div className="bottom">
{error
? "Something went wrong!"
: loading
? "loading"
: firstPage.map((item) => <Card item={item} key={item.id} />)}
</div>
<Pagination
postPerPage={postPerPage}
totalPosts={data.length}
paginate={paginate}
/>
</div>
);
};
export default FeaturedProducts;
pagination.js
import React from "react";
const Pagination = ({ postPerPage, totalPosts, paginate }) => {
const pageNumbers = [];
//for loop
for (let i = 1; i <= Math.ceil(totalPosts / postPerPage); i++) {
pageNumbers.push(i);
}
return (
<div>
<ul className="flex mx-auto items-center justify-center h-[55px]">
{pageNumbers.map((number) => (
<li
key={number}
className=" h-[40px] px-[10px] flex items-center justify-center border-[2px] border-blue-500 boreder-solid text-black font-bold"
>
<button
onClick={() => paginate(number)}
className="h-[40px] w-full flex items-center justify-center px-[10px] text-black font-bold"
>
{number}
</button>
</li>
))}
</ul>
</div>
);
};
export default Pagination;
Please someone should help me, why do i get slice is null?

Related

SendGrid Dynamic Templates + Firebase Functions (Node.js) not erroring, but not sending an email

I am trying to use the dynamic template feature with SendGrid with my Firebase Functions (Node.js), but my mail is not sending for some reason. I get a few errors thrown, but they shouldn't be preventing the email from sending.
When I save the SG template on the web app, I get a pop-up notification saying: Your template has been successfully saved, but we've detected an issue with your handlebars code that requires attention. I have messed around with fixing this and can't find anything to make the "handlebars issue" go away.
On the firebase functions console, I get the below logs:
Any ideas why I am not getting the email in my inbox? Everything was working fine when I was just passing an HTML snippet directly to the send() method.
Node.js snippet:
const heading = "New Website Contact Message!";
const body =
`
<div>
<h3>Message Details:</h3>
<p><b>Name</b>: ${newValues.name}</p>
<p><b>Email</b>: ${newValues.email}</p>
<p>
<b>Message</b>:
<br/>
${newValues.body}
</p>
<hr/>
<p>
You can reply directly to this email to continue the email thread with the user who sent the message.
</p>
</div>
`;
// Pack It
const msg = {
to: sensitiveSiteData.messengers,
from: `${publicSiteData.name} <${publicSiteData.emails.noreply}>`,
replyTo: `${newValues.email}`,
cc: "",
bcc: [],
// Create this template on SendGrid: https://mc.sendgrid.com/dynamic-templates
template_id: "d-3ce711231142141241241241241",
dynamic_template_data: {
"subject": "New " + publicSiteData.name + " Contact Message",
"siteName": publicSiteData.name,
"logoUrl": publicSiteData.logo.url,
"logoWidth": publicSiteData.logo.width,
"heading": heading,
"body": body,
"colors": publicSiteData.theme.schemes.light.colors,
"emails": publicSiteData.emails,
"ppUrl": publicSiteData.projectId + ".web.app/privacy-policy",
"termsUrl": publicSiteData.projectId + ".web.app/terms",
},
text: `${newValues.name} <${newValues.email}>: ${newValues.body}`,
};
// Send it
allPromises.push(
sgMail.send(msg).then(() => {
console.log("Email sent");
}).catch((error: any) => {
console.error(error);
})
);
SendGrid HTML template:
<html>
<head>
<title>{{{ insert heading 'default=Fire React Base Email' }}}</title>
</head>
<body>
<div style="width: 100%; font-family: Arial, Helvetica, sans-serif;">
<div style="text-align: center;">
<img
alt="{{{ insert siteName 'default=Fire React Base' }}} logo"
src="{{{ insert logoUrl 'default=https://firebasestorage.googleapis.com/v0/b/test-fire-react-base.appspot.com/o/public%2Flogos%2Flogo192.png?alt=media' }}}"
width="{{{ insert logoWidth 'default=150' }}}px"
height="auto"
/>
</div>
<h1 style="margin: 20px 0 0 0; text-align: center; color: {{{ insert colors.primary 'default=black' }}} !important;">
{{{ insert siteName 'default=Fire React Base' }}}
</h1>
<div style="margin: auto; width: 80%; padding: 1%;">
<h2>{{{ insert heading 'default=Heading Here' }}}</h2>
<div style="border: solid {{{ insert colors.primary 'default=black' }}} 2px; padding: 5%;">
{{{
insert body
'
default=Tempor officia officia commodo labore do ut qui laboris occaecat nulla esse excepteur. Officia est exercitation ex laborum qui. Nostrud magna excepteur qui incididunt velit eiusmod consequat laborum ea laborum aliquip ut. Id ut fugiat elit adipisicing cillum nulla veniam anim nisi ea velit. Mollit dolore proident minim reprehenderit officia fugiat. Ea ea occaecat dolor est ipsum cupidatat tempor eu dolor amet. In deserunt elit in commodo tempor consectetur id excepteur mollit ea aliquip. Adipisicing incididunt commodo officia amet velit ea deserunt deserunt enim ipsum reprehenderit Lorem elit. Lorem ex pariatur elit ut anim excepteur nostrud nostrud dolore nulla. Ad ex mollit proident enim quis eu ipsum cupidatat irure non quis. Labore veniam consequat pariatur sunt eu quis qui occaecat aute sunt et dolor est ullamco. Sunt Lorem adipisicing id elit.
'
}}}
</div>
<div style="text-align: center; margin: 25px 0; font-size: 14px;">
<p>
Questions? Contact
{{{ insert emails.support 'default=help#company.com' }}}
</p>
<p>
Privacy Policy
Terms & Conditions
</p>
<p>Powered by Company</p>
</div>
</div>
</div>
</body>
</html>

Node Project: EJS rendering white space before text retrieved from MongoDB

Good morning.
I am working in my first real development project using Node/MongoDB stack.
Everything is working as expected except by rendering text in EJS engine when I retrieve a string from DB to show in the page: the text is shown with a lot of white spaces in front of it.
I am trimming the text before sending it to the DB, directly in the model. I also tried to trim the text after retrieving it, with no luck.
What makes me believe the problem is with EJS its the fact that the text, on MongoDB doesn't has any trailing white spaces, but it has in the HTML seen in the browser inspect window.
I've searched through a lot of questions related to undesired white spaces, but did not found anything that could help me, so here I am asking for help, which would be very appreciated.
Thank you in advance!
This is how the text is rendered:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus gravida sem libero. Phasellus convallis tellus vitae imperdiet aliquam. Cras sollicitudin maximus augue, sit amet tincidunt felis. Mauris bibendum sollicitudin iaculis. Fusce eget magna tincidunt, porta lorem eu, semper nunc. Morbi at commodo mi. Aliquam feugiat, sem fringilla imperdiet porta, est nisl ultricies mauris, sed finibus orci odio eget quam. Praesent odio ex, suscipit luctus tempus posuere, suscipit ut nisi. Ut feugiat, velit vitae laoreet malesuada, ligula augue vulputate ligula, ut vulputate sapien neque ut dolor. Maecenas congue enim at nisi porttitor cursus. Etiam convallis neque vel urna molestie, et aliquet tortor congue...
This is how it appears in the Inspect Window:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus gravida sem libero. Phasellus convallis tellus vitae imperdiet aliquam. Cras sollicitudin maximus augue, sit amet tincidunt felis. Mauris bibendum sollicitudin iaculis. Fusce eget magna tincidunt, porta lorem eu, semper nunc. Morbi at commodo mi. Aliquam feugiat, sem fringilla imperdiet porta, est nisl ultricies mauris, sed finibus orci odio eget quam. Praesent odio ex, suscipit luctus tempus posuere, suscipit ut nisi. Ut feugiat, velit vitae laoreet malesuada, ligula augue vulputate ligula, ut vulputate sapien neque ut dolor. Maecenas congue enim at nisi porttitor cursus. Etiam convallis neque vel urna molestie, et aliquet tortor congue.
Nullam suscipit dui turpis, non porta odio egestas at. Sed eu ex tristique, facilisis massa sit amet, eleifend erat. Curabitur eu tempus tellus, sed lacinia nunc. Sed aliquam gravida porta. Vivamus eu luctus leo. Vestibulum condimentum arcu sem, vitae vehicula ligula ultrices eget. Fusce pretium molestie pellentesque. Nam ultrices mattis sapien ut consectetur. Cras et vehicula felis. Suspendisse quis egestas nunc, id tempor tellus. Proin placerat accumsan tristique.
</p>
Here is how it is in MongoDB:
{
_id: ObjectId("624c9293e176a46912503d36"),
title: 'Teste Novo Layout',
ages: '3-7',
sensiblePeriod: 'Matemática',
category: 'Visualização de Dados',
theme: 'Testagem',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus gravida sem libero. Phasellus convallis tellus vitae imperdiet aliquam. Cras sollicitudin maximus augue, sit amet tincidunt felis. Mauris bibendum sollicitudin iaculis. Fusce eget magna tincidunt, porta lorem eu, semper nunc. Morbi at commodo mi. Aliquam feugiat, sem fringilla imperdiet porta, est nisl ultricies mauris, sed finibus orci odio eget quam. Praesent odio ex, suscipit luctus tempus posuere, suscipit ut nisi. Ut feugiat, velit vitae laoreet malesuada, ligula augue vulputate ligula, ut vulputate sapien
neque ut dolor. Maecenas congue enim at nisi porttitor cursus. Etiam convallis neque vel urna molestie, et aliquet tortor congue.\r\n' +
' \r\n' +
' \r\n' +
' \r\n' +
' Nullam suscipit dui turpis, non porta odio egestas at. Sed eu ex tristique, facilisis massa sit amet, eleifend e
rat. Curabitur eu tempus tellus, sed lacinia nunc. Sed aliquam gravida porta. Vivamus eu luctus leo. Vestibulum condimen
tum arcu sem, vitae vehicula ligula ultrices eget. Fusce pretium molestie pellentesque. Nam ultrices mattis sapien ut co
nsectetur. Cras et vehicula felis. Suspendisse quis egestas nunc, id tempor tellus. Proin placerat accumsan tristique.',
owned: 'Sim',
picture: 'fatherhood.svg',
date: ISODate("2022-04-05T18:59:49.801Z"),
reviews: [],
user: ObjectId("624c8dfdd0c88d172dfeebee"),
__v: 0
}
This is my Model
//File Requirements
const mongoose = require('mongoose');
const Review = require('./review');
const Schema = mongoose.Schema;
//Local variables
const sensiblePeriods = ['Movimento', 'Linguagem', 'Detalhes', 'Ordem', 'Desenvolvimento dos Sentidos', 'Refinamento dos Sentidos', 'Graça e Cortesia', 'Música e Ritmo', 'Escrita', 'Leitura', 'Matemática']
//Activity Schema
const ActivitySchema = new Schema({
title: {
type: String,
required: true
},
ages: {
type: String,
required: true
},
sensiblePeriod: {
type: String,
//enum limits the options to those inside the array
enum: sensiblePeriods,
required: true
},
category: {
type: String,
},
theme: {
type: String,
},
description: {
type: String,
required: true,
trim: true
},
owned: {
type: String,
required: true,
default: 'Não'
},
picture: {
type: String,
default: 'fatherhood.svg'
},
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
date: {
type: Date,
default: Date.now()
//required: true
},
reviews: [
{
type: Schema.Types.ObjectId,
ref: 'Review'
}
]
})
ActivitySchema.post('findOneAndDelete', async function (doc) {
if (doc) {
await Review.deleteMany({
_id: {
$in: doc.reviews
}
})
}
})
//"Compile" Schema
const Activity = mongoose.model('Activity', ActivitySchema);
//Export module to be used elsewhere
module.exports = Activity;
This is the controller taking the information for the route:
module.exports.details = async (req, res, next) => {
const activity = await Activity.findById(req.params.id).populate({
path: 'reviews',
populate: {
path: 'user'
}
}).populate('user');
if (!activity) {
req.flash('error', 'Atividade não encontrada!')
return res.redirect('/atividades')
}
res.render('atividades/detalhes', { activity });
}
And, finally, this is my EJS file:
<%- include('../partials/head') %>
<div class="row mb-3">
<div class="col-md-6">
<div class="card mb-3">
<img src="/public/img/<%=activity.picture%>" alt="" class="card-img-top">
<div class="card-body">
<h3 class="card-title">
<%=activity.title%>
</h3>
<p class="card-text">
<!-- This is the line which renders the text -->
<%=activity.description%>
<!-- ----------------------------- -->
</p>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item"><b>Dono: </b>
<%=activity.user.username%>
</li>
<li class="list-group-item"><b>Idades: </b>
<%=activity.ages%>
</li>
<li class="list-group-item"><b>Período Sensível: </b>
<%=activity.sensiblePeriod%>
</li>
<li class="list-group-item"><b>Categoria: </b>
<%=activity.category%>
</li>
<li class="list-group-item"><b>Tema: </b>
<%=activity.theme%>
</li>
</ul>
</div>
<% if(currentUser && activity.user.equals(currentUser._id)) {%>
<div class="card mb-3">
<div class="card-body">
<h4 class="card-text mb-3">Área de Risco</h4>
Editar Atividade
<form class="d-inline" action="/atividades/<%=activity._id%>/?_method=DELETE" method="POST">
<button class="btn btn-danger">Excluir Atividade</button>
</form>
</div>
</div>
<% } %>
<p><a class="card-link" href="/atividades">Voltar à todas as atividades</a></p>
</div>
<div class="col-md-6">
<!-- <h2 class="text-center card-title mb-2">Comentários</h2> -->
<% if(currentUser) {%>
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title text-center mb-3">Incluir Comentário
</h4>
<form action="/atividades/<%=activity._id%>/reviews" method="POST">
<div class="row mb-3">
<div class="col">
<div>
<label class="form-label" for="title">Título</label>
</div>
<div>
<input class="form-control" type="text" name="review[title]" id="title" size="26">
</div>
</div>
<!-- <div class="col">
<div class="form-outline">
<div>
<label class="form-label" for="date">Data</label>
</div>
<div>
<input class="form-control" type="date" name="review[date]" id="date">
</div> -->
<!-- </div>
</div> -->
</div>
<div class="mb-3">
<div><label class="form-label" for="body">Comentário</label></div>
<div><textarea class="form-control" name="review[body]" id="body" cols="42" rows="5"></textarea>
</div>
</div>
<button class="btn btn-success">Incluir Comentário</button>
</form>
</div>
</div>
<% } %>
<% const reviews=activity.reviews %>
<% for(let review of reviews) { %>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">
<%= review.title %>
</h5>
<h6 class="card-subtitle">
Autor: <%= review.user.username %>
</h6>
<% const dbDate=review.date.toISOString()%>
<% const day=dbDate.substring(8,10)%>
<% const month=dbDate.substring(5,7)%>
<% const year=dbDate.substring(0,4)%>
<% const lastUpdated=`${day}/${month}/${year}` %>
<p class="text-secondary">
Última Atualização: <%= lastUpdated %>
</p>
<p>
<%= review.body %>
</p>
<% if(currentUser && review.user.equals(currentUser._id)) {%>
<a href="/atividades/<%= activity._id %>/reviews/<%=review._id%>"
class="btn btn-sm btn-info">Editar Comentário</a>
<form class="d-inline"
action="/atividades/<%= activity._id %>/reviews/<%=review._id%>?_method=DELETE "
method="post">
<button class="btn btn-sm btn-danger">Excluir Comentário</button>
</form>
<% } %>
</div>
</div>
<%}%>
</div>
</div>
</div>
<%- include('../partials/foot') %>

How do I create a sticky (non scrollable) header/footer in a FluentUI modal control?

Using a React Fluent UI Modal Control, could someone please show me how to:
Ensure the header and footer are not part of the scrollable content (i.e. they are 'sticky', while the main content sitting between them is scrollable if the window size is insufficient).
Minimise the change in modal size as content changes - that is the window sizes to the viewport as initially, but as the content changes dynamically, the modal maintains it original size.
Below is an edited example from the relevant Microsoft documentation. I have also put it in this codepen which works (unlike the snippet). Clicking the button in the footer of the modal control alters the amount of content.
const { useBoolean } = window.FluentUIReactHooks;
const { getTheme, mergeStyleSets, FontWeights, ContextualMenu, Toggle, Modal, IDragOptions, IIconProps, Stack, IStackProps, DefaultButton, IconButton, IButtonStyles, ThemeProvider, initializeIcons, Separator, PrimaryButton } = window.FluentUIReact;
// Initialize icons in case this example uses them
initializeIcons();
const ModalBasicExample: React.FunctionComponent = () => {
const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
const [pageNo, setPageNo] = React.useState(0);
const changePage = React.useCallback(() => setPageNo(oldVal => ~oldVal),[setPageNo])
const titleId = "titleId";
return (
<div>
<DefaultButton onClick={showModal} text="Open Modal" />
<Modal
titleAriaId={titleId}
isOpen={isModalOpen}
onDismiss={hideModal}
isBlocking={false}
containerClassName={contentStyles.container}
topOffsetFixed={true}
>
<div className={contentStyles.header}>
<span id={titleId}>Lorem Ipsum</span>
<IconButton
styles={iconButtonStyles}
iconProps={cancelIcon}
ariaLabel="Close popup modal"
onClick={hideModal}
/>
</div>
<div className={contentStyles.body}>
{pageNo===0 ? <div dangerouslySetInnerHTML={{
__html:lorem}}></div> : <p>page {pageNo}</p>}
</div>
<footer className={contentStyles.footer}>
<Separator/>
<PrimaryButton text="switch" onClick={changePage}/>
</footer>
</Modal>
</div>
);
};
const cancelIcon: IIconProps = { iconName: 'Cancel' };
const theme = getTheme();
const contentStyles = mergeStyleSets({
container: {
display: 'flex',
flexFlow: 'column nowrap',
alignItems: 'stretch',
},
header: [
// eslint-disable-next-line deprecation/deprecation
theme.fonts.xLargePlus,
{
flex: '1 1 auto',
borderTop: `4px solid ${theme.palette.themePrimary}`,
color: theme.palette.neutralPrimary,
display: 'flex',
alignItems: 'center',
fontWeight: FontWeights.semibold,
padding: '12px 12px 14px 24px',
},
],
body: {
flex: '4 4 auto',
padding: '0 24px 24px 24px',
overflowY: 'hidden',
selectors: {
p: { margin: '14px 0' },
'p:first-child': { marginTop: 0 },
'p:last-child': { marginBottom: 0 },
},
},
footer: {
}
});
const iconButtonStyles: Partial<IButtonStyles> = {
root: {
color: theme.palette.neutralPrimary,
marginLeft: 'auto',
marginTop: '4px',
marginRight: '2px',
},
rootHovered: {
color: theme.palette.neutralDark,
},
};
const lorem = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc suscipit, est eget porta tempor, ante justo finibus odio, sit amet rhoncus neque velit nec leo. Morbi vitae ex a urna auctor sagittis dictum at ante. Etiam vel commodo turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean dapibus malesuada luctus. Vivamus nec convallis dolor, nec condimentum ligula. Aenean blandit mi et justo rutrum, sed feugiat erat gravida. Donec sit amet eleifend mauris. Duis eget leo vel elit viverra ullamcorper. Quisque eu purus nec diam convallis suscipit.</p>".repeat(7);
const ModalBasicExampleWrapper = () => <ThemeProvider><ModalBasicExample /></ThemeProvider>;
ReactDOM.render(<ModalBasicExampleWrapper />, document.getElementById('content'))
<script src="https://unpkg.com/#fluentui/react#8/dist/fluentui-react.js"></script>
<script src="https://unpkg.com/#fluentui/react-hooks#8/dist/react-hooks.js"></script>
<div id="content"></div>

How to set up a react app to work with carousel without fading images the image

import React from 'react';
import { Carousel } from 'react-bootstrap';
import "./HomePage.css";
import img1 from '../../img/car_polising.jpg';
import img2 from '../../img/polishing-light.jpg';
import img3 from '../../img/spoljasnje-pranje-vozila.jpg';
export default class HomePage extends React.Component {
render() {
return (
<Carousel controls={false} >
<Carousel.Item>
<img
className="d-block w-100"
src={img1}
alt="First slide"
/>
<Carousel.Caption>
<h3>First slide label</h3>
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item>
<img
className="d-block w-100"
src={img2}
alt="Second slide"
/>
<Carousel.Caption>
<h3>Second slide label</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</Carousel.Caption>
</Carousel.Item>
<Carousel.Item>
<img
className="d-block w-100"
src={img3}
alt="Third slide"
/>
<Carousel.Caption>
<h3>Third slide label</h3>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>
</Carousel.Caption>
</Carousel.Item>
</Carousel>
)
}
}
When I launch the application, the first image disappears and only then the next one appears.
There is no real slide where one image pushes another. I don't understand what the problem is.
React app works in strict mode. When I throw out strict mode it behaves the same.

Jade looping through db to build <div>, each one with 3 block of content using bootstrap ? Example provided

I am using this theme http://twbs.github.io/bootstrap/examples/justified-nav/
I want to instantiate the documents of my collections in jade view and (create pagination later on), but my question is about having an HTML or Jade example just to figure out the further process.
this is my div to loop:
<div class="row">
<div class="col-lg-4">
<h2>Safari bug warning!</h2>
<p class="text-danger">As of v7.0.1, Safari exhibits a bug in which resizing your browser horizontally causes rendering errors in the justified nav that are cleared upon refreshing.</p>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa.</p>
<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>
</div>
</div>
Let say I have just 12 documents in my collection, how do I loop trough my collection to create
4 <div class="row"> and each one of these <div class="row"> have 3 <div class="col-lg-4"> and
each <div class="col-lg-4"> have a:
<h2>= product.title
<p> = product.imgurl
<p> = product.description
<p> = prodcuct.url
I know how to route, access the db, display on jade engine...I made simple test
all successful, but to get to the next-level I would appreciate some explanations or a small example.
I resolved myself:
each product, i in products
div
div
h1 = product.title
p = product.imgurl
p = product.description
p = prodcuct.url
I just made a small, quick and dirty example out of your provided informations, I hope it will help you to do the last few steps to get familiar with Jade and co.
First your collection, just a small example (only with 8 examples):
{
products: [{title: 'xyz', imgurl: 'http://www.example.com/img.jpeg',
description: 'more text',
url: 'http://www.example.com/'},
{title: 'abc', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/another'},
{title: 'fgh', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/another'},
{title: 'tgb', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/another'},
{title: 'qwe', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/anotherz'},
{title: 'asd', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/anothery'},
{title: 'hjk', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/anotherx'}]
}
This is what you pass through res.render in your node app.
Next we have your Jade markup, your example is not that wrong, I changed only a few things here:
- for (var i = 0; i < products.length; i += 4)
div.row
- for (var j = i; j < 3+i; j++)
div(class="col-lg-4")
h1= products[j].title
p= products[j].imgurl
p= products[j].description
p= products[j].url
Like you see, I put your <div class="row"> between two loops (I used for loops here, it would be easier if you pass your data in an other way. What I try to say: This example is not fail safe, e.g. if you don't have data that has 3 cols you will get an error like Cannot read property 'title' of undefined - so here you have to set exceptions), so we don't get more than one per 3 iterations, your example would produce one div per iteration.
A class can be added by a dot. For example div.yourClass or just with div(class="yourClass" style="..." whatever="...").
Next we have the loop, after that given <div class="col-lg-4 "> for your collection data. Your data can be displayed by either tag= var or tag #{var}.
The rest should be simple to guess.
This will produce following HTML code:
<div class="row">
<div class="col-lg-4">
<h1>xyz</h1>
<p>http://www.example.com/img.jpeg</p>
<p>more text</p>
<p>http://www.example.com/</p>
</div>
<div class="col-lg-4">
<h1>abc</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/another</p>
</div>
<div class="col-lg-4">
<h1>fgh</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/another</p>
</div>
</div>
<div class="row">
<div class="col-lg-4">
<h1>qwe</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/anotherz</p>
</div>
<div class="col-lg-4">
<h1>asd</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/anothery</p>
</div>
<div class="col-lg-4">
<h1>hjk</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/anotherx</p>
</div>
</div>
You see the <p> tag for links makes here not that much sense, but you can easily change them to an <a> tag, it is always the same procedure.
Important, in your Jade markup, is the right indentation, everything shifted is between the opening tag and the close tag.
So the loop is in div row, the data in your cols.

Resources