0

I am building a dynamic form and am using the HTML5 date input for fields of type date. I was struggling to get the date input to display my date, and have come to the conclusion the value has to be a JavaScript date or the date will not display. If I am wrong on that, someone please correct me because it doesn't seem like it should be a requirement. Because my fields are dynamic I can't simply initialize specific fields to a Date, so I created a directive to convert to a JavaScript date.

angular.module( 'convertDate-directive', [] )
.directive('convertDate', function( $parse ) {
    return {
        restrict: "A",
        link: function( scope, element, attrs ) {
            var fieldModel = $parse( attrs.ngModel );
            var fieldValue = fieldModel( scope );
            fieldModel.assign( scope, new Date( fieldValue ) );
        }
    };
});

Here is my date input, which is rendered only if the field is of type date:

<input type="date"
       ng-if="field.type == 'date'"
       dynamic-model="field.name"
       ng-model="field.name"
       name="field.name"
       max="{{field.maxValue | date : 'yyyy-MM-dd'}}"
       min="{{field.minValue | date : 'yyyy-MM-dd'}}"
       ng-required="field.required"
       ng-model-options="{ updateOn: 'blur' }"
       convert-date
       class="form-control">

The problem with this directive is it triggers a $watch that I have on an object in my controller, which determines whether changes have been made and a save is needed.

My watch code:

$scope.$watch( 'application.' + resource.name, function( newValue, oldValue ) {
    if ( newValue !== oldValue ) {
        resource.changed = true;
    }
}, true );

Is there any way to suppress the change event in this scenario? Or, is there a better way to initialize an HTML5 date field? Looking for ideas. Thanks!

jsparks
  • 1,020
  • 1
  • 14
  • 19
  • Sorry I don't understand what you want. So you do have already setup a `$watch` and can determine when there is a change. What do you want to then suppress? – Kousha Aug 18 '14 at 23:20
  • The $watch fires any time the value of one of my fields changes. I don't want it to fire when I am simply initializing a date using new Date(). I want the HTML5 date input to display my date. The issue with $watch firing is a side effect of the directive I created and I would like to find a way to prevent that from happening, or I'm open to other suggestions if there is a better way to go about it than the directive I created. – jsparks Aug 18 '14 at 23:43
  • I see. Well, the `$watch` is going to fire everytime the model changes. What is the problem though with the `$watch` firing? You can check to make sure the `newValue != oldValue` and `typeof oldValue !== 'undefined'` to detect a change. When you initialize, `oldValue` is undefined, so that's what the second if statement is for. I posted it as a solution. – Kousha Aug 19 '14 at 00:05
  • Did you see my comment on your answer? – jsparks Aug 19 '14 at 00:20
  • I posted the answer after your comment on snowman's post! can you review your comment, and post it under my question if it is still relevant? – Kousha Aug 19 '14 at 00:23

2 Answers2

1

A date input doesn't require the value to be set as a Date object. It requires it to be in ISO format. See this question/answer for more details: pre-populating date input field with Javascript

Community
  • 1
  • 1
Marshmellow1328
  • 1,205
  • 3
  • 18
  • 27
  • Yes, I tried hardcoding a date in my controller in the format of yyyy-MM-dd to see if it would display in the date input and it did not. However, after seeing your answer I decided to try again with version 1.2.9 of Angular and it worked, so it must have been a bug in the beta version of 1.3.0 we are using. I upgraded to a newer beta version and it worked, so must have been fixed at some point. Thanks for confirming a JavaScript Date object is not required. – jsparks Aug 19 '14 at 01:44
  • From Angular 1.2 to 1.3 migration guide: input: types date, time, datetime-local, month, week now always require a Date object as model. That explains why it wasn't working with 1.3. – jsparks Aug 20 '14 at 01:50
0

$watch is fired every time there is a change in your scope value, this includes the initialization. However, you can use the fact that the old value is undefined before the initialization takes place:

$scope.$watch('field.name', function(newValue, oldValue)
{
    // Do not save if there is no change
    // OR this is an initialization (oldValue is undefined)
    if (newValue == oldValue || typeof oldValue === 'undefined') return;

    // Run your save() function now
});
Kousha
  • 32,871
  • 51
  • 172
  • 296
  • oldValue will initially be either a Unix timestamp or an ISO 8601 string, so it won't be undefined. I am replacing the value in the model with a Date object. I could possibly check if typeof oldValue != typeof newValue, but that seems kind of hackish to me. Another option would be to convert oldValue to a Date and compare with newValue, but that would require me to know they are supposed to be dates. – jsparks Aug 19 '14 at 00:45