I'm using react-dates for a simple birthday picker. I'm using the renderMonthElement prop to render 2 selects on top of the datepicker for months and years:
Whenever I select a month, the calendar updates correctly however the value shown in the react-select component doesn't update.
My Select looks like this:
<Select
placeholder="Monat"
styles={{ indicatorSeparator: () => {}, ...customStyles }}
options={months}
filterOption={createFilter(filterConfig)}
name="months"
value={bdaymonth}
className="monthSelect"
onChange={optionSelected => {
onMonthSelect(month, optionSelected.label)
setBdayMonth(optionSelected.label)
}}
/>
as soon as I take it out of the renderMonthElement, it works perfectly fine by either using bdaymonth from state or just directly with months.label
I thought it might have something to do with the SingleDatePicker being rendered in a Portal but even if I render it inline, the issue persists.
Here is the complete code of my renderMonthElement (pretty much stolen from https://stackoverflow.com/a/57666932/6118046) :
const renderMonthElement = ({ month, onMonthSelect, onYearSelect }) => {
let i
let years = []
for (i = moment().year() - 16; i >= moment().year() - 100; i--) {
years.push(
<option value={i} key={`year-${i}`}>
{i}
</option>
)
}
const months = moment.months().map((label, value) => {
return { value: value, label: label }
})
return (
<BdaySelect>
<div>
<Select
placeholder="Monat"
styles={{ indicatorSeparator: () => {}, ...customStyles }}
options={months}
filterOption={createFilter(filterConfig)}
name="months"
value={bdaymonth}
className="landSelect"
onChange={optionSelected => {
onMonthSelect(month, optionSelected.label)
setBdayMonth(optionSelected.label)
}}
/>
</div>
<div>
<select
value={month.year()}
onChange={e => onYearSelect(month, e.target.value)}
>
{years}
</select>
</div>
</BdaySelect>
)
}
Got it working by changing the value of the Select to
value={months.filter(function(month) {
return month.label === bdaymonth;
})}
Related
I have a vue2 app which I need to pre-select a dropdown but for the life of me, I can't figure it out.
I have looked and tried everything in:
How to preselect current value in a select created with v-repeat in Vue.js
Normal HTML
<select ref="courierList" id="courierList" class="form-control" v-model="shippingDetails.selectedCourier" #change="selectedCourierDd">
<option :value="courier.name" v-for="(courier, i) in couriers" :key="i">
{{ courier.name }}
</option>
</select>
data() {
return {
couriers: [],
.... OTHER DATA ITEMS
}
},
beforeMount() {
this.fetchCouriers();
},
fetchCouriers() {
axios.get('/couriers')
.then((response) => {
this.couriers = response.data.couriers;
.... OTHER CODE
Tried code > 1
Adding the below to the option
selected="{{ courier.name === preselectedCourierName ? 'true' : 'false' }}">
also tied without the true/false
Tried code > 2
Adding the below to the option
v-bind:selected="courier === preselectedCourierName"
and the below
data() {
return {
.... OTHER DATA ITEMS
preselectedCourier: [],
preselectedCourierName: ''
}
fetchCouriers() {
axios.get('/couriers')
.then((response) => {
this.couriers = response.data.couriers;
.... OTHER CODE
console.log('couriers', this.couriers[0])
this.preselectedCourier = this.couriers[0];
this.preselectedCourierName = this.preselectedCourier.name;
console.log('preselectedCourier', this.preselectedCourier)
console.log('preselectedCourierName', this.preselectedCourierName)
gives
Tried code > 3
<option :value="courier.name" v-for="(courier, i) in couriers" :key="i" :selected="courier.name === 'APC'">
no errors but dropdown still not pre-selected
The fix is in the mounted hook set the v-model of the select
<select v-model="shippingDetails.selectedCourier">
mounted() {
this.shippingDetails.selectedCourier = 'APC';
}
Give me exactly what i wanted
I have form input using Vue on my project , but in my input 1 field select box cannot record on my sending input ( always null) , another filed like tipe text , number its work , but only this select box cannot record on input
its my input
// this field select cant record ( always give null ) ,
<div class="field">
<div class="select">
<select name="anak_id">
<option v-for="(invent, id) in kod_rek" :key="id" :value="id">
{{ invent }}
</option>
</select>
</div>
</div>
// and this field work normally
<div class="field">
<label for="kode_rekening">kode rekening</label>
<input
type="text"
id="kode_rekening"
class="input"
:value="userData.kode_rekening"
#input="userData.kode_rekening = $event.target.value"
>
<div v-if="errors && errors.kode_rekening" class="text-danger">{{ errors.kode_rekening[0] }}</div>
</div>
and on this export default
export default {
data(){
return{
fields: {},
errors: {},
userData:{
anak_id:'',
kode_rekening:'',
uraian:'',
anggaran:'',
},
kod_rek:{},
isSubmited: true,
}
},
created(){
axios.get('/users/get_data_turunan_anak').then((res)=>{
this.kod_rek = res.data
// console.log(res.data)
}).catch((err) => {
console.log(err)
});
}
methods:{
submited(){
this.isSubmited = true;
},
submit() {
this.errors = {};
axios.post('/users/input_turunan_anak', this.userData).then(response => {
window.location = response.data.redirect;
}).catch(error => {
if (error.response.status === 422) {
this.errors = error.response.data.errors || {};
}
});
},
},
only my select box cant storing on this input , whats this problem and my network having error
message: "SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'anak_id' cannot be null (SQL: insert into turunan_anak (anak_id, kode_rekening, uraian, anggaran, updated_at, created_at)
Try using #change event for the select box.You can also use v-model for this use case. v-model directive will help you to create two-way data bindings.
I am trying to create a custom component for edit/create in react admin. The problem I am facing is that the new updated value is not being taken, what my component is doing is adding and removing values from ChipArray with the values coming from a dropdown select
render() {
return (
<React.Fragment>
<Paper>
{this.state.scopes.map((item, key) => {
return (
<Chip
key={key}
label={item.description}
onDelete={(e) => this.handleDelete(e, item)}
/>
)
})}
</Paper>
<div>
<button onClick={(e) => this.displayChoices(e)}>
{this.state.show ? <span>Hide Scopes Select List</span> : <span>Show Scopes Select List</span>}
</button>
<div/>
{this.state.show ? <Field name="scope" component="Select" placeholder="Spaces"
onChange={(e) => this.handleAdd(e)}>
{this.state.data.map((option, index) =>
<option key={index} value={JSON.stringify(option)}>
{option.description}
</option>
)}
</Field> : ''}
</div>
</React.Fragment>
)
}
}
I manged to remove and add to the ChipArray but when I save the channges were never taken, here is the delete and add functions :
handleAdd = (e) => {
e.preventDefault();
const value = JSON.parse(e.target.value);
let selectedScopes = this.state.scopes;
if (selectedScopes.filter(s => (s.id === value.id)).length === 0) {
selectedScopes.push(value);
this.setState({scopes: [...selectedScopes]});
}
};
handleDelete = (e, value) => {
e.preventDefault();
const selectedScopes = this.state.scopes;
this.setState((prevState, props) => {
return {scopes: prevState.scopes.filter(scope => scope !== value)};
})
};
I know I am supposed to use <Field/> from "react-final-form" but I am not sure how or where.
Really sorry if this question was asked before but I looked online and wasn't so lucky and I am stuck on this.
Thanks
I have the following code to display data from json file, i have more that 500 records i want to display 10 records per page. Here is my project in [code pen][1] . I tried react-pagination library but that doesn't work. what is the best way to do this? Open to use any library recommended -- i tried almost all of them.
here is how my code looks like
I'm sure there are a hundred different ways of doing it, but just to teach the idea of the mechanics, here is a very manual version:
{this.state.filteredData
.slice(this.state.activePage * 10, (this.state.activePage + 1) * 10)
.map(results => ( ...
))}
.....
{/*Pagination goes here */}
<button onClick={() => {this.setState({activePage: this.state.activePage - 1})}} >
prev</button>
<button onClick={() => {this.setState({activePage: this.state.activePage + 1})}} >
next</button>
That is, you take only a slice of the data before mapping it into DOM elements, and the buttons for advancing or going back just select the slice by setting the activePage state variable you already had.
You could have something along the lines of an index and offset and then create chunks of your array.
Give this a try:
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import cardData from "./response.json";
import "./style.css";
class App extends Component {
constructor() {
super();
const offset = 5;
console.log(cardData);
this.state = {
name: "React",
index: 0,
offset,
chunks: this.chunkArray(cardData.data.Table, offset)
};
}
chunkArray(inputArray, chunkSize){
console.log("inputArray:: ", inputArray);
const results = [];
while (inputArray.length) {
results.push(inputArray.splice(0, chunkSize));
}
console.log("results:: ", results);
return results;
}
handleClick(index) {
this.setState({
index
})
}
render() {
console.log(this.state.chunks);
return (
<div>
{this.state.chunks && this.state.chunks[this.state.index].map(results => (
<div className="col-sm-3">
<h3>
{results.first_name} {results.last_name}
</h3>
<h3>{results.manager}</h3>
<div className="row">
<div className="col-md-3 col-sm-6"> {results.Department}</div>
</div>
<a
to={{ pathname: `/cards/${results.id}`, state: results }}
className={`card-wrapper restore-${results.id}`}
href={`/cards/${results.id}`}
>
View Detail
</a>
</div>
))}
<br />
{ this.state.chunks && this.state.chunks.map((item, index) => <button onClick={() => this.handleClick(index)}>{index + 1}</button>) }
</div>
);
}
}
render(<App />, document.getElementById("root"));
Here's a Working Code Sample Demo for your ref.
If you're using hooks, this will work otherwise it can be easily adapted. Basically, just store the index of where you are and then get the data you need based on that index:
const [index, setIndex] = React.useState(0);
const PAGE_SIZE = 10;
const tableData = cardData.data.Table.slice(index, index + PAGE_SIZE);
const table = {tableData.map(results => (
<div className="col-sm-3">
<h3>
{results.first_name} {results.last_name}
</h3>
<h3 >{results.manager}</h3>
<div className="row">
<div className="col-md-3 col-sm-6"> {results.Department}</div>
</div>
<Link
to={{ pathname: `/cards/${results.id}`, state: results }}
className={`card-wrapper restore-${results.id}`}
>
View Detail
</Link>
</div>
))}
const navigation = (
<div>
<div disabled={index <= 0 ? true : false} onClick={() => setIndex(index - PAGE_SIZE)}>Prev</div>
<div disabled={index <= cardData.data.Table.length ? true : false} onClick={() => setIndex(index + PAGE_SIZE)}>Next</div>
</div>
);
select with options are generated dynamically.
When button 'GO' were click select options generates again with different data. But the issue is when user select option 1 and click 'go' automatically option 1 is selected from next select, how to clear that?
my code:
<select v-model="key" #change="onChange($event)">
<option v-for="(option, index) in passSelect" :value="index" v-if="option!==null" :data-foo="option" #click="onChange($event)" #click="onClick($value)">
{{ option }}
</option>
</select>
<button #click="onChildClick" class="button">Go -></button>
methods:
onChildClick() {
this.counter++;
this.loadAgain();
},
getSelect(){
this.passSelect = this.checkExist();
},
onChange(event) {
this.selectedIndex = event.target.value;
this.selectedValue = event.target.options[event.target.value].dataset.foo;
},
loadAgain(){
this.getSelect();
},
Selection is determined by the v-model, which is using the property key. As you're using the index for the value this will cause the option with the same index as the previous list to be selected.
You need to clear the value of key to reset the <select>:
new Vue({
el: '#app',
data () {
return {
counter: 0,
key: null,
passSelect: [],
selectedIndex: null,
selectedValue: null
}
},
created () {
this.getSelect();
},
methods: {
onChildClick () {
this.counter++;
this.loadAgain();
},
getSelect () {
this.key = null;
this.selectedIndex = null;
this.selectedValue = null;
this.passSelect = getOptionsList();
},
onChange (event) {
const value = event.target.value;
if (value) {
this.selectedIndex = event.target.value;
this.selectedValue = event.target.options[event.target.value].dataset.foo;
}
},
loadAgain () {
this.getSelect();
}
}
})
function getOptionsList () {
return ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'].filter(c => {
return Math.random() > 0.4;
});
}
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<select v-model="key" #change="onChange($event)">
<option v-for="(option, index) in passSelect" :value="index" v-if="option !== null" :data-foo="option">
{{ option }}
</option>
</select>
<button #click="onChildClick" class="button">Go -></button>
<p>counter: {{ JSON.stringify(counter) }}</p>
<p>key: {{ JSON.stringify(key) }}</p>
<p>selectedIndex: {{ JSON.stringify(selectedIndex) }}</p>
<p>selectedValue: {{ JSON.stringify(selectedValue) }}</p>
</div>
I've also cleared selectedIndex and selectedValue to try to keep the data consistent.
Some other notes:
I've got rid of the 2 click listeners on the <option>. Not really sure what they were for but you shouldn't have had 2 listeners for the same event on the same element.
key and selectedIndex are almost the same thing. The only difference is that selectedIndex ends up being a string whereas key is a number. Not clear why you aren't just using selectedIndex for your v-model directly.
I don't know what checkExist does but passSelect feels like it should be a computed property from the code provided.
There shouldn't be any need to use data-foo to pass the option to the listener. You can get the relevant option directly from the data once you have the index. All of which assumes you actually need the index, otherwise you could just bind the value directly to the string option.