I've got two calendars in a form. One is a starting date, and the other is the ending date. I'm using the 'ng-pick-datetime' (https://www.npmjs.com/package/ng-pick-datetime) to have a cross-browser calendar picker.
My goal is to block from date 0 (1st Jan 1970) to the date selected in the starting date calendar, in the ending date calendar picker.
So the thing here is to make sure the ending date is after the starting date.
For this, ng-pick-datetime' picker has the [disabledDates] property, which is waiting for an array of Dates that shouldn't be selectable.
What I'm trying is to bind this property to my array of forbidden dates, which is created in a function when the form is created, and also every time the ending date calendar gets focus.
I'm printing my array of forbidden dates to check if it is created correctly and if the dates included in it are between date 0 and the starting date selected. I looks like this part is working fine.
I don't get any browser console error. Just have the ending date calendar picker not blocking any date.
This is my template code:
<div class="input-control col-sm-6" [class.has-error]="startDate.invalid && startDate.dirty">
<label class="control-label" for="startDate">Starting Date *</label>
<owl-date-time
[(ngModel)]="data.startDate"
[dateFormat]="'DD-MM-YYYY'"
[inputId]="'startDate'"
[placeHolder]="'dd-mm-aaaa'"
[type]="'calendar'"
[dataType]="'date'"
[autoClose]="'true'"
id="startDate"
name="startDate"
#startDate="ngModel"
[disabled]="!paramsService.isSolicitante()"
[hideClearButton]
required>
</owl-date-time >
</div>
<div class="input-control col-sm-6" [class.has-error]="endDate.invalid && endDate.dirty">
<label class="control-label" for="endDate">Ending Date *</label>
<owl-date-time
[(ngModel)]="data.endDate"
[dateFormat]="'DD-MM-YYYY'"
[inputId]="'endDate'"
[placeHolder]="'dd-mm-aaaa'"
[type]="'calendar'"
[dataType]="'date'"
[autoClose]="'true'"
id="endDate"
name="endDate"
#endDate="ngModel"
[disabled]="!paramsService.isSolicitante()"
[hideClearButton]="!paramsService.isSolicitante()"
[disabledDates]="'forbiddenDates'"
(onFocus)="getForbiddenEndDates()"
required>
</owl-date-time >
</div>
//printing of selected date values:
<div class="col-sm-6">{{ data.startDate}}</div>
<div class="col-sm-6">{{ data.endDate}}</div>
{{ this.forbiddenDates }} //printing of the dates array to check it
And this is the component code (typescript), just the part that matters here:
forbiddenDates: Date[] = [];
ngAfterViewInit(): void { this.getForbiddenEndDates(); }
// This creates an array of Dates from the beginning of all times to the value of startDate
getForbiddenEndDates(): void {
let dateZero: Date = new Date(0);
let forbiddenDates: Date[] = [];
while (dateZero <= this.data.startDate){
forbiddenDates.push(new Date(dateZero));
dateZero.setDate(dateZero.getDate() + 1);
}
this.forbiddenDates = forbiddenDates;
}
Screenshot of the form and the forbidden dates array printed
I answer myself. It seems that this [disabledDates] template property doesn't change dynamically, so it's just for a fixed array of dates.
The solution is much simpler. Add this template property to the endDate input field:
[min]="data.startDate"
Related
I've created a form the user fills out, and then can update. When the form renders to update, the date that is stored in the user's database entry won't show up. I get this error: The specified value "Mon Jul 27 1987 20:00:00 GMT-0400 (Eastern Daylight Time)" does not conform to the required format, "yyyy-MM-dd"
I have another form, and it seems to work just fine, but for some reason this form won't load the date upon rendering.
This is how the date is set when the form is originally submitted and updated:
<div>
<label>Date of birth</label>
<input name="dateOfBirth" label="Date of birth" type="date" value={dateOfBirth} onChange={(e)=> setDateOfBirth(e.target.value)} />
</div>
and this is how the state is loaded:
const HHForm = ({user, userState}) => {
const [dateOfBirth, setDateOfBirth] = useState(userState?.healthHistory[0]?.dateOfBirth ? ((userState?.healthHistory[0]?.dateOfBirth) : (''))
But when the component renders to update the form, the date is just left as an empty date selector, as if there is no date data, but the database has an entry for the dateOfBirth.
HTML 5 date pickers should be in format of yyyy-MM-dd. You should format your date. You can use moment to do that. https://www.npmjs.com/package/moment
import moment from 'moment'
setState(moment(your date here).format('YYYY-MM-DD'))
Here is full code https://codesandbox.io/s/date-picker-76lgw?file=/src/App.js
How to select a past date in the DOB field? What Javascript function can I use in Cypress automation?
It is not a free text field, only can select from the date picker. Here is the screenshot and the HTML
<input _ngcontent-kgi-c484="" id="dob" formcontrolname="dob" readonly=""
bsdatepicker="" placeholder="Optional" class="form-control
plore-form-control ng-valid ng-touched ng-dirty" ng-reflect-name="dob"
ng-reflect-bs-config="[object Object]"
ng-reflect-max-date="Fri Apr 16 2021 00:00:00 GMT+1">
I tried this function but it didn't work
cy.get('#dob').invoke('val').then((text) => {
expect('08/05/1999').to.equal(text);
What I did was add a custom command (we have various datepickers throughout our system, each having a slightly different selector).
Cypress.Commands.add("setDateInput", (selector, value) => {
// wait for the flatpickr instance to be applied before setting the date
// 'flatpickr-input' class is added on initiation
cy.get(`${selector}.flatpickr-input`).then($el => {
$el.get(0)._flatpickr.setDate(value, true)
})
});
Here, you can pass in a changing selector and then the DD/MM/YYYY format as parameters. Hope this helps someone.
The control is a bunch of buttons, you can click them in Cypress, e.g
cy.get('button').contains('8').click(); // select the 8th day
The chevrons (left and right) you'll need to click a few times,
cy.get('button.uib-left').click().click().click().click() // keep going for MM/YY
You can click on that middle part, but I can't figure that one out exactly.
Ok, I figured it out, click "April 2021" once to choose the month
cy.get('button').contains('April 2021').click();
// now select the month
cy.get('button').contains('May').click()
OR click the "April 2021" then "2021" to select the year
cy.get('button').contains('April 2021').click();
cy.get('button').contains('2021').click();
cy.get('button.uib-left').click().click() // get decade with 1999
// now select the year
cy.get('button').contains('1999').click()
But you get the idea, interact the way a user does.
How can I make that ReactJS Datepicker should only display days starting from this month and on (no back dates).
This is not exactly what I was trying to do but its a quick fix.
I use the includeDates={this.state.includeDates} from ReactJS Datepicker
and I made a custom function to print out the days starting from today and i save it in an array that i then pass to the react state excludeDates: [''],
and only those days will be clickable.
let fromDate = moment();
let toDate = moment().add(24, 'months'); //including only days starting from today untill 2 year
for (let i = 0; i < moment(toDate).diff(fromDate, 'days') + 1; i++) {
state.includeDates.push(moment(fromDate).add(i, 'days'));
}
Thanl you! hope it helps someone.
You can use moment startOf using 'month' parameter to get the first day of the month and pass it to minDate option to make the datepicker enable only dates from the start of the current month:
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
minDate={moment().startOf('month')}
/>
If you want to enable only future dates, simply remove maxDate option from the linked example, you can use the following code:
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
minDate={moment().startOf('day')}
/>
I am using angularjs to show a history of stocks bought and sold date wise.
My data is consists of a unixtimestamp field. I want to club the date together to show a header BAND of the date and show entries of that date below the header.
I currently used the ng-repeat="x in transactions" however i am not able to add a custom if condition to check if the date is a new data and inject a header between the rows printed.
Here is how i want the output to be
Monday, 12th January 2015
MSFT,BUY,10,1000
YHOO,SELL,50,200
Tuesday, 13th January 2015
MSFT,SELL,40,500
Code currently is
<div ng-repeat="x in transactions" >
{{ x.transaction_date *1000| date:'MMM-dd-yyyy'}}, {{x.transaction_type}}, {{x.stock_code | limitTo: 10}}, {{x.units}}, Rs. {{x.balance}}
</div>
you can refer with your ng-if to a function with the actual item and the last Date. the function will check if the item has the same date than the last item and save the actual date into an scope variable to check the next one against this.
ng-repeat="item in transactions"
....
<div class="header" ng-if="ctrl.checkForNewDate(item)">
<!-- Header Content -->
</div>
in the controller
var vm = this;
vm.lastDate = new Date("2000/01/01");
vm.checkForNewDate = checkForNewDate;
function checkForNewDate(item) {
var dateItem = new Date(item.timestamp);
if (dateItem == vm.lastDate) {
return false;
} else {
vm.lastDate = dateItem;
return true;
}
code as prototype not checked sorry for that ;-)
I'm having trouble getting Moment in Angular to format my time like I would like. I have the date filter working here:
<h4>{{event.date | amDateFormat:'MMMM Do'}}</h4>
But when I try to use this format to print out a time, my time disappears completely out of the browser. This is what I am typing:
<div class="row">
{{event.time | amDateFormat: 'h:mm a'}}
</div>
I am using Firebase if that matters. Also, the input to get the time is the HTML5 input type=time attribute.
When you use type=time for an input, the value is stored as a string which only represents a time, such as "1:00" or "13:00". The amDateFormat filter needs a value that can be interpreted as a date which can be a Date object, a number value for a timestamp, or a properly formatted string date. The time values that you will get using type=time are not valid date strings so amDateFormat can't properly parse the value.
The easiest way to make it work is to just concatenate the value of event.date and event.time before you use the amDateFormat filter:
<div class="row">
{{event.date + ' ' + event.time | amDateFormat: 'h:mm a'}}
</div>
A better solution is to use a function where you pass in the date and time, or just the time and construct something that can be interpreted as a date, or is a date object.
<div class="row">
{{ combine(event.date,event.time) | amDateFormat: 'h:mm a'}}
</div>
simple combine function
$scope.combine = function(date,time) {
if (date && time) {
return date + ' ' + time;
} else {
return "";
}
};
I still think it's kinda hacky to have to add a date to the time like that but it works and you may even end up joining them together anyway in your data model. The best solution I believe would be to just have one event.dateAndTime object that you can use to represent both the date and time -- and you can do this using the type=datetime-local html5 type (at least in Chrome it worked for me).
<dir>Date and time: <input type="datetime-local" ng-model="event.datetime"></dir>
<h4>{{event.datetime | amDateFormat:'MMMM Do'}}</h4>
<div class="row">
event.datetime time: {{ event.datetime | amDateFormat: 'h:mm a'}}
</div>
Here's a working plunker: http://plnkr.co/edit/OERKK9ilxFwUlKLKirtl?p=preview