Textalk / angular-schema-form-datepicker

Datepicker add-on for Angular Schema Form using pickadate!
MIT License
43 stars 57 forks source link

min/max date $watch continuously #23

Open luciformed opened 9 years ago

luciformed commented 9 years ago

Common use case is to have two pickers to specify start and end dates, where end date cannot be before the start date. Doesn't it make sense to keep watching for min/max date changes?

davidlgj commented 9 years ago

The standard approach in schema form has been to not watch changes in form definitions but instead let the user issue a schemaFormRedraw event , this is to keep the number of watches down.

Two solutions spring to mind (if the standard solution is not enough), one is to add an option to watch for changes of min/max, the other is to create an addon with two date fields explicitly for ranges.

luciformed commented 9 years ago

I'm not sure how the latter approach could work, one field handling 2 keys? Could $validators be used somehow to implement a solution to this?

davidlgj commented 9 years ago

I need to get an example going on how to do something like that soon, you aren't the first one to ask :) But basically you could swing something by letting it include the two fields, like a fieldset limited to two fields.

$validators could be used to validate the ranges, but wouldn't let you change min/max unless we watch them.

ghost commented 9 years ago

Hi @davidlgj @luciformed ,

I have find some work-around for this issue, Please have a look at my plnkr link http://plnkr.co/edit/Tkhgnh?p=preview

I am an angular schema form noob. So, I would really appreciate your suggestion on my fix.

Before going through the code, I would like to share you the logic what I followed.

When we select the start date (i.e., 9 september, 2015) the end date can't be before the given date When we select the end date (i.e., 9 septermber, 2015) the start date can't be after the given date

Let me start with the template changes, I have added three attributes to the template "rangeStartDateField","rangeEndDateField","rangeSelector"

            ******************** datepicker.html *********************************

    <div class="form-group {{form.htmlClass}}" ng-class="{'has-error': hasError()}">
      <label class="control-label" ng-show="showTitle()">{{form.title}}</label>
      <div ng-class="{'input-group': (form.fieldAddonLeft || form.fieldAddonRight)}">
        <span ng-if="form.fieldAddonLeft"
          class="input-group-addon"
          ng-bind-html="form.fieldAddonLeft"></span>
        <input ng-show="form.key"
           style="background-color: white"
           type="text"
           class="form-control {{form.fieldHtmlClass}}"
           schema-validate="form"
           ng-model="$$value$$"
           ng-disabled="form.readonly"
           pick-a-date="form.pickadate"
           min-date="form.minDate"
           emit="form.minDate"
           max-date="form.maxDate"
           rangeStartDateField ="form.rangeStartDateField"
           rangeEndDateField="form.rangeEndDateField"
           rangeSelector="form.rangeSelector"
           name="{{form.key.slice(-1)[0]}}"
           format="form.format" />
        <span ng-if="form.fieldAddonRight"
          class="input-group-addon"
          ng-bind-html="form.fieldAddonRight"></span>
      </div>
      <span class="help-block">{{ (hasError() && errorMessage(schemaError())) || form.description}}</span>
    </div>

I have changed the config section of the bootstrap-datepicker.js

       ******************** bootstrap-datepicker.js *********************************
        var datepicker = function(name, schema, options) {
        if (schema.type === 'string' && (schema.format === 'date' || schema.format === 'date-time')) {
            var f = schemaFormProvider.stdFormObj(name, schema, options);
            f.key = options.path;
            f.type = 'datepicker';
            f.rangeStartDateField = options.rangeStartDateField;
            f.rangeEndDateField = options.rangeEndDateField;
            f.rangeSelector = options.rangeSelector;
            console.log("angular schema form >  addon > datepicker > form definition > ", f);
            options.lookup[sfPathProvider.stringify(options.path)] = f;
            return f;
        }
        };

When we select the date, the date has been pushed to the view using ngModel.$parsers.push(function()); , Here I am getting the start date or end date and $emit the event

        ******************** bootstrap-datepicker.js *********************************
        ngModel.$parsers.push(function() {
            /*
                range selector
            */
            if (angular.isDefined(scope.$parent.form.rangeSelector) && scope.$parent.form.rangeSelector ==="true") {
                    /*
                        selected start date should be set as min date for end date field
                        $emit the event 
                    */
                var key = scope.$parent.form.key[0];
                if (angular.isDefined(key) && angular.isDefined(scope.$parent.form.rangeStartDateField) && key === scope.$parent.form.rangeStartDateField) {
                    var rangeEndDateField = {};
                    rangeEndDateField.minDate = picker.get('select', scope.format || defaultFormat);
                    rangeEndDateField.key = scope.$parent.form.rangeEndDateField;
                    scope.$root.$emit( "rangeEndDateField", rangeEndDateField);
                } 
            /*
                   selected end date should be set as max date for start date field
                   $emit the event
            */
            else if (angular.isDefined(key) && angular.isDefined(scope.$parent.form.rangeEndDateField) && key === scope.$parent.form.rangeEndDateField) {
                   var rangeStartDateField = {};
                   rangeStartDateField.maxDate = picker.get('select', scope.format || defaultFormat);
                   rangeStartDateField.key = scope.$parent.form.rangeStartDateField;
                   scope.$root.$emit("rangeStartDateField", rangeStartDateField);
                }
                }

                return picker.get('select', scope.format || defaultFormat);
            });

added the listeners to the event and updating the min and max date of the field as per my logic

     ******************** bootstrap-datepicker.js *********************************
       /*
        listener for the event rangeEndDateField
        */
        scope.$root.$on("rangeEndDateField", function(event, data) {
        var key = scope.$parent.form.key[0];
        if (angular.isDefined(key) && key === data.key) {
            picker.set('min', formatDate(data.minDate));
            console.log("angular schema form >  addon > datepicker > event listener > event name : rangeEndDateField > ", event, key, data);
        }
        });
        /*
        listener for the event rangeStartDateField
        */
        scope.$root.$on("rangeStartDateField", function(event, data) {
        var key = scope.$parent.form.key[0];
        if (angular.isDefined(key) && key === data.key) {
            console.log("angular schema form >  addon > datepicker > event listener > event name : rangeStartDateField > ", event, key, data);
            picker.set('max', formatDate(data.maxDate));
        }
        });

This is my schema and form definition

      $scope.schema = {
        "type": "object",
        "title": "Comment",
        "properties": {

          "userStartDate": {
        "type": "string",
        "format": "date",
        "title":"Product Start Date"
          },
          "userEndDate": {
        "type": "string",
        "format": "date",
        "title":"Product End Date"
          },

        },

      };

      $scope.form = [
     {
          "key": "userStartDate",
          "type": "datepicker",
          "format": "yyyy-mm-dd",
          "minDate": "2015-07-01",
          "maxDate": "2015-11-30",
          "rangeStartDateField": "userStartDate",
          "rangeEndDateField": "userEndDate",
          "rangeSelector": "true"
        }, {
          "key": "userEndDate",
          "type": "datepicker",
          "format": "yyyy-mm-dd",
          "minDate": "2015-07-01",
          "maxDate": "2015-11-30",
          "rangeStartDateField": "startDate",
          "rangeEndDateField": "userEndDate",
          "rangeSelector": "true"
        }, {
          "type": "submit",
          "style": "btn-info",
          "title": "OK"
        }
      ];
jamesdhakera commented 8 years ago

any updates on this ?