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

HTML5 Time and Date picker #39

Open
chargrove opened this issue Mar 13, 2017 · 3 comments
Open

HTML5 Time and Date picker #39

chargrove opened this issue Mar 13, 2017 · 3 comments

Comments

@chargrove
Copy link

chargrove commented Mar 13, 2017

Enhancement

HTML5 native time and date pickers

I've created a HTML5 version of the time and date input object that could be a nice addition to the list of supported fields. This seems a lot easier than dealing with the Textalk datepicker that I see commonly used (and which doesn't support time input). Is there any possibility or interest in adding this in as an official type?

Below is the source, but the template directory would need to be changed slightly.

sfDateTime.js

angular.module('schemaForm').config(['schemaFormProvider',
    'schemaFormDecoratorsProvider', 'sfPathProvider', 'sfBuilderProvider',
    function(schemaFormProvider, schemaFormDecoratorsProvider, sfPathProvider, sfBuilderProvider) {

        function dateParser(value){
          if(value && value.toISOString){
            return value.toISOString();
          }else{
            return '';
          }
        }
        function dateFormatter(value) {
            if (angular.isUndefined(value) || value === null) {
              return value;
            }
            return new Date(value);
        }

        // First, we want this to be the default for a combination of schema parameters
        var time = function (name, schema, options) {
            if (schema.type == 'string' && schema.format == 'time') {
                // Initiate a form provider
                var f = schemaFormProvider.stdFormObj(name, schema, options);
                f.key = options.path;
                f.type = 'time';
                if(schema['min']){ f.min = schema['min']; }
                if(schema['max']){ f.min = schema['max']; }

                f.$parsers = [dateParser];
                f.$formatters = [dateFormatter];

                f.validationMessage = {
                    min: "Time must be after {{form.min | date:'shortTime':'UTC'}}",
                    max: "Time must be before {{form.max | date:'shortTime':'UTC'}}",
                };

                // Add it to the lookup dict (for internal use)
                options.lookup[sfPathProvider.stringify(options.path)] = f;
                return f;
            }
        };
        var date = function (name, schema, options) {
            if (schema.type == 'string' && schema.format == 'date') {
                // Initiate a form provider
                var f = schemaFormProvider.stdFormObj(name, schema, options);
                f.key = options.path;
                f.type = 'date';
                if(schema['min']){ f.min = schema['min']; }
                if(schema['max']){ f.min = schema['max']; }

                f.$parsers = [dateParser];
                f.$formatters = [dateFormatter];

                // Fix validation message to show existing constraint
                f.validationMessage = {
                    min: "Date must be after {{form.min | date:'mediumDate':'UTC'}}",
                    max: "Date must be before {{form.max | date:'mediumDate':'UTC'}}",
                };

                // Add it to the lookup dict (for internal use)
                options.lookup[sfPathProvider.stringify(options.path)] = f;

                return f;
            }
        };

        // Add our default to the defaults array
        schemaFormProvider.defaults.string.unshift(time);
        schemaFormProvider.defaults.string.unshift(date);

        schemaFormDecoratorsProvider.addMapping(
            'bootstrapDecorator',          // Name of the decorator you want to add to.
            'time',                    // Form type that should render this add-on
            '/schemaForm/sfDateTime/sfDateTime.html'    // Template name in $templateCache
        );
        schemaFormDecoratorsProvider.addMapping(
            'bootstrapDecorator',          // Name of the decorator you want to add to.
            'date',                    // Form type that should render this add-on
            'sfDateTime.html'    // Template name in $templateCache
        );
    }]);

sfDateTime.html

<div class="form-group has-feedback {{::form.htmlClass + ' ' + idClass}} sfDateTime" ng-class="{'has-error': form.disableErrorState !== true && hasError(), 'has-success': form.disableSuccessState !== true &&  hasSuccess()}" >
  <label class="control-label {{::form.labelHtmlClass}}" ng-class="{'sr-only': !showTitle()}" for="{{::fieldId(true, false)}}">{{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-if="form.type == 'time'"
            min="{{form.min}}"
            max="{{form.max}}"
            class="form-control {{::form.fieldHtmlClass}}"
            type="{{::form.type}}"
            ng-model="$$value$$"
            ng-model-options="{ timezone: 'UTC' }"
            id="{{::fieldId(true, false)}}"
            sf-changed="form"
            ng-attr-placeholder="{{::form.placeholder}}"
            ng-disabled="form.readonly"
            sf-field-model
            schema-validate="form"
            name="{{::fieldId(true, false)}}">
    </input>
    <input ng-if="form.type == 'date'"
            min="{{form.min | date:'yyyy-MM-dd':'UTC'}}"
            max="{{form.max | date:'yyyy-MM-dd':'UTC'}}"
            class="form-control {{::form.fieldHtmlClass}}"
            type="{{::form.type}}"
            ng-model="$$value$$"
            id="{{::fieldId(true, false)}}"
            sf-changed="form"
            ng-attr-placeholder="{{::form.placeholder}}"
            ng-disabled="form.readonly"
            sf-field-model
            schema-validate="form"
            name="{{::fieldId(true, false)}}">
    </input>
    <span ng-if="form.fieldAddonRight"
          class="input-group-addon"
          ng-bind-html="form.fieldAddonRight"></span>
  </div>

  <span ng-if="form.feedback !== false"
        class="form-control-feedback"
        ng-class="evalInScope(form.feedback) || {'glyphicon': true, 'glyphicon-ok': form.disableSuccessState !== true && hasSuccess(), 'glyphicon-remove': form.disableErrorState !== true && hasError() }"
        aria-hidden="true"></span>

  <span ng-if="hasError() || hasSuccess()"
        id="{{::fieldId(true, true) + '-status'}}"
        class="sr-only">{{ hasSuccess() ? '(success)' : '(error)' }}</span>

  <span class="help-block" sf-message="form.description"></span>
</div>

@json-schema-form/angular-schema-form-bootstrap-lead

@Anthropic
Copy link
Member

Anthropic commented Mar 13, 2017

@chargrove yes there is interest, I've been wanting to do it for a while, thanks for sharing, how well does it handle browser fallback like in Firefox which still doesn't appear to support them?

@chargrove
Copy link
Author

@Anthropic You'll get a text entry with success and error validation in Firefox but it accepts the date and time using the correct format. Accepted date is input as "2017-12-31" and time is "18:13" or "18:13:44". This is on version Firefox 52, but the scheduled release of Firefox 54 in June has flags to enable these new input types.

I'm personally planning to use a polyfill for the time being but I don't have a specific one in mind yet.

@omaigad
Copy link

omaigad commented Feb 8, 2018

@chargrove could you guide me a bit, how to configure for it to work? Im having trouble with Textalk datepicker addon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants