Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow DateTime to have a starting date without setting the object's value #9846

Closed
mikewagz opened this issue Jan 2, 2017 · 51 comments
Closed
Assignees

Comments

@mikewagz
Copy link

mikewagz commented Jan 2, 2017

Ionic version: (check one with "x")
[X] 2.x

I'm submitting a ... (check one with "x")
[X] feature request

Current behavior:
Currently to have the DateTime object open with a value (other than the max value) you must set the ngModel value for the object before the DateTime is opened. Sometimes this isn't desired, such as when you'd like to leave the field blank if the user does not input a date.

Expected behavior:
Adding parameters to start the DateTime at a certain date, like today, will enhance usability. For example, if my date selection range is from 2000 - 2025, but the users most often select a date within a few weeks of today, it would be much easier to start the DateTime interface with today's date instead of 1-1-2025.

Steps to reproduce:
Open DateTime.

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

Cordova CLI: 6.4.0 
Ionic Framework Version: 2.0.0-rc.4
Ionic CLI Version: 2.1.17
Ionic App Lib Version: 2.1.7
Ionic App Scripts Version: 0.0.48
ios-deploy version: 1.9.0 
ios-sim version: 5.0.11 
OS: OS X El Capitan
Node Version: v6.9.2
Xcode version: Xcode 8.2.1 Build version 8C1002
@WhatsThatItsPat
Copy link

WhatsThatItsPat commented Jan 2, 2017

@mikewagz I had a half-written feature request that is similar, so I'll piggyback on yours.

DateTime needs a "presentWith" input property which is what the dials in the interface will be set to when a user opens the control, but before they've selected a date and put data in the model.

It could be bound to a date in your code: [presentWith]="ISOinCode"

You could pass in something that matches your displayFormat (or pickerFormat if that makes more sense): presentWith="2017/01/01"

If you've set min or max properties, you could use those strings for convenience: presentWith="min" or presentWith="max"


pickerPreset could be an alternative to presentWith.

@mhartington
Copy link
Contributor

So just some comment on this

As for a presentWith property, I don't think I see the point of this.
Take for example, the alarm option in ios

img_4487

While it's an inline control, it's default value and presented value is the current date. So if I toggled the alarm and hit save, it would just take that fine. I see no issue with the "presented value" being the actual value of the dateTime.

@WhatsThatItsPat
Copy link

The iOS alarm is too simple to compare to other use cases:

  • Because the DateTime is inline, and is essentially the whole point of the form, it's impossible for the user to miss.
  • There is almost no penalty for a wrong answer; you just delete or edit it.
  • Validation is irrelevant since there's no invalid response.
  • The user isn't actually expected to choose the current time. The assumption is that they'll change it, but it's a convenient starting point if they want to set an alarm N minutes from now.

But if you have a more complicated form (several other inputs, start and end dates, follow up screens that depend on those dates, etc.), and you put valid presets in the model:

  • A user might forget to enter dates, the form submission will succeed, and now you have the penalty of bad data in the DB.
  • To fix that you have to watch for ionChange event. Then, if the user hasn't changed the value, alert them and ask if they intended to leave the date as-is (I'm actually doing this in one of my flows).
  • You've lost out on the default touched/pristine/valid functionality without doing extra work.

Starting the form with preset DateTime values is like putting John and Doe in the model as first and last names, and counting on the user to change them while writing extra code to respond if they don't.

A presentWith property would give users a more convenient starting point regarding the dials, like a souped-up placeholder.

In fact, pickerPlaceholder is another alternative property name to consider.

@mikewagz
Copy link
Author

mikewagz commented Jan 6, 2017

@mhartington - I belive a valid use case for this involves forms where a date field is optional. I don't want to set a value to the field, as the user may desire to leave it blank. However, if they choose to enter a date, there should be an option to start it at a certain value instead of the maximum date allowable by the field (which is the current default.)

A concrete example would be "follow_up_date". A user may or may not want to input something in here. If they do, the presented date when they open the DateTime UI should be tomorrow, not 12-31-2025. Currently this user experience involves the user scrolling all three date fields quite a bit to get from, say, 12-31-2025 to 1-6-2017.

Let me know if that makes sense. Thank you and thanks for creating such a great framework for building mobile apps!

@mhartington
Copy link
Contributor

Both comments make sense. We will revisit this post 2.0 final release.

@shyamal890
Copy link

Time to revisit, I guess

@keithdmoore
Copy link
Contributor

+1 This is a VERY common use case that I encounter often.

@trakhimenok
Copy link

My issue was closed as part-duplicate: #10710

But it has different details so I copy-paste my post here.

Ionic version: (check one with "x")
[x] 2.x

I'm submitting a ... (check one with "x")
[x] bug report
[x] feature request

Current behavior:

If max attribute specified into future for example "2020-12-31" the date picker would display:

  • Day: {1}
  • Month: {unselected but list starts with today's month, currently March}
  • Year - {the max one, for this example 2020}.

If I scroll the year to 2019 and back to 2020 all 12 months are shown as expected.

Expected behavior:

Regards bug: I expect either max year with all 12 months (or up to the last allowed by max) or a current year to be selected by default (or first allowed by min property)

Regards feature request: I suggest we have additional property defaultValue.

Reasoning: I want some of my date fields to be optional so I can't fill the value before the picker clicked but once user opens drop down I want a specific date to be preselected, specifically I need today or tomorrow but could be any arbitrary date. Also for optional fields would be nice to have some way to clear the field from previously entered value.

Steps to reproduce:
See plunker: http://plnkr.co/edit/H7eMFjSDrj8VbsUo0bDW?p=preview

Related code:

<ion-list>
    <ion-item>
			<ion-label>Due on</ion-label>
			<ion-datetime
			  displayFormat="D MMMM YYYY"
			  pickerFormat="D MMMM YYYY"
			  min="2017-03-08"
			  max="2020-12-31"
			  ></ion-datetime>
    </ion-item>
  </ion-list>
</

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

Cordova CLI: 6.5.0 
Ionic Framework Version: 2.2.0
Ionic CLI Version: 2.2.1
Ionic App Lib Version: 2.2.0
Ionic App Scripts Version: 1.1.4
ios-deploy version: 1.9.1 
ios-sim version: 5.0.11 
OS: OS X El Capitan
Node Version: v6.7.0
Xcode version: Xcode 8.2.1 Build version 8C1002

@manucorporat manucorporat added this to the 2.3.0 milestone Mar 15, 2017
@manucorporat manucorporat self-assigned this Mar 15, 2017
@manucorporat manucorporat removed this from the 2.3.0 milestone Mar 16, 2017
@SliceofCheese
Copy link

@manucorporat Any progress on this? It would be really great if I had the ability to set default dates that haven't been selected to today's date. Or at the very least, do you guys have a sort of work around that could work as a temporary patch-up solution?

@zakton5
Copy link
Contributor

zakton5 commented May 2, 2017

Yes, this is pretty important functionality. Common user expectations are for the datepicker to have today's date selected by default.

@imgx64
Copy link
Contributor

imgx64 commented May 9, 2017

I made a PR that sets the default picker values to today. It doesn't completely fix this bug since you can't change the default to an arbitrary date, but I think that's fine for most use cases.

@nrcrabbe
Copy link

I have been toying with this lately. I have a datetime field that is optional, so I do not want to populate the ngModel. However on opening the picker, the current date should be presented. However I think this is a narrow solution as the developer should be able to pass any value in as an input as the pickerDefault.

Posting this here as it is a slightly different take on what has been suggested above.

So after a bit of hacking I think I'm on the right path.

datetime.js L451

                // cool, we've loaded up the columns with options
                // preselect the option for this column
                var /** @type {?} */ optValue = getValueFromFormat(_this.getValue(), format);
                var /** @type {?} */ selectedIndex = column.options.findIndex(function (opt) { return opt.value === optValue; });
                if (selectedIndex >= 0) {
                    // set the select index for this column's options
                    column.selectedIndex = selectedIndex;
                }
                // add our newly created column to the picker
                picker.addColumn(column);

The problem here is getting optValue. It takes this from _this.getValue() which will return the model Value. Since we want separation between the picker default and the passed model value this must be changed.

Replace the call to _this.getValue() with a call to an new function:

    DateTime.prototype._getValueOrDefault = function () {
      if (Object.keys(this._value).length)
        return this.value;
      else {
        var _default = {};
        updateDate(_default, this.pickerDefault);
        return _default;
      }
    };

If there is no valid date being passed then use this.pickerDefault which I have declared:

DateTime.prototype.pickerDefault; in DateTime_tsickle_Closure_declarations()

So now you can call it thusly:

<ion-datetime displayFormat="DD MMM YY" pickerFormat="DD MMM YYYY" pickerDefault="2017-08-06" min="2017" max="2020" formControlName="date"></ion-datetime>

or more realistically pass in a function that returns an ISO string of whichever date is applicable.

This works for me but I felt like an absolute novice poking around the innards of the Ionic component code so I'm not really sure what I was doing.

I'm hoping this could inspire a developer to make what should be an easy modification.

Cheers

@RyxMedia
Copy link

Also waiting for this feature as the current behaviour is not really user friendly.

@shyamal890
Copy link

This is THE most important feature that needs to be there. I would term it as bug instead of feature request.

@jacek-jaskolski
Copy link

I've created PR for this issue: #12698

@bkarv
Copy link

bkarv commented Aug 26, 2017

As discussed here, what is a likelihood of a presentWith or default value property being implemented for Datetime? Like the other comments having the date starting on the MAX value is not very user friendly especially when setting the date value in advance is not an option.

Has anyone found a work around which does not involve setting the ngModel value?

Is there a way to listen or an event when the DateTime modal is open?
If so a possible work around is to set the today date value just before the modal box is opened. If the user hits cancel, we can reset the value back to NULL on the datetime event ionCancel. I've tried doing this by using the (click) event but the datetime dialog view is opened before I can set the datetime value through click therefore showing the MAX value.

Appreciate any comments or possible work arounds. Thanks.

@longdw
Copy link

longdw commented Sep 8, 2017

need this feature also, I hope ionic team update this as soon as possible.

@longdw
Copy link

longdw commented Sep 8, 2017

I found a solution, look at this stackoverflow

@shyamal890
Copy link

Ionic Guys would really appreciate if you can give an update on this. Current ion-datetime is a bad UX design!

I have heard a lot of end clients say

Its too time consuming to change day, then month and then the year. Even if we want to change just the day from today, it takes a hell lot of time and effort

@dniemuth
Copy link

Any update on this?

@mlynch mlynch closed this as completed in 559f4d3 Sep 29, 2017
@WhatsThatItsPat
Copy link

As there are valid use cases for using min, max, or the current time, you could have convenience values to pass in. So...

pickerPlaceholder="2017/10/1"
pickerPlaceholder="min" // only if a min is defined, otherwise default to now
pickerPlaceholder="max" // only if a max is defined, otherwise default to now
pickerPlaceholder="now" // maybe not necessary if this is the default anyway

@mlynch
Copy link
Contributor

mlynch commented Sep 29, 2017

Fixed in 3.7.1. Should satisfy all of the above. use initialValue to set the initial value, but note that will only "commit" if the user chooses something and hits "done"

@mlynch mlynch closed this as completed Sep 29, 2017
@mlynch
Copy link
Contributor

mlynch commented Oct 1, 2017 via email

@MikeCIDFG
Copy link

MikeCIDFG commented Oct 2, 2017

Well, it doesn't in my case. Only event binding with parentheses (as shown below) works for me.
Plain property or [bound] property default it to "01/01/2017" same as not doing anything ...

"Banana Box" two-way binding [(initialValue)]="10/10/2017" throws a template parse error on encountering =. Not sure what that's about, because nothing else changes. I'm probably just not using that right.

Might be a quirk of my setup, or using Reactive form instead of template-driven form?

In any case, the following works as expected for me w/Ionic 3.10.3, and I thought that note might be of help to others if they encounter the same issue:

<ion-datetime displayFormat="MM/DD/YYYY" formControlName="resultsReceivedDate" (initialValue)="getLocalDateTime()"></ion-datetime>

@WhatsThatItsPat
Copy link

WhatsThatItsPat commented Oct 2, 2017

Try an ISO formatted date: initialValue="2017-10-10".

@mlynch, Any way it could be smart enough to pick up on your displayFormat or pickerFormat?


...or a note in the docs saying it must be ISO (never mind, it's already there).

@J-who
Copy link

J-who commented Oct 5, 2017

I'm having an issue with initialValue and using displayFormat/pickerFormat to allow the user to only adjust the times.

<ion-datetime displayFormat="h:mm a" pickerFormat="h:mm a" [(ngModel)]="entry.time_end" (ionChange)="updateTimes()" initialValue="2017-10-05T04:15:48+00:00">

If the item is empty and you pick a time, it'll save just the h:mm and not in the valid Date format. But if there's an existing time, it'll save the thing in the correct format.

time_start: "2017-10-02T01:37:53+00:00",
time_end: "04:15"

Maybe I'm doing it wrong?

@tamiris-fonseca
Copy link

initialValue doesn't work for me. My code is:

<ion-datetime cancelText="Cancelar" doneText="Ok" (initialValue)="2017-10-18" [(ngModel)]="editCorretiva.dataFalha" displayFormat="DD MMM YYYY"></ion-datetime>

I've tried using initialValue as a plain property, tried using a function that returns the date string and also tried to put the value format as displayFormat instead of ISO but none of them work. Any ideas?

@zakton5
Copy link
Contributor

zakton5 commented Oct 18, 2017

@tamiris-fonseca (initialValue)="2017-10-18" should be initialValue="2017-10-18" or [initialValue]="'2017-10-18'". Try that and see if it works.

@tamiris-fonseca
Copy link

@zakton5 none of them work. initialValue="2017-10-18" has no effect and [initialValue]="'2017-10-18'" returns a runtime error, it says initialValue is not a know property of 'ion-datetime'

@d4ex
Copy link

d4ex commented Oct 26, 2017

I have the following Code and it is not working too:

              <ion-datetime #dueDatePicker hidden="true" min="{{ minDate }}" [initialValue]="2017-12-30" max="2100-10-31" pickerFormat="DD MMMM YYYY HH mm" [(ngModel)]="dueDate" ></ion-datetime>

@kukipei
Copy link

kukipei commented Oct 26, 2017

initialValue="2017-10-18" doesn't work for me also

@tobbbe
Copy link

tobbbe commented Oct 26, 2017

are you sure you're running ionic 3.7.1? https://github.com/ionic-team/ionic/blob/master/CHANGELOG.md

ionic info

@kukipei
Copy link

kukipei commented Oct 26, 2017

you are right, I am not using 3.7.1. Thanks

@d4ex
Copy link

d4ex commented Oct 26, 2017

I'am using 3.7.1... but initialValue is not working because its only a solution for kukipei's problem.
But via

@ViewChild

and "setValue" i can set the date to a initial value.

@fspugna
Copy link

fspugna commented Oct 26, 2017

@d4ex can you please show us an example about how you set the initial value via @ViewChild?
Thx a lot!

@d4ex
Copy link

d4ex commented Oct 30, 2017

I have a Datepicker like this one in the html file:
<button ion-button icon-only id="btn_add_duedate" (click)="addDueDate()"> <ion-icon ios="md-time" md="md-time"></ion-icon> <ion-datetime #dueDatePicker hidden="true" min="{{ minDate }}" cancelText="{{ 'TASK_DETAILS.ADD_DUE.CANCEL' | translate }}" doneText="{{ 'TASK_DETAILS.ADD_DUE.DONE' | translate }}" max="2100-10-31" pickerFormat="DD MMMM YYYY HH mm" [(ngModel)]="dueDate" (ionChange)="dueDateChange()"></ion-datetime> </button>

In the typescriptfile i use the following code to get the Viewchild:
@ViewChild('dueDatePicker') dueDatePicker: DateTime;

... and before open of the datePicker is called i use 'setValue' to set a initialValue:

addDueDate() {
    if(this.task.dueDate != undefined) {
      this.dueDatePicker.setValue(this.task.dueDate.toISOString());
    }

    this.dueDatePicker.open();
  }

@whitecat
Copy link

whitecat commented Nov 21, 2017

I am using ionic 3.10.3
<ion-datetime pickerFormat="DDDD MMMM D YYYY" placeholder="Click to select date" formControlName="{{aQuestion.questionId}}" (initialValue)="10/01/2017"></ion-datetime>
The initial date is still 01/01/2017

I also tried both initialValue="2017-10-18" or [initialValue]="'2017-10-18'" which didn't work.

@kensodemann
Copy link
Member

@whitecat - 3.10.3 is not a valid version of the ionic framework. Perhaps that is your CLI version? not sure.

To check your Ionic Framework version, you can run ionic info and the look for the line that says Ionic Framework. It will look something like this:

    Ionic Framework    : ionic-angular 3.9.2

You can also query NPM to find out what version of ionic-angular is installed. That will be your version of Ionic Framework.

@whitecat
Copy link

You are correct, that is why it is not working. I am on 3.6.0

@misterti
Copy link

misterti commented Dec 11, 2017

Fixed in 3.7.1. Should satisfy all of the above. use initialValue to set the initial value, but note that will only "commit" if the user chooses something and hits "done"

This is unfortunately not good enough. The initialValue needs to be visible immediately in the field when set, not only after picker is opened and done is hit. The behaviour i'm getting now on 3.9.2 is that the field is initially empty

@misterti
Copy link

To have the value presented on the field immediately, add this code after this._initialize():
if (this.initialValue)
this.setValue(this.initialValue);
If someone can please examine if this is the right place and commit a change to the trunk.
Thank you.

@WhatsThatItsPat
Copy link

@misterti see #13292 (comment)

You're (understandably) misunderstanding initialValue and should just use ngModel.

initialValue is meant to set the picker wheels / dropdown to a sensible starting spot while not affecting the data in the model. It's not meant to set the initial value of the DateTime as the property name implies, but of the picker when it opens.

@misterti
Copy link

misterti commented Dec 11, 2017

Hi,
i see, but if i have a ngFor loop, how else can i set and present initial value for multiple items in the template?

@misterti
Copy link

Then we need a way for ion-datetime to present an "initial" value in the field

@kensodemann
Copy link
Member

@misterti - what exactly are you attempting to accomplish here?

You mention using ngFor so I assume you have a collection of objects and need to edit the dates or something (really hard to know without context).

If I had a bunch of objects and a standard input in a regular old Angular CLI app, I would do something like:

<input *ngFor="let item of items" [(ngModel)]="item.description" />

If I needed to initialize the description fields beforehand I would do that at some point in the TypeScript.

So it would be basically the same for datetime, something like this:

<ion-datetime *ngFor="let item of items" [(ngModel)]="item.startDate"></ion-datetime>

And again if startDate needed a value that wasn't set for some reason, I would handle that in the TypeScript.

The idea behind the (somewhat awkwardly named) initialValue property is that you don't want to set the model value, and thus don't want to display anything until the user picks something, but you still want to give them a default option when they open the picker, as described in the initial write-up and further clarified in the comments that the followed:

Currently to have the DateTime object open with a value (other than the max value) you must set the ngModel value for the object before the DateTime is opened. Sometimes this isn't desired, such as when you'd like to leave the field blank if the user does not input a date.

@misterti
Copy link

I had to do a transformation of the date before presentation, so i tried [(ngModel)]="transformationFunction(item.startDate)" in a ngFor, but that didn't work. Doing transformation in typescript before presentation and only putting [(ngModel)]="item.startDate" indeed works and also changes the list model accordingly. Thank you for clarifying.

@ehorodyski
Copy link

What about the default label value? I have a form where there are two different <ion-datetime>s, both using the same formControlName, one for date, one for time. Consumers want two fields, what can I do?

However, no matter how hard I try, when I'm just doing time with a formControlName I never get the timezone offset calculated for the label..even if the field itself has been properly adjusted.

@ionitron-bot
Copy link

ionitron-bot bot commented Sep 1, 2018

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

@ionitron-bot ionitron-bot bot locked and limited conversation to collaborators Sep 1, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests