I am implementing a customized dropdown becuase of the requirements we have, using Vue 2 and typescript (jquery is not an option).
It is working fine, when you click on the main box, it opens the options list downwards.
An improvement I am looking for is that, when at the end of the screen, the options list adds to the page height and thus causing the scrollbar to appear or increase scroll height.
What I am looking for is that, when popping up the div, if there's not enough space at the bottom of the screen, open it upwards instead. How do I achieve this?
(classes are using bootstrat 5)
Opened dropdown &
Closed dropdown
My code:
import Vue, {
PropType
} from 'vue';
import {
Validation
} from 'vuelidate';
let uidc = 0;
export default Vue.extend({
name: 'BaseDropdown',
props: {
value: {
type: [Number, String, Object],
default: () => ''
as string,
},
target: {
type: String,
default: '',
},
label: {
type: String,
default: '',
},
valueIsNumber: {
type: Boolean,
default: false,
},
options: {
type: Array,
default: null,
},
placeholder: {
type: String,
default: '',
},
required: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
validations: {
type: Object as PropType < Validation > ,
default: () => ({
$error: false,
$touch: () => undefined,
$params: {},
}) as Validation,
},
error: {
type: Boolean,
default: false,
},
trackEvent: {
type: String,
default: '',
},
trackField: {
type: String,
default: '',
},
trackPublic: {
type: Boolean,
default: false,
},
padLeft: {
type: Boolean,
default: false,
},
enforceBlackColour: {
type: Boolean,
default: false,
},
customStyled: {
type: Boolean,
default: false,
},
borderBottomWarning: {
type: Boolean,
default: false,
},
},
data(): {
selectedItem: any | null;
menuOpen: boolean;
searchText: string | null;
} {
return {
selectedItem: null,
menuOpen: false,
searchText: null,
};
},
mounted() {
const appElement = document.getElementById('app_home');
(appElement as any).addEventListener('click', this.handleDropdownClickOutside);
this.$nextTick(() => {
if (this.value) {
if (this.valueIsNumber) {
this.selectedItem = this.options.find((x: any) => x.value === Number(this.value)) || null;
} else {
this.selectedItem = this.options.find((x: any) => x.value.toString().toLowerCase() === this.value.toString().toLowerCase()) || null;
}
}
});
},
computed: {
v(): Validation | {} {
return this.validations;
},
errorMessage(): string {
// Validation must be cast to any to access validators
return Object.entries((this.v as Validation).$params).find(([k]) => !(this.v as any)[k]) ? .[1].message;
},
optgroups(): any {
return this.options.reduce((acc: any, o: any) => ({ ...acc,
[o.optgroup]: [...(acc[o.optgroup] || []), o]
}), {});
},
isRequired(): boolean {
return this.required !== false;
},
getSelectedItemText(): string | null {
return this.selectedItem ? this.selectedItem.text : this.placeholder || 'Please select an item';
},
filteredItems(): any[] {
const list: any[] = [];
for (let c = 0; c < 10; c += 1) {
list.push({
text: c,
value: c
});
}
// return this.searchText && this.searchText.length > 0 ? this.options.filter((x: any) => x.text.toLowerCase().indexOf(this.searchText!.toLowerCase()) > -1) : this.options;
return list;
},
},
methods: {
openMenu() {
this.menuOpen = !this.menuOpen;
if (this.menuOpen) {
this.searchText = null;
}
},
selectItem(item: any) {
this.selectedItem = item;
this.$emit('input', item.value);
this.menuOpen = false;
},
setSuppliedSelectedItem() {
this.$nextTick(() => {
if (this.value) {
this.selectedItem = this.options.find((x: any) => x.value === this.value) || null;
}
});
},
handleDropdownClickOutside(event: any): void {
const parent = document.getElementById(`select-${(this as any).uid}`);
const isParent = parent !== event.target && parent ? .contains(event.target);
if (!isParent) {
this.menuOpen = false;
// this.closeOpenendMenu();
// this.searchText = '';
}
},
},
beforeCreate() {
// eslint-disable-next-line no-plusplus
(this as any).uid = uidc++;
},
});
.dropdown {
font-size: 0.7rem;
img {
// float: right;
// padding-right: 10px;
// padding-top: 5px;
position: absolute;
top: 40%;
right: 10px;
}
.fade {
opacity: 0.5;
}
.search-box {
.form-control {
font-size: 12px !important;
height: 30px !important;
margin: 0 10px 5px 10px !important;
width: 95% !important;
}
}
.selected-item {
border-radius: 3px;
border: 1px solid #ced4da;
padding: 10px;
.selected-item-text {
text-overflow: ellipsis;
overflow: hidden;
width: 93%;
/* height: 1.2em; */
white-space: nowrap;
}
}
.items {
border: 1px solid rgb(236, 236, 236);
width: 100%;
z-index: 15;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
background-color: white;
}
.item {
padding: 10px;
background-color: rgb(240, 240, 240);
cursor: pointer;
&:hover {
background-color: rgb(216, 216, 216);
}
}
}
.hidden {
opacity: 0.2;
}
.disabled {
background-color: #e9ecef;
opacity: 1;
pointer-events: none;
}
<template>
<div class="mt-2" :id="`select-${uid}`">
<label v-show="label" class="mb-2 label-grey" :class="{ 'required': isRequired }" :for="`select-${uid}`">{{ label }}</label>
<div class="dropdown noselect position-relative" :class="{'disabled': disabled}">
<div class="selected-item cursor-pointer" #click="openMenu">
<div class="selected-item-text" :class="{'fade': !selectedItem}">{{getSelectedItemText}}</div>
<img v-if="menuOpen" :src="constants.icons.arrowTop" />
<img v-else :src="constants.icons.arrowDown" />
</div>
<div class="items position-absolute" v-show="menuOpen">
<div v-if="filteredItems && filteredItems.length > 5 || searchText" class="search-box">
<input :size="'sm'" v-model="searchText" />
</div>
<div v-for="item in filteredItems" :key="item.value" #click="selectItem(item)">
<div class="item">
{{item.text}}
</div>
</div>
</div>
</div>
<span v-if="v.$error" class="text-error text-xs font-light">{{ errorMessage }}</span>
</div>
</template>
Suggest to use Floating-ui (well known as Poper)
Floating UI is a low-level library for positioning "floating" elements...intelligently keeping them in view
It's been using widely and cover a lot of edge cases you might encounter when try to create dropdown yourself
You can try with references here
creating-vue-component-dropdown-with-popper-js
floating-vue/dropdown
Iam using react Autosuggest component for city country list. When an input is given the suggested list of cities name with their respective countries is displayed. I am able to change the background color while hovering, but, I want to change when key pressed 'up' or 'down'. Following is the code for reference
Form.js
const getSuggestions = value => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
return inputLength === 0 ? [] : cities.filter(data =>
data.name.toLowerCase().slice(0, inputLength) === inputValue
).slice(0,4);
};
// When suggestion is clicked, Autosuggest needs to populate the input
// based on the clicked suggestion.
const getSuggestionValue = suggestion => suggestion.name
const renderSuggestion = suggestion =>
(
<table className='auto-complete'>
<tbody>
<ArrowTooltip title={suggestion.name + ', ' + countries.getName(suggestion.country,"en")} placement="top">
<tr>
<td style={{ width: '88%' }} dangerouslySetInnerHTML=
{highlight(suggestion.name, suggestion.value)}></td>
<td style={{ width: '12%' }}>{suggestion.country}</td>
</tr>
</ArrowTooltip>
</tbody>
</table>
);
class Form extends React {
constructor() {
super();
this.state = {
value: '',
suggestions: []
};
}
onChange = (event, { newValue, method }) => {
this.setState({
value: newValue,
});
if(method == 'up' || method == 'down') {
// Here the value is triggered when key pressed
console.log('KEY UP/DOWN')
}
};
onSuggestionsFetchRequested = ({ value }) => {
this.setState({
suggestions: getSuggestions(value)
});
};
// Autosuggest will call this function every time you need to clear suggestions.
onSuggestionsClearRequested = () => {
this.setState({
suggestions: []
});
};
onSuggestionSelected = (event, {suggestion}) => {
const isSuggestion = true
this.props.getWeather(suggestion, isSuggestion)
}
render() {
const { value, suggestions} = this.state;
// Autosuggest will pass through all these props to the input.
const inputProps = {
placeholder: 'Search City...',
value,
onChange: this.onChange
};
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
onSuggestionSelected={this.onSuggestionSelected}
/>
}
}
export default Form
CSS required for suggestions (which is to be styled)
Form.css
.react-autosuggest__suggestions-container {
display: none;
}
.react-autosuggest__suggestions-container--open {
display: block;
perspective: 1000px;
position:absolute;
top: 30px;
width: 180px;
font-family: 'Oxygen';
font-weight: 100;
font-size: 16px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
z-index: 2;
}
#media screen and (max-width: 576px) {
.react-autosuggest__suggestions-container--open, .react-autosuggest__input {
display: block;
width: 220px;
}
}
.react-autosuggest__suggestions-container--open li{
transform-origin: top center;
margin-bottom: 2px;
background: #c7ecee;
}
/* Here the background color is changed on hovering each li */
.react-autosuggest__suggestions-container--open li:hover {
background: #95afc0;
transition: 0.1s ease-in-out;
}
As seen above, when the mouse is hovered over each elements background color changes, but, I want to change when key (up or down) is pressed. Any suggestions or changes??
Just add theme prop. Something like this:
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={
this.onSuggestionsFetchRequested
}
onSuggestionsClearRequested={
this.onSuggestionsClearRequested
}
getSuggestionValue={this.getSuggestionValue}
renderSuggestion={this.renderSuggestion}
inputProps={inputProps}
focusInputOnSuggestionClick={true}
theme={{
container: {
display: "block",
width: "100%",
position: "absolute",
borderTop: "none",
borderBottom: "1px solid #aaa",
borderLeft: "1px solid #aaa",
borderRight: "1px solid #aaa",
backgroundColor: "#fff",
fontFamily: "Helvetica, sans-serif",
fontWeight: 300,
fontSize: "16px",
borderBottomLeftRadius: "4px",
borderBottomRightRadius: "4px",
zIndex: 2,
paddingLeft: 0,
paddingRight: 0,
},
input: {
marginBottom: 0,
display: "block",
width: "100%",
height: "34px",
padding: "6px 12px",
fontSize: "14px",
lineHeight: "1.4285",
color: "#555",
backgroundColor: "#fff",
backgroundImage: "none",
borderRadius: "4px",
border: "1px solid #ccc",
},
suggestionHighlighted: {
backgroundColor: "lightgrey", //magic line
cursor:'pointer'
},
}}
/>
I am trying to replicate data in the database for a specific user. It is almost 1000 rows that should be replicated. But my request gets failed with Empty response after 2 min. you can see in the picture. I am not able to identify the issue. Guide me if anyone has already solved this kind of issue.
My database is hosted on Google Cloud Storage and I am using MySQL.
This is my controller method:
public function createDataForManyToMany (Request $request)
{
$rows = TableA::where('id_analysis',
$request->analysis_id)->get();
$files_data = TableB::Where('id_analysis',
$request->analysis_id)->get();
foreach ($rows as $row)
{
$row->input_files()->saveMany($files_data);
}
return response()->json([
'status' => 'ok',
'analysis_id' => $request->analysis_id
]);
}
My Axios post request:
axios.post('/app/create-det-infiles-data', { '_token': this.csrf_token, 'analysis_id': res.data.analysis_id})
.then( res => {
if (res.data.status === 'ok') {
this.signupTried = false
this.emailSent = true
}
Vue Component:
<template>
<div class="fullwidth-container">
<div class="login-container">
<v-card class="login_form elevation-9">
<form class="login">
<input type="hidden" name="_token" :value="csrf_token"/>
<div class="header">
<h1>PIX2MAP SignUp</h1>
</div>
<v-text-field
color="dark"
prepend-icon="person"
:label="$t('name')"
required
:error-messages="nameErrors"
v-model="name">
</v-text-field>
<v-text-field
color="dark"
prepend-icon="email"
label="Email"
required
:error-messages="emailErrors"
v-model="email">
</v-text-field>
<v-text-field
color="dark"
prepend-icon="vpn_key"
:append_icon="show_pass ? 'visibility_off' : 'visibility'"
:type="show_pass ? 'text' : 'password'"
:error-messages="passwordErrors"
required
:label="$t('password')"
v-model="password"
#click:append="show_pass = !show_pass">
</v-text-field>
<v-text-field
class="pwd-confirm"
color="dark"
:append_icon="show_pass ? 'visibility_off' : 'visibility'"
:type="show_pass2 ? 'text' : 'password'"
:error-messages="repeatPasswordErrors"
required
:label="$t('repeat_password')"
v-model="password2"
#click:append="show_pass = !show_pass">
</v-text-field>
<v-layout row style="margin: 0">
<v-flex shrink style="margin-top: 0">
<v-checkbox
v-model="termsAccepted"
:label="`I accept the `"
:error-messages="acceptAgreementError"
>
</v-checkbox>
</v-flex>
<v-flex grow text-xs-left style="margin-top: 0">
contract
</v-flex>
</v-layout>
<v-btn class="btn-signup" color="accent" #click="doSignup"
:disabled="formFilled"
>Confirm <span class="float-right" :class="{'fas':signupTried, 'fa-spinner':signupTried, 'fa-spin':signupTried}"></span>
</v-btn>
<p class="privacy">{{ $t('form_privacy') }}</p>
</form>
</v-card>
<div class="back">
<v-btn flat #click="$emit('back')"><v-icon>arrow_back</v-icon>{{ $t('back_button') }}</v-btn>
</div>
</div>
<v-dialog
v-model="dialog"
max-width="650"
>
<v-card>
<v-card-title class="headline grey lighten-2">{{ contractTitile }}
<span style="margin-left: auto"><v-icon right #click="dialog = !dialog">fas fa-times</v-icon></span>
</v-card-title>
<v-card-text >
{{ contractBody }}
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
<v-snackbar
v-if="signupTried"
v-model="snackbar"
dark
:bottom="y === 'bottom'"
:timeout="timeout"
:left="x === 'left'"
:color="color"
:multi-line="mode === 'multi-line'"
:right="x === 'right'"
:top="y === 'top'"
:vertical="mode === 'vertical'"
>
{{ text }}
</v-snackbar>
<v-snackbar
v-if="emailSent"
v-model="emailSnackbar"
:bottom="y === 'bottom'"
:timeout="timeout"
:left="x === 'left'"
:multi-line="mode === 'multi-line'"
:right="x === 'right'"
:top="y === 'top'"
:color="color"
:vertical="mode === 'vertical'"
>
{{ emailSentMessage }}
</v-snackbar>
</div>
</template>
<script>
import { required, email } from 'vuelidate/lib/validators'
import {TITLE, BODY_TEXT} from '../contract'
import axios from 'axios'
export default {
props: {
csrf_token: String,
name: String,
email: String,
},
data: () => ({
contractTitile: TITLE,
contractBody: BODY_TEXT,
show_pass: false,
show_pass2: false,
name: '',
email: '',
password: '',
password2: '',
signupTried: false,
emailExist: false,
dialog: false,
termsAccepted: false,
snackbar: true,
y: 'bottom',
x: null,
mode: '',
timeout: 10000,
color: '#fff',
text: 'This process will take some time, please! be patience.',
emailSent: false,
emailSnackbar: true,
emailSentMessage: 'We have sent you instructions, please verify your account by visiting your email.'
}),
validations: {
name: {
required
},
email: {
required,
email
},
password: {
required
},
password2: {
required
},
termsAccepted: {
required
}
},
methods: {
async doSignup () {
this.signupTried = true
if (this.$v.name.required && this.$v.email.required && this.$v.email.email && this.$v.password.required && this.termsAccepted ) {
axios.post('/app/register', { '_token': this.csrf_token, 'name': this.name,'email': this.email, 'password': this.password })
.then(res => {
if (res.data.status === 'ok') {
axios.post('/app/create-in-files-data', { '_token': this.csrf_token, 'analysisIds': res.data.analysis_ids})
.then(resp => {
if (resp.data.status === 'ok') {
axios.post('/app/create-mo-files-data', { '_token': this.csrf_token, 'analysisIds': resp.data.analysis_ids})
.then( res => {
if (res.data.status === 'ok') {
// window.location = '/'
// this.signupTried = false
// this.emailSent = true
axios.post('/app/create-det-infiles-data', { '_token': this.csrf_token, 'analysis_id': res.data.analysis_id})
.then( res => {
if (res.data.status === 'ok') {
this.signupTried = false
this.emailSent = true
// await axios.post('/app/create-det-mofiles-data', { '_token': this.csrf_token, 'analysis_id': res.data.analysis_id, demo: true})
// .then(async res => {
// if (res.data.status === 'ok') {
// this.showSpinner = false
// window.location = '/'
// } else {
// console.log('Files not created')
// this.showSpinner = false
// this.$emit('forgotPw', {email: this.email});
// }
// })
// .catch(e => {
// console.log('2nd error', e)
// })
} else {
console.log('Files not created')
this.showSpinner = false
this.$emit('forgotPw', {email: this.email});
}
})
.catch(e => {
console.log('2nd error', e)
})
} else {
console.log('Signup Failed')
this.signupTried = false
this.$emit('forgotPw', {email: this.email});
}
})
.catch(e => {
console.log('2nd error', e)
})
} else {
console.log('Files not created')
this.showSpinner = false
this.$emit('forgotPw', {email: this.email});
}
})
.catch(e => {
console.log('Error: ', e)
})
} else {
this.showSpinner = false
this.$emit('forgotPw', {email: this.email});
}
})
}
},
changeState () {
this.dialog = !this.dialog
}
},
computed: {
nameErrors () {
if (this.signupTried && this.name.length == 0 && !this.$v.name.required) return [this.$t('name_required')]
},
emailErrors () {
const errors = []
if (this.signupTried && !this.$v.email.required) errors.push(this.$t('email_required'))
if (!this.$v.email.email) errors.push(this.$t('not_valid_email'))
if (this.emailExist) errors.push(this.$t('existing_email'))
return errors
},
passwordErrors () {
if (this.signupTried && !this.$v.password.required) return [this.$t('password_required')]
},
repeatPasswordErrors () {
if (this.signupTried && !this.$v.password2.required) return [this.$t('password_required')]
if (this.password2 != this.password) return [this.$t('passwords_not_equal')]
},
acceptAgreementError () {
if (this.signupTried && !this.$v.termsAccepted.required) return [this.$t('agreement_required')]
},
formFilled () {
if (!this.$v.name.required || !this.$v.email.required || !this.$v.password.required || !this.$v.password2.required || !this.termsAccepted || (this.password != this.password2))
{
return true
} else {
return false
}
}
}
}
</script>
<style scoped lang="stylus">
#import '../../stylus/theme.styl'
.fullwidth-container {
width: 100%;
height: 100%;
background: $bg-login;
position: absolute;
top: 0px;
left: 0px;
z-index: 2;
.login-container {
position: relative;
width: 500px;
top: 25px;
margin: auto;
.login_form {
padding: 16pt;
text-align: center;
height: 800px;
* {
margin-top: 24pt;
}
.header {
margin: 24pt;
}
.i-am {
display: flex;
flex-direction: row;
align-items: center;
* {
margin-top: 0pt;
}
span {
width: 8%;
}
.i-am-text {
margin-right: 20px;
}
.i-am-select {
margin-left: 5%;
}
}
.btn-signup {
margin-left: auto;
margin-right: auto;
width: 80%;
}
.privacy {
margin-top: 8pt;
font-style: italic;
}
.pwd-confirm {
margin-left: 7%;
}
.checkboxAccept {
display: inline;
}
.float-right {
margin-top: -3px;
margin-left: 5px;
color: #fff;
font-size: 18px;
}
}
}
}
</style>
This issue might be caused due to MySQL instance is reaching the time out limit for your query.
In Cloud SQL you can try to modify the flag “wait_timeout” and set a bigger value, for example 50000.
Check this link as a reference to set a flag in Cloud SQL instance.
I tried zebra striping my table in a React application here. However, it is not being applied. Here are the relevant styles:
tr:nth-child(even) {
background-color: rgba(0,100,1,0.5)
}
tr:nth-child(odd) {
background-color: rgba(0,100,1,0.3)
}
And the full demo:
'use strict';
var /*var Leaderboard = React.createClass({
getInitialState: function(){
/*var recentCampers= [];
var allTimeCampers= [];*/
//return {toggle30: 'true'};
/*return {recentCampers: [],
allTimeCampers: [],
toggle30: 'true'};
this.recentCampers= this.recentCampers.bind(this);
this.allTimeCampers.bind(this);
this.toggle30= this.toggle30.bind(this); */
/* },
componentDidMount: function(){return axios.all([this.getTopRecentCampers(),this.getTopAlltimeCampers()]).then(function(arr){return {
recentCampers: arr[0].data,
allTimeCampers: arr[1].data};
console.log(this.state.recentCampers[0].username); })},
/*
getTopRecentCampers: function(){return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/recent');},
getTopAlltimeCampers: function(){return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/alltime');},
toggleViewOne: function(){this.setState({toggle30: 'true'});},
toggleViewTwo: function(){this.setState({toggle30: 'false'});},
/* render: function(){return (<div>
<h6>Sort by:</h6> <button onClick={this.toggleViewOne} className="btn">Points in past 30 days <span className="fa fa-sort-desc"> </span></button> <button onClick={this.toggleViewTwo} className="btn"> All time points <span className="fa fa-sort-desc"> </span> </button> <h1> freeCodeCamp <span className="fa fa-free-code-camp"> </span> </h1> <hr></hr> <div className="table-responsive"> <table className="table"> <thead> <tr> <th> <td> # </td> <td> Camper name </td> <td> Points in last month </td> <td> All time points </td> </th> </tr> </thead> <tbody>
//</tbody> </table> </div> </div>);} */
/* });
var Tbody = React.createClass({
render: function(){return (<tbody> {} </tbody>);}
});*/
/*</tr> <tr> <td> gtew</td> </tr> <tr> <td> gffs</td> </tr>this.recentCampers= this.recentCampers.bind(this);
this.allTimeCampers.bind(this) */
/*
ReactDOM.render(<Leaderboard />,document.getElementById('freeCodeCamp'));
---------------------------------------------------------------------------- */Leaderboard = React.createClass({
displayName: 'Leaderboard',
getInitialState: function getInitialState() {
return {
recentCampers: [],
allTimeCampers: [],
toggle: 'recentCampers'
};
},
componentWillMount: function componentWillMount() {
return this.getRequest();
},
getRequest: function getRequest() {
return axios.all([this.getTopRecentCampers(), this.getTopAlltimeCampers()]).then(function (arr) {
this.setState({
recentCampers: arr[0].data,
allTimeCampers: arr[1].data
});
/*var recent= [];
recent= this.state.recentCampers;
for (var i=0;i>=100;i++){return recent[i];};
//console.log(this.state.recentCampers[0].username);*/
}.bind(this));
},
getTopRecentCampers: function getTopRecentCampers() {
return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/recent');
},
getTopAlltimeCampers: function getTopAlltimeCampers() {
return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/alltime');
},
toggleViewOne: function toggleViewOne() {
this.setState({
toggle: 'recentCampers'
});
},
toggleViewTwo: function toggleViewTwo() {
this.setState({
toggle: 'allTimeCampers'
});
},
render: function render() {
return React.createElement(
'div',
null,
' ',
' ',
React.createElement(
'h6',
null,
'Sort by:'
),
' ',
React.createElement(
'button',
{ onClick: this.toggleViewOne, className: 'btn' },
'Points in past 30 days ',
React.createElement(
'span',
{ className: 'fa fa-sort-desc' },
' '
)
),
' ',
React.createElement(
'button',
{ onClick: this.toggleViewTwo, className: 'btn' },
' All time points ',
React.createElement(
'span',
{ className: 'fa fa-sort-desc' },
' '
),
' '
),
' ',
React.createElement(
'h1',
null,
' freeCodeCamp ',
React.createElement(
'span',
{ className: 'fa fa-free-code-camp' },
' '
),
' '
),
' ',
React.createElement('hr', null),
' ',
React.createElement(
'div',
{ className: 'table-responsive' },
' ',
React.createElement(
'table',
{ className: 'table' },
' ',
React.createElement(
'thead',
null,
' ',
React.createElement(
'tr',
null,
' ',
React.createElement(
'th',
null,
' ',
React.createElement(
'td',
{ style: { width: '80px' }, className: 'text-center' },
' # '
),
' ',
React.createElement(
'td',
{ style: { width: '600px' } },
' Camper name '
),
' ',
React.createElement(
'td',
{ style: { width: '400px' }, className: 'text-center' },
' Points in last month '
),
' ',
React.createElement(
'td',
{ style: { width: '400px' }, className: 'text-center' },
' All time points '
),
' '
),
' '
),
' '
),
' ',
React.createElement(
'tbody',
null,
' ',
React.createElement(Map, { data: this.state[this.state.toggle] })
),
' '
),
' '
),
' '
);
}
});
//{<Tbody data={this.state}
/*
-------------------------------------------------------------------------- */
var Map = React.createClass({
displayName: 'Map',
render: function render() {
var rows = this.props.data.map(function (row, index) {
return React.createElement(Tbody, { rank: index + 1, data: row });
});
return React.createElement(
'tbody',
{ id: 'stripe' },
rows
);
}
});
/*
-------------------------------------------------------------------------- */
var Tbody = React.createClass({
displayName: 'Tbody',
render: function render() {
return React.createElement(
'div',
null,
' ',
/*<h1>{this.props.data.username}</h1>*/React.createElement(
'tr',
null,
React.createElement(
'td',
{ style: { width: '80px' }, className: 'text-center' },
this.props.rank + '.'
),
React.createElement(
'td',
{ style: { width: '600px' } },
React.createElement(
'a',
{ target: '_blank', href: 'http://freecodecamp.com/' + this.props.data.username },
React.createElement('img', { src: this.props.data.img }),
' ',
React.createElement(
'span',
null,
this.props.data.username
)
)
),
React.createElement(
'td',
{ id: 'recent', className: 'text-center' },
this.props.data.recent
),
React.createElement(
'td',
{ id: 'all', className: 'text-center' },
this.props.data.alltime
)
),
' '
);
//console.log(JSON.stringify(this.props));*/
}
});
/*
-------------------------------------------------------------------------- */
ReactDOM.render(React.createElement(Leaderboard, null), document.getElementById('freeCodeCamp'));
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-image: linear-gradient(161deg, #006401 0%, #FCFFEE 100%);
background-attachment: fixed;
color: #502d17;
margin-left: 20px;
margin-right: 20px;
}
button {
margin: 5px;
background-image: -webkit-linear-gradient(#006401, #FCFFEE);
background-attachment: fixed;
color: #FCFFEE;
box-shadow: inset -1px -3px 10px 1px #515151;
margin-bottom: 20px;
}
button:active {
transform: translate(0, 3px);
box-shadow: none;
text-decoration: none;
outline: none;
}
button:hover, button:active, button:visited {
text-decoration: none;
outline: none;
}
h6 {
margin-left: 10px;
margin-top: 15px;
margin-bottom: 5px;
}
h1 {
color: rgba(245, 245, 245, 0.5);
margin-left: 5px;
}
.fa-free-code-camp {
font-size: 1em;
color: rgba(245, 245, 245, 0.7);
}
table, td {
border: 1px solid grey;
table-layout: fixed;
}
tr:nth-child(even) {
background-color: rgba(0, 100, 1, 0.5);
}
tr:nth-child(odd) {
background-color: rgba(0, 100, 1, 0.3);
}
img {
border-radius: 100%;
height: 60px;
}
a {
text-decoration: none;
color: #502d17;
}
#all {
max-width: 280px;
min-width: 280px;
}
#recent {
max-width: 280px;
min-width: 280px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.8.1/axios.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<div id="freeCodeCamp"></div>
As your HTML markup is pulled in within your codepen I'm not sure how useful this is to future users but in the context of your codepen your selectors are incorrect.
Your tbody does not contain tr siblings but each tr is wrapped into a div, hence you need to target those instead.
tbody>div:nth-child(even)
background-color: rgba(0,100,1,0.5)
tbody>div:nth-child(odd)
background-color: rgba(0,100,1,0.3)
See updated CodePen
'use strict';
var /*var Leaderboard = React.createClass({
getInitialState: function(){
/*var recentCampers= [];
var allTimeCampers= [];*/
//return {toggle30: 'true'};
/*return {recentCampers: [],
allTimeCampers: [],
toggle30: 'true'};
this.recentCampers= this.recentCampers.bind(this);
this.allTimeCampers.bind(this);
this.toggle30= this.toggle30.bind(this); */
/* },
componentDidMount: function(){return axios.all([this.getTopRecentCampers(),this.getTopAlltimeCampers()]).then(function(arr){return {
recentCampers: arr[0].data,
allTimeCampers: arr[1].data};
console.log(this.state.recentCampers[0].username); })},
/*
getTopRecentCampers: function(){return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/recent');},
getTopAlltimeCampers: function(){return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/alltime');},
toggleViewOne: function(){this.setState({toggle30: 'true'});},
toggleViewTwo: function(){this.setState({toggle30: 'false'});},
/* render: function(){return (<div>
<h6>Sort by:</h6> <button onClick={this.toggleViewOne} className="btn">Points in past 30 days <span className="fa fa-sort-desc"> </span></button> <button onClick={this.toggleViewTwo} className="btn"> All time points <span className="fa fa-sort-desc"> </span> </button> <h1> freeCodeCamp <span className="fa fa-free-code-camp"> </span> </h1> <hr></hr> <div className="table-responsive"> <table className="table"> <thead> <tr> <th> <td> # </td> <td> Camper name </td> <td> Points in last month </td> <td> All time points </td> </th> </tr> </thead> <tbody>
//</tbody> </table> </div> </div>);} */
/* });
var Tbody = React.createClass({
render: function(){return (<tbody> {} </tbody>);}
});*/
/*</tr> <tr> <td> gtew</td> </tr> <tr> <td> gffs</td> </tr>this.recentCampers= this.recentCampers.bind(this);
this.allTimeCampers.bind(this) */
/*
ReactDOM.render(<Leaderboard />,document.getElementById('freeCodeCamp'));
---------------------------------------------------------------------------- */Leaderboard = React.createClass({
displayName: 'Leaderboard',
getInitialState: function getInitialState() {
return {
recentCampers: [],
allTimeCampers: [],
toggle: 'recentCampers'
};
},
componentWillMount: function componentWillMount() {
return this.getRequest();
},
getRequest: function getRequest() {
return axios.all([this.getTopRecentCampers(), this.getTopAlltimeCampers()]).then(function (arr) {
this.setState({
recentCampers: arr[0].data,
allTimeCampers: arr[1].data
});
/*var recent= [];
recent= this.state.recentCampers;
for (var i=0;i>=100;i++){return recent[i];};
//console.log(this.state.recentCampers[0].username);*/
}.bind(this));
},
getTopRecentCampers: function getTopRecentCampers() {
return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/recent');
},
getTopAlltimeCampers: function getTopAlltimeCampers() {
return axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/alltime');
},
toggleViewOne: function toggleViewOne() {
this.setState({
toggle: 'recentCampers'
});
},
toggleViewTwo: function toggleViewTwo() {
this.setState({
toggle: 'allTimeCampers'
});
},
render: function render() {
return React.createElement(
'div',
null,
' ',
' ',
React.createElement(
'h6',
null,
'Sort by:'
),
' ',
React.createElement(
'button',
{ onClick: this.toggleViewOne, className: 'btn' },
'Points in past 30 days ',
React.createElement(
'span',
{ className: 'fa fa-sort-desc' },
' '
)
),
' ',
React.createElement(
'button',
{ onClick: this.toggleViewTwo, className: 'btn' },
' All time points ',
React.createElement(
'span',
{ className: 'fa fa-sort-desc' },
' '
),
' '
),
' ',
React.createElement(
'h1',
null,
' freeCodeCamp ',
React.createElement(
'span',
{ className: 'fa fa-free-code-camp' },
' '
),
' '
),
' ',
React.createElement('hr', null),
' ',
React.createElement(
'div',
{ className: 'table-responsive' },
' ',
React.createElement(
'table',
{ className: 'table' },
' ',
React.createElement(
'thead',
null,
' ',
React.createElement(
'tr',
null,
' ',
React.createElement(
'th',
null,
' ',
React.createElement(
'td',
{ style: { width: '80px' }, className: 'text-center' },
' # '
),
' ',
React.createElement(
'td',
{ style: { width: '600px' } },
' Camper name '
),
' ',
React.createElement(
'td',
{ style: { width: '400px' }, className: 'text-center' },
' Points in last month '
),
' ',
React.createElement(
'td',
{ style: { width: '400px' }, className: 'text-center' },
' All time points '
),
' '
),
' '
),
' '
),
' ',
React.createElement(
'tbody',
null,
' ',
React.createElement(Map, { data: this.state[this.state.toggle] })
),
' '
),
' '
),
' '
);
}
});
//{<Tbody data={this.state}
/*
-------------------------------------------------------------------------- */
var Map = React.createClass({
displayName: 'Map',
render: function render() {
var rows = this.props.data.map(function (row, index) {
return React.createElement(Tbody, { rank: index + 1, data: row });
});
return React.createElement(
'tbody',
{ id: 'stripe' },
rows
);
}
});
/*
-------------------------------------------------------------------------- */
var Tbody = React.createClass({
displayName: 'Tbody',
render: function render() {
return React.createElement(
'div',
null,
' ',
/*<h1>{this.props.data.username}</h1>*/React.createElement(
'tr',
null,
React.createElement(
'td',
{ style: { width: '80px' }, className: 'text-center' },
this.props.rank + '.'
),
React.createElement(
'td',
{ style: { width: '600px' } },
React.createElement(
'a',
{ target: '_blank', href: 'http://freecodecamp.com/' + this.props.data.username },
React.createElement('img', { src: this.props.data.img }),
' ',
React.createElement(
'span',
null,
this.props.data.username
)
)
),
React.createElement(
'td',
{ id: 'recent', className: 'text-center' },
this.props.data.recent
),
React.createElement(
'td',
{ id: 'all', className: 'text-center' },
this.props.data.alltime
)
),
' '
);
//console.log(JSON.stringify(this.props));*/
}
});
/*
-------------------------------------------------------------------------- */
ReactDOM.render(React.createElement(Leaderboard, null), document.getElementById('freeCodeCamp'));
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-image: linear-gradient(161deg, #006401 0%, #FCFFEE 100%);
background-attachment: fixed;
color: #502d17;
margin-left: 20px;
margin-right: 20px;
}
button {
margin: 5px;
background-image: -webkit-linear-gradient(#006401, #FCFFEE);
background-attachment: fixed;
color: #FCFFEE;
box-shadow: inset -1px -3px 10px 1px #515151;
margin-bottom: 20px;
}
button:active {
transform: translate(0, 3px);
box-shadow: none;
text-decoration: none;
outline: none;
}
button:hover, button:active, button:visited {
text-decoration: none;
outline: none;
}
h6 {
margin-left: 10px;
margin-top: 15px;
margin-bottom: 5px;
}
h1 {
color: rgba(245, 245, 245, 0.5);
margin-left: 5px;
}
.fa-free-code-camp {
font-size: 1em;
color: rgba(245, 245, 245, 0.7);
}
table, td {
border: 1px solid grey;
table-layout: fixed;
}
tbody>div:nth-child(even){
background-color: rgba(0, 100, 1, 0.5);
}
tbody>div:nth-child(odd) {
background-color: rgba(0, 100, 1, 0.3);
}
img {
border-radius: 100%;
height: 60px;
}
a {
text-decoration: none;
color: #502d17;
}
#all {
max-width: 280px;
min-width: 280px;
}
#recent {
max-width: 280px;
min-width: 280px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.8.1/axios.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<div id="freeCodeCamp"></div>
Just to add, while the above works, I think your JavaScript generates invalid HTML to begin with as I think a div is not allowed as a child inside a tbody wrapping tr elements. If this is your own code, you can update it to use multiple tbody siblings inside the table element, each containing tr elements, instead of nested tbody elements with a div wrapping tr elements. If this is not your own code but the code you got from freeCodeCamp, I would consider switching code camp.
Your table markup is invalid. Your rows shouldn't be wrapped in divs.
The reason nth-child isn't working in this case is because it can only iterate through sibling elements(https://www.w3.org/TR/css3-selectors/#nth-child-pseudo).
Remove your wrapping divs in Leaderboard render function and it should work just fine.