Currently working on creating a react component for a form. I am applying a datepicker via a regular javascript file to my inputs which are being rendered in react (jsx).
I am trying to pull the state from the inputs when a date is selected from the datepicker. Unfortunately react is not picking up the value. I know it is probably something to do with calling the datepicker from a regular javascript file onto the rendered inputs. Thing is, when I am calling a regular .val on the input once I have selected a date, it gives me the value.
Also should mention, I am using bootstrap-datepicker
Any suggestions or recommendations would be greatly appreciated :)
form.js.jsx
var StepOne = React.createClass({
getInitialState: function() {
return {start: '', end: ''};
},
startDateChange: function(e) {
this.setState({start: e.target.value});
},
endDateChange: function(e) {
this.setState({end: e.target.value});
},
render: function() {
return (
<div className="stepOne">
<ul>
<li>
<label>Starts</label>
<input id="event-start" type="text" value={this.state.start} onChange={this.startDateChange} />
<label>Ends</label>
<input id="event-end" type="text" value={this.state.end} onChange={this.endDateChange} />
</li>
</ul>
</div>
);
},
}); // end of component
stepone_datepicker.js
$(function() {
var date = new Date();
date.setDate(date.getDate()-1);
$('#event-start, #event-end').each(function() {
$(this).datepicker({
autoclose: true,
minDate: new Date(),
startDate: date
});
});
});
The code in the stepone_datepicker.js file is probably executing before your React component has rendered into the DOM.
Using id to reference a DOM node inside a React component is very rarely a good idea and generally ends up as confusing spaghetti code.
React gives us a way to get hold of the DOM nodes with it's refs mechanism.
First, move the date picker code into a new method in your component.
makeDatePicker: function(element) {
var date = new Date();
date.setDate(date.getDate() - 1);
$(element).datepicker({
autoclose: true,
minDate: new Date(),
startDate: date
});
}
Now we can add the ref attribute to each input and use this new method as the callback.
<label>Starts</label>
<input ref={this.makeDatePicker} type="text" value={this.state.start} onChange={this.startDateChange} />
<label>Ends</label>
<input ref={this.makeDatePicker} type="text" value={this.state.end} onChange={this.endDateChange} />
When the element is ready, React will call makeDatePicker and pass the DOM node as the first argument.
After that, you can intercept the DOM node and apply the jQuery plugin.
This way you could even render multiple instances of the StepOne component and not have to worry about collisions between id attributes.
It's not the correct way to do it maybe better to use react-datepicker
But you can do this to trigger onChange event manually
$(function() {
var date = new Date();
date.setDate(date.getDate()-1);
$('#event-start, #event-end').each(function() {
$(this).datepicker({
autoclose: true,
minDate: new Date(),
startDate: date,
onSelect: function( selectedDate ) {
var event = new Event('input', { bubbles: true });
this.dispatchEvent(event);
}
});
});
});
and maybe better to use react-dom to get the DOM node anyway the code that i post with the minimum changes
Related
I would like to add and render event by selection of dates range. select() is correctly fired, but there is error calendar.fullCalendar is not a function on the last line. I googled a lot but did not find any working solution.
I use FullCalendar v4 in timeline-view.
var calendar = null;
document.addEventListener('DOMContentLoaded', function() {
calendar = new FullCalendar.Calendar(document.getElementById('preview'), {
editable: true,
eventResizableFromStart: true,
eventResourceEditable: true,
selectable: true,
...
select: function(selectionInfo) {
var event = new Object();
event.title = 'title';
event.start = selectionInfo.start;
event.end = selectionInfo.end;
event.resourceId = selectionInfo.resource.id;
calendar.fullCalendar('renderEvent', event); // console says 'calendar.fullCalendar is not a function'
//$('#preview').fullCalendar('renderEvent', event); // I also tried this, but the same error as above
}
});
});
calendar.fullCalendar('renderEvent', event);
...I guess you copied this from somewhere? Because this is fullCalendar version 3 syntax. for version 4 you would write
calendar.addEvent(event);
See https://fullcalendar.io/docs/Calendar-addEvent for documentation. Always check that the examples you find apply to the correct version of the software.
This same question has been asked repeatedly, and the only time it has been answered is the one where the fellow was trying to initialise datepicker in the .onReady() function. I am not doing that. In fact, I am actually doing what that solution is doing; implementing datepicker immediately after creating the element.
Here is my template code:
<input type=text name="txt_you_History_From_Date_XXX" id="txt_you_History_From_Date_XXX" class="month-picker inputField" size=16 maxlength=16>
You will notice the month-picker class. Also, you will notice the "XXX" placeholders.
Here is the code that inserts that template code:
//
// find the next available id
//
for (var i = 0; ; i++) {
if (!$("#divEmployer_" + i.toString()).length) {
break;
}
}
//
// get html, and replace the placeholders with id, then append.
//
$.get("content/contentHistoryEmployerTemplate.html", function (data) {
while (data.indexOf("XXX") >= 0) {
data = data.replace("XXX", i.toString());
}
$("#employerDIV").append(data);
});
//
// activate datepicker on all month-picker class elements
//
$('.month-picker').datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
dateFormat: 'MM yy',
onClose: function (dateText, inst) {
$(this).datepicker('setDate', new Date(inst.selectedYear, inst.selectedMonth, 1));
}
});
//alert("here");
I do see the "here" alert if I uncomment it, so I know the code is being run.
The datepicker() throws no error.
I know the function is available because if I comment out my jquery-ui-min.js in my <HEAD>, a reference to datepicker() does then throw an error.
But the field does not respond when it receives focus. The datepicker does not appear.
Can anyone tell me what's wrong? Thanks!
You are trying to instantiate the datepicker before the element exists. Put that code inside the async callback.
$.get("content/contentHistoryEmployerTemplate.html", function (data) {
while (data.indexOf("XXX") >= 0) {
data = data.replace("XXX", i.toString());
}
$("#employerDIV").append(data);
// PUT DATEPICKER HERE
});
I'm trying to write my first qunit tests using my jquery date picker module, right now I want to trigger the onSelect method I am using but this doesn't seem to get picked up in the tests, here is my simple test:
JS
this.dateSelectorView.$el.on('onSelect', function() {
assert.ok(true, 'true succeeds');
});
Here is the date picker:
this.$el.datepicker({
dateFormat: Common.DATE_FORMAT,
showOtherMonths: true,
selectOtherMonths: true,
beforeShowDay: function (date) {
return _.availableDates(date, Common.availableDates);
},
onSelect: function() {
Backbone.Events.trigger('date:selected', this.value);
}
});
Listen to the view itself,
when invoking the date picker, trigger the event to the view
onSelect: _.bind(function() {
this.trigger('date:selected', this.value);
},this)
I use "bind" to expose the outer scope(the view)
Then, in your View creating the the datepicker, listen to the change event.
this.listenTo(this.dateSelectorView, 'date:selected', this.callback);
Hi I have been trying to just get the date of a bootstrap date picker and have been able to but it seems to fires 3 times. NOTE: This is not jquery date picker but bootstrap date picker.
Using this date picker: https://github.com/eternicode/bootstrap-datepicker, not older eyecon.ro one.
$(".date-picker").on("change", function(e) {
contents = $(this).val();
id = $(this).attr('id');
console.log("onchange contents: " + contents);
console.log("onchange id: " + id);
});
HTML:
<input id="start_date" type="text" data-date-format="yyyy-mm-dd" class="date-picker form-control" />
I have used a few other options other than change, like
$('.date-picker').datepicker().change(function(){};
But this does not close date picker, hoping there is an easy solution to this. thx
You should be using the "changeDate" event. For example:
var datePicker = $('.date-picker').datePicker().on('changeDate', function(ev) {
//Functionality to be called whenever the date is changed
});
Please view the documentation here for more info on this event.
it does not fix the problem, but i was using the datepicker to send through an ajax post, so the 3 change events was causing me problems - the 3rd event always failed. even if the documentation says to use a changeDate event, it doesn't seem right to me to fire the input tag's change event 3 times. the value isn't changing 3 times!
I wrote a simple 'debounce' function to get around the problem. doesn't fix the issue - which is due to multiple change events being fired from the methods: setValue (line 508) _setDate:(line 1048) and setValue (line 508) (version 1.3.0) of the widget.
var lastJQueryTS = 0 ;// this is a global variable.
....
// in the change event handler...
var send = true;
if (typeof(event) == 'object'){
if (event.timeStamp - lastJQueryTS < 300){
send = false;
}
lastJQueryTS = event.timeStamp;
}
if (send){
post_values(this);
}
it is pretty simple, just finds the jquery 'event', and makes sure that values in a window of 300ms are ignored. in my testing this all happened in 30 msec or so.
As some has mentioned already, use this:
$('#calendar').on("changeDate", function() {
});
The trick is to use changeDate instead of change.
It seems as if when checking the change event, if the change was from actual user interaction, the change event contains a value for originalEvent.
The event does NOT contain this value if the input was changed via JS:
$obj.val('1990-03-07').change() and the same with bootstrap-datepicker
Here's how I set it up:
Generic initial setup
// General selector for date inputs
var $obj = $('input[type="date"]');
$obj.datepicker({
// options here, not important for this example
});
Handle bootstrap-datepicker specific changes
$obj.datepicker().on('changeDate', function (event) {
handleInputDateAndTimeChange(event);
});
Now, deal with user interaction changes
$('input[type="date"], input[type="time"]').change(function (event) {
// This checks if change was initiated by user input and NOT JS
if(event.originalEvent !== undefined) {
handleInputDateAndTimeChange(event);
}
});
And finally, here's the handleInputDateAndTimeChange function
function handleInputDateAndTimeChange(event) {
var $input = $(event.target);
// Do what you want with $input object here...
}
I tried the answer from #pgee70 and it doesn't work for me. So this is my solution, hope its help
var send=true;
$('.input-group.date').datepicker({
todayBtn: "linked",
keyboardNavigation: false,
forceParse: false,
language: 'es-ES',
weekStart: 1,
format: 'dd/mm/yyyy',
enableOnReadonly:false,
calendarWeeks: true,
autoclose: true,
todayHighlight:true
}).on("changeDate", function(e) {
if(send){
modificarFechaAplicacionCliente($("#input_filtro_fecha_cliente").val());
send=false;
}
setTimeout(function(){send=true;},200);
});
It´s not a beaty solution, but it´s work.
Similar to the above answer, but you should use datepicker unless you've renamed the function:
var datePicker = $('.date-picker').datepicker().on('changeDate', function(ev) {
//Functionality to be called whenever the date is changed
});
This works for me, except in my case, I renamed the function to datepickerBootstrap to avoid the clash with JQuery's. So then it would become:
var datePicker = $('.date-picker').datepickerBootstrap().on('changeDate', function(ev) {
// On change functionality
});
It is fixed find your fixed js datepicker file HERE
Read fixing description HERE
I have faced the same problem with bootstrap-datepicker when it used with the jQuery OnChange event they call function 3 times. Here is my code
#Html.TextBoxFor(x => x.CmpStartDate, "{0:dd-MMM-yyyy}", new { #size = "30", #class = "form-control search-date", #placeholder = "Start date" })
#Html.TextBoxFor(x => x.CmpEndDate, "{0:dd-MMM-yyyy}", new { #size = "30", #class = "form-control search-date", #placeholder = "End date" })
<script>
$('#CmpStartDate,#CmpEndDate').datepicker({
autoclose: true,
todayHighlight: true,
minViewMode: 3,
format: "dd-M-yyyy"
});
$(".search-date").on("change", function () {
cmpStartDate = $("#CmpStartDate").val();
cmpEndDate = $("#CmpEndDate").val();
SearchThisDateRecords(cmpStartDate,cmpEndDate);
});
function SearchThisDateRecords(cmpStartDate,cmpEndDate) {
console.log("Call search method");
}
</script>
We need to call this function only one time, Not multiple time so you can use the below logic to fix this problem
<script>
$('#CmpStartDate,#CmpEndDate').datepicker({
autoclose: true,
todayHighlight: true,
minViewMode: 3,
format: "dd-M-yyyy"
});
var i = 0;
$(".search-date").on("change", function () {
cmpStartDate = $("#CmpStartDate").val();
cmpEndDate = $("#CmpEndDate").val();
SearchThisDateRecords(cmpStartDate,cmpEndDate);
i++;
console.log(i);
if (i == 3) {
SearchThisDateRecords(cmpStartDate,cmpEndDate);
}
});
function SearchThisDateRecords(cmpStartDate,cmpEndDate) {
i =0; //Reset i value
console.log("Call search method");
}
</script>
Get global variable count and check if equal to 0 then execute Your function.
var count=0;
$( "#Id" ).datepicker({ minDate: 0}).on('change',function (){
if(count==0)
validity();//any function
count=1;
});
validity(){ count=0;}
bit annoying..
my code was:
var c=0;var send=false;
$(document).ready(function() {
jQuery( ".ed" ).datepicker({
format: "yyyy-mm-dd",
autoclose:!0
}).on('change',function() {
if(c==2){
c=0;
send=true;
}else{
c++;
send=false;
}
});
});
Please use changeDate function in place of change .
var LastController =['id','value']; //global variable...
function datepeakerchange(e){
if ((LastController[0] != e.target.id && LastController[1] != e.target.value) || (LastController[0] == e.target.id && LastController[1] != e.target.value)) {
LastController[0] = e.target.id;
LastController[1] = e.target.value;
write your code....
}
}
var pickerFireCount = 0;
function checkSelectedDateIsHollyday(rId) {
pickerFireCount++;
if (pickerFireCount == 3) {
if (!selectedDateIsHolyday(rId)) {
showInfoMessage('The date you selected is a holiday.');
pickerFireCount = 0;
}
}
}
Im using Pikaday as a datepicker because JQuery Datepicker is having conflict with Prototype Library.
A few issues here.
How do i use pikaday datepicker in multiple text box
How to format the date. Previously by using JQuery Datepicker, to change the format I only need to
add dateFormat:"dd M yy",
Here is the sample code
<input type="text" id="datepicker">
<script src="pikaday.js"></script>
<script>
var picker = new Pikaday(
{
changeMonth: true,
changeYear: true,
field: document.getElementById('datepicker'),
firstDay: 1,
minDate: new Date('2000-01-01'),
maxDate: new Date('2020-12-31'),
yearRange: [2000,2020]
});
</script>
I guess you're looking for a way to have pikaday work together for a date range type of thing and then manipulate the last one according to the date you selected in the first on?
...
I realize this is a bit late but perhaps someone else is interested in an answer:
Pikaday does not offer anything inhouse here but I was able to work around this by destroying the instance and creating it again when a day has been picked in the "from" picker.
HTML:
From: <input type="text" name="from" id="from">
To: <span id="toField"><input type="text" name="to" id="to"></span>
Javascript:
function dateRange() { //destroy to field and init with new param
var picker = new Pikaday({ field: document.getElementById("from") });
if(picker.toString()) {
$("#to").pikaday('destroy');
$("#to").remove();
$("#toField").html('<input type="text" name="to" id="to">');
$("#to").pikaday({ //should have the same param as the original init
format: "YYYY-M-DD",
minDate: moment(picker.toString(), "YYYY-MM-DD").toDate()
});
}
}
$(function() { //pikaday init
$("#from").pikaday({
format: "YYYY-MM-DD", //adjust to your liking
minDate: moment().subtract({days: 1}).toDate()
});
$("#to").pikaday({
format: "YYYY-MM-DD",
minDate: moment().subtract({days: 1}).toDate()
});
});
PS: don't forget to include your jquery, pickaday and moment js files...
Hope it helps
In case this stumps anyone else - you need to actually trigger the code in #Dominik's answer once a date has been selected, using the "onSelect" trigger. My code has ended up like this (because I'm using the jquery plugin version throughout in a UK format):
var dateFormat = "DD/MM/YYYY";
function dateRange() { //destroy to field and init with new param
var $from = $("#from").pikaday({
format: dateFormat,
});
if($from.val()) {
$("#to").pikaday('destroy');
$("#to").remove();
$("#toField").html('<input type="text" name="to" id="to">');
$("#to").pikaday({
format: dateFormat,
minDate: moment($from.val(), dateFormat).toDate()
});
}
}
$("#from").pikaday({
format: dateFormat,
minDate: moment().subtract({days: 1}).toDate(),
onSelect: dateRange
});
$("#to").pikaday({
format: dateFormat,
minDate: moment().subtract({days: 1}).toDate()
});
I realize this is not quite an answer to the op question, but if it's preferable to select a date range using one control, this is the method I'm using:
var cal = document.getElementById('datepicker');
var picker = new Pikaday({
onSelect: (function() {
var init = true,
start,
end;
return function(date) {
if (init) {
start = date;
picker.setStartRange(date);
picker.setEndRange(null);
rangeClear();
} else {
end = date;
picker.setEndRange(date);
rangeSet(start, end);
}
picker.draw();
init = !init;
}
}())
});
cal.appendChild(picker.el);
Where the rangeSet and rangeClear functions would exist elsewhere with the following signatures:
function rangeSet(start, end) {
//do something with the start and end dates
}
function rangeClear() {
//clear the start and end dates
}
You can see this working here: http://codepen.io/cshanejennings/pen/OMWLLg
The following is my Javascript (without jQuery) solution for From and To datepickers using Pikaday. It's working in Chrome and Firefox, but it does not work in Chrome-Android.
var nowDT = new Date();
var nowDTStr = nowDT.toShortDate();
var sin = document.createElement('input');
sin.setAttribute('type', 'text');
sin.setAttribute('id', this.id + "_cp_sin");
sin.style.width = '20%';
sin.style.cssFloat = 'left';
this.controlPanel.appendChild(sin);
this.sinPika = new Pikaday({
field: sin,
firstDay: 1,
minDate: new Date('2001-01-01'),
maxDate: new Date(nowDTStr),
yearRange: [2001, nowDT.getFullYear()]
});
this.sinPika.setDate(nowDTStr);
var ein = document.createElement('input');
ein.setAttribute('type', 'text');
ein.setAttribute('id', this.id + "_cp_ein");
ein.style.width = '20%';
ein.style.cssFloat = 'right';
this.controlPanel.appendChild(ein);
this.einPika = new Pikaday({
field: ein,
firstDay: 1,
minDate: new Date('2001-01-01'),
maxDate: new Date(nowDTStr),
yearRange: [2001, nowDT.getFullYear()]
});
this.einPika.setDate(nowDTStr);
Since I have sinPika and einPika objects added as members to my class, they're accessible elsewhere in my class in other methods, where Pika objects are used to fetch the dates set by users. Only thing is that this solution is not working in Chrome-Android for me. Could anyone try and let me know what you find?
Thanks!
Edit
I found the problem why Pikaday wasn't working on chrome-android for me. The reason is that the pikaday.js (https://github.com/dbushell/Pikaday/blob/master/pikaday.js) is different from the one here http://dbushell.github.io/Pikaday/, in that the difference lies in attaching the mousedown, touchend events. Pikaday.js on github attaches like this:
addEvent(self.el, 'ontouchend' in document ? 'ontouchend' : 'mousedown', self._onMouseDown, true);
(I think, Javascript defines touchend not ontouchend, may be, this is the reason why Pikaday.js from github repo does not work.)
And the one on dbushell.github.io/Pikaday attaches like this:
addEvent(self.el, 'mousedown', self._onMouseDown, true);
Using the script from http://dbushell.github.io/Pikaday/ works on chrome-android, the one on git repo does not.