Meteor and getting carousel to render dynamically with #each - meteor

Like slick. Struggling to get it working w/ dynamic dataset from Meteor. Problem that I now have, when opening prior instances of an item I'm left w/ ghost blank slides from priorly selected. If I open an item that has 15 images, close it and select another w/ 1 - I have 14 blank slide. Also, if I had clicked through the 15, say to the 7th slide, when I open the new item w/ 1 I'm still pointed at slide 7, which is blank, and need to click 6 slides to the left to actually see an image.
It would seem to me that I need to somehow reset the slick control? I'm just not sure where of how to do it.
Followed instructions here: Image slider doesn't show my images properly before they're cached to get up and running.
parent template
<div class="col-md-7">
<div class="gallery">
{{#each galleryImages}}
{{> slickItem}}
{{/each}}
</div>
</div>
slick template
<template name="slickItem">
<img class="slick-image" src="{{href}}">
</template>
I've played around w/ a few different options on the slick render.
Template.slickItem.onRendered(function() {
setTimeout(function() {
$('.gallery').slick({
arrows: true,
dots: false,
autoplay: false,
infinite: true,
mobileFirst: true,
adaptiveHeight: true
})
}, 100);
});

Working with friend Patrick Lewis we worked out the following - done now in React versus Blaze.
Carousel = React.createClass({
getInitialState: function() {
return {
carousel : null
}
},
componentDidMount() {
console.log("componentDidMount");
this.setState({
// carousel: $('#maveletCarousel')
carousel: $(this.props.id)
}, function() {
console.log("carousel: componentDidMount", this.state);
this.state.carousel.carousel();
});
},
initCarousel: function() {
// $('#maveletCarousel').carousel();
// Initialize the carousel
if( this.state.carousel ) {
this.state.carousel.carousel({
interval : 2000
});
}
},
render() {
var hrefId = "#" + this.props.id;
// <li data-target={hrefId} key={ index } data-slide-to={ index } className={ indicatorClass }></li>
return (
<div id={this.props.id} className="carousel slide">
<ol className="carousel-indicators">
{
this.props.slides.map((slide, index) => {
return (
<li data-target={hrefId} key={ index } data-slide-to={ index }></li>
);
})
}
</ol>
<div className="carousel-inner" role="listbox">
{
this.props.slides.map((slide, index) => {
return (
slide && <Slide slide={ slide } key={ index } index={ index } initCarousel={ this.initCarousel }/>
);
})
}
</div>
<a className="left carousel-control" href={ hrefId } role="button" data-slide="prev">
<span className="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span className="sr-only">Previous</span>
</a>
<a className="right carousel-control" href={ hrefId } role="button" data-slide="next">
<span className="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span className="sr-only">Next</span>
</a>
</div>
);
}
});
Slide = React.createClass({
componentDidMount() {
this.props.initCarousel();
},
render() {
var isActive = 'item'
if( this.props.index === 0 ) {
isActive = 'item active'
}
return (
<div className={ isActive }>
<img src={this.props.slide.href}></img>
</div>
)
}
})

Related

How to add a class on click, and remove the same class from all other elements?

I have a button navigation and when you click on a button, the active class is added. My goal is for the active class to be added to the button clicked, but remove that class of active on all other buttons if present. The 'About' button will have a class of active on page load.
Not sure how to translate this to React, in JavaScript on click I would remove the class from all the elements in a loop and add a class to the target clicked if it did not already have the active class.
Code Sandbox - https://codesandbox.io/s/toggle-active-on-class-clicked-remove-from-the-rest-r467l1?file=/src/App.js
export default function Header() {
const [active, setActive] = useState(true);
const toggleColor = function (e) {
// on load, 'About' button has active class
// when clicking another menu item add active class, remove active from the rest of buttons
console.log(e.target);
};
return (
<header className="header-img-container">
<nav>
<ul>
<li>
<button onClick={toggleColor} className={active ? "active" : ""}>
About
</button>
</li>
<li>
<button onClick={toggleColor}>Skills</button>
</li>
<li>
<button onClick={toggleColor}>Projects</button>
</li>
<li>
<button onClick={toggleColor}>Words</button>
</li>
</ul>
</nav>
</header>
);
}
There are so many ways to solve that problem. You can try this if it's meet your requirements.
import "./styles.css";
import { useState } from "react";
const list = ["About", "Skills", "Projects", "Words"];
export default function Header() {
const [activeLink, setActiveLink] = useState("About");
return (
<header className="header-img-container">
<nav>
<ul>
{list.map((item) => (
<li key={item}>
<button
onClick={() => setActiveLink(item)}
className={activeLink === item ? "active" : ""}
>
{item}
</button>
</li>
))}
</ul>
</nav>
</header>
);
}
Create a state like this
const [active, setActive] = useState({About: true, Skills: false, Projects: false, Words: false})
А change local parameter to add a class to element. For example
<li>
<button onClick={() => {
setActive({...active, About: false, Skills: true, Projects: false,
Words: false })
}}>Skills</button>
</li>
There are many possible approaches, here is a basic example that uses an object type active state to store the value for each list item.
const [active, setActive] = useState({ About: true })
The list data is stored in an array so it can be mapped in the JSX part of the component.
const itemList = ["About", "Skills", "Projects", "Words"]
While index is not an ideal key it is used here just for example purpose.
{
itemList.map((item, index) => (
<li key={index}>
<button
onClick={() => toggleColor(item)}
className={active[item] ? "active" : ""}
>
{item}
</button>
</li>
));
}
toggleColor sets value for active, and it specify that active should always be in the format of {About: true}, {Skills: true} and such. The !!! covers the case when certain keys are not existing in the object.
const toggleColor = function (item) {
setActive((prev) => {
return { [item]: !!!prev[item] };
});
};
Below is the full example, it runs in the snippet for convenience.
function Header() {
const [active, setActive] = React.useState({ About: true });
const itemList = ["About", "Skills", "Projects", "Words"];
const toggleColor = function (item) {
// on load, 'About' button has active class
// when clicking another menu item add active class, remove active from the rest of buttons
setActive((prev) => {
return { [item]: !!!prev[item] };
});
};
return (
<header className="header-img-container">
<nav>
<ul>
{itemList.map((item, index) => (
<li key={index}>
<button
onClick={() => toggleColor(item)}
className={active[item] ? "active" : ""}
>
{item}
</button>
</li>
))}
</ul>
</nav>
</header>
);
}
const App = () => {
return (
<div>
<Header />
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
.App {
font-family: sans-serif;
text-align: center;
}
button {
padding: 6px;
}
.active {
border: 1px solid pink;
color: hotpink;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

React change state triggers transition

I have the following react component
export interface IDivBodyVisible {
isVisible: string;
}
export default class NavDropDownItem extends React.Component<{ItemContent: string}, IDivBodyVisible> {
constructor(props: any) {
super(props);
this.state = {
isVisible: 'none'
}
}
render() {
return (
<div className="divBox" >
<div className="divHeader" onClick={this.SwitchVisibility}>
<Icon className="icon" iconName="ChevronDown"/>
{this.props.ItemContent}
</div>
{
this.state.isVisible !== 'block' ? null :
<div className="divBody">
<ul className="ItemList">
<li>
<a className="miau" title="item1" onClick={this.ConsoleLog}>Item 1</a>
</li>
<li>
<a title="item2" onClick={this.ConsoleLog}>Item 2</a>
</li>
<li>
<a title="item3" onClick={this.ConsoleLog}>Item 3</a>
</li>
</ul>
</div>
}
</div>
)
}
private ConsoleLog = () : void => {
console.log("Test");
}
private SwitchVisibility = (): void => {
this.setState({
isVisible : this.state.isVisible === 'none' ? 'block' : 'none'
});
}
}
At the moment if I click on the icon, the divbody appears instantly. Instead, I want that the divbody slights very smooth. I already tried to give the .divBox a transition ease-out 0.2, but that didn´t do anything.
Is there any advice what I can try?

How do I scroll up and down a SideBar rather than the whole window?

I will only show relevant code as there is a lot of it. This is the parent component App:
export default class App extends React.Component {
render() {
return (
<nav className="navbar navbar-expand-xl navbar-side" aria-label="Side Navigation">
<div className={`navbar-toggler ${this.state.notification ? 'has-notification' : ''}`} data-toggle="collapse" data-target="#sidebarCollapse" aria-controls="sidebarCollapse" aria-expanded="false" aria-label="Toggle side navigation">
Menu
</div>
<div className="collapse navbar-collapse" id="sidebarCollapse">
<ul className="navbar-nav mr-auto">
<li className="nav-user">
<div className="profile-pic">
<i className="fa fa-lg fa-user mt-1" />
</div>
<i><span>{this.state.authenticatedUser.first_name} {this.state.authenticatedUser.last_name}</span><br />{this.state.authenticatedUser.job_title}</i>
</li>
<NavBar />
</ul>
</div>
</nav>
)
}
This is the Navbar component:
class NavBar extends Component {
constructor(props) {
super(props);
this.state = {
auth: false,
slide: 0, // How much should the Navbar slide up or down
lastScrollY: 0, // Keep track of current position in state
}
}
componentWillMount() {
let navbar = document.getElementById('navbar-div');
navbar.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
let navbar = document.getElementById('navbar-div');
navbar.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
let navbar = document.getElementById('navbar-div');
const { lastScrollY } = this.state;
const currentScrollY = navbar.scrollY;
if (currentScrollY > lastScrollY) {
this.setState({ slide: '-48px' });
} else {
this.setState({ slide: '0px' });
}
this.setState({ lastScrollY: currentScrollY });
};
render() {
return (
<div className="navbar-div" id="navbar-div">
{this.adminMenu()}
{this.usersMenu()}
</div>
);
}
}
adminMenu and usersMenu are just arrays of objects which output the object names. The error I get says navbar is null hence it cannot add an event listener onto a null object. How do I solve this?
Use componentDidMount rather than componentWillMount. The latter will run before any markup is rendered.
You can read more about lifecycle methods here: https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class
However, I'd highly recommend you to apply a handler on the element instead of componentDid/Will/Mount/Unmount, like this:
render() {
return (
<div className="navbar-div" id="navbar-div" onScroll={this.handleScroll}>
{this.adminMenu()}
{this.usersMenu()}
</div>
);
}

react collapisble panel css issue

I'm trying to add a Collapsible in my project. The functionality works simply. But there is a CSS issue in collapsible. When I click on a header the collapsible panel opens on after all the header. I want to open the collapsible panel next to each header. I'm using react-collapsible package.
Here is my code,
return (
assignTasklist && assignTasklist.map((assign) =>
<div className="dashboard-tasklists-group_header">
<div id={assign.TaskType} className={ "dashboard-tasklists-group_header-left"} onClick={()=> {
// e.preventDefault();
// e.stopPropagation();
this.onToggleAccordion(assign.TaskType)}}>
{assign.Description}
</div>
<div className="dashboard-tasklists-group_header-right">
<button className="dashboard-tasklists-group_header-caret-button" onClick={()=> {
// e.preventDefault();
// e.stopPropagation();
this.onToggleAccordion(assign.TaskType)}}>
<CaretIcon />
</button>
</div>
</div>
)
);
}
render() {
const { assignDetails } = this.props;
return <div className="dashboard-tasklists-group">
<Collapsible trigger={this.groupWorkingHeader()} /* handleTriggerClick={() => {
}}open={this.state.testflag} */ >
{assignDetails && assignDetails.length>0 && <div className="dashboard-index_announcements-wrapperWP" style={{cursor:'pointer'}}>
<div /* className="dashboard-index_announcements" */ style={{maxHeight: '240px',overflowY: "scroll"}}>
{assignDetails.map(patient =>
<div onClick={()=> { browserHistory.push(`/patientsTask/${patient.PatientID}`); }} className="showingdet"><span style={{fontWeight:700}}>{patient.PatientID}</span>-{patient.Name}</div>
)}
</div>
</div>}
</Collapsible>
</div>;
}
Please help me to solve

How to bind class to a div based on some conditions where the condition is not based upon only true or false condition using Vue.js?

Actually, I need to activate the background color of a div based on the specific value given by the user. So I have done something like this. And don't know how to go further.
<template>
<div>
<div class="row" style="padding-left:6vw; padding-right:6vw;">
<button #click="r_id = 1"><q-icon name="thumb_up" class="reaction col-auto" style="font-size: 3rem;" /></button>
<button #click="r_id = 2"><q-icon name="ion-happy" class="reaction col-auto" style="font-size: 3rem;" /> </button>
<button #click="r_id = 3"><q-icon name="ion-ios-heart" class="reaction col-auto" style="font-size: 3rem;" /> </button>
<button #click="r_id = 4"><q-icon name="ion-sad" class="reaction col-auto" style="font-size: 3rem;" /></button>
<button #click="r_id = 5"><q-icon name="thumb_down" class="reaction col-auto" style="font-size: 3rem;" /></button>
</div>
<div class="button-group">
<q-btn class="button" push color="amber-7" style="width: 75px" #click="Reset()">Reset</q-btn>
<q-btn class="button" push color="positive" style="width: 75px" #click="Submit()">Submit</q-btn>
</div>
</div>
<div v-bind:class="[{active1: r_id === 1},{active2: r_id === 2},{active3: r_id === 3},{active4: r_id === 4},{active5: r_id === 5}]" >
Mycard
</div>
<template>
And my script part is:
export default {
components: {
QBtn,
QIcon
},
data () {
return {
r_id: '',
name: '',
toName: ''
}
},
computed: {
className () {
return 'active' + this.r_id
}
},
methods: {
Submit: function () {
this.hardcode = {
'r_id': this.r_id,
'user_name': 'Shine',
'fb_title': this.fbTitle,
'fb_id': this.id,
'fb_descrption': this.fbDescription,
'created_time': '10 hours ago',
'user_id': '1'
}
this.fbList.push(this.hardcode)
this.Reset()
this.id++
}
}
and my css part is:
active1{background:red;}
active2{background:black;}
active3{background:green;}
active4{background:yellow;}
active5{background:white;}
So how should I go on using Vuejs?
Seems like r_id already have the correct number so just use a simple computed property:
<div :class="className" >
Mycard
</div>
computed: {
className () {
return 'active' + this.r_id
}
}

Resources