Question

Looking at implementing column or list validation for a date field to stop them from entering past dates

The validation should do the following

  1. Validate only there is a value in the column
  2. Validate only if this particular field has changed. E.g. a user entered today's date and saved the item. They come back and change some other fields but not the date field in question they should be allowed to save

However if they change the date field it should validate that the date is not a past date

Était-ce utile?

La solution

This is possible using JSLink/CSR client-side validation. That is, if you are on a version of SharePoint that still has JSLink/CSR available.

From my understanding, SP Online modern experience does not use the JSLink/CSR system from older versions. I am unsure if SP Online classic experience still has that (can someone who knows confirm in a comment?). SP 2013 / 2016 on-prem definitely has JSLink/CSR available to tap into (and I believe 2019 as well? Again, not sure on that one...)

Here's some example code (tested on 2013):

var MyNamespace = MyNamespace || {};

MyNamespace.PreviousFieldValue = null;

MyNamespace.MyFieldValidator = function myFieldValidator () {

    MyNamespace.MyFieldValidator.prototype.Validate = function (fieldValue) {
        var isError = false;
        var errorMessage = '';

        // only validate if the field has a value
        if (fieldValue) {

            // assume that we do need to check if it is a past date
            var shouldCheckIfPastDate = true;
            var enteredDate = new Date(fieldValue);

            // if there was a previous value, check to see if it has changed
            if (MyNamespace.PreviousFieldValue !== null) {

                var previousDate = new Date(MyNamespace.PreviousFieldValue);

                // if the date has not changed, don't check if it's a past date
                // Date object can't do equality comparison natively, so we have to use getTime()
                if (enteredDate.getTime() === previousDate.getTime()) {
                    shouldCheckIfPastDate = false;
                }
            }

            if (shouldCheckIfPastDate) {

                // get todays date and zero out the time so we are only comparing the date
                var today = new Date();
                today.setHours(0, 0, 0, 0);

                // Date object can handle greater than/less than comparison natively
                if (enteredDate < today) {
                    isError = true;
                    errorMessage = 'You cannot enter a past date.';
                }
            }
        }

        return new SPClientForms.ClientValidation.ValidationResult(isError, errorMessage);
    }
}

MyNamespace.MyFieldFieldOverride = {
    edit: function edit (ctx) {

        // if it's not blank, store the current value of the field to check against later
        if (ctx.CurrentFieldValue) {
            MyNamespace.PreviousFieldValue = ctx.CurrentFieldValue;
        }

        // get the form context and create a new validator set
        var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
        var fieldValidators = new SPClientForms.ClientValidation.ValidatorSet();

        // if the field has been marked as required, register the default required field validator
        if (formCtx.fieldSchema.Required) {
            fieldValidators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
        }

        // register our custom validator
        fieldValidators.RegisterValidator(new MyNamespace.MyFieldValidator());

        // add the error callback and register the validator set with the form context
        formCtx.registerValidationErrorCallback(formCtx.fieldName, MyNamespace.MyFieldFieldOverride.onError);
        formCtx.registerClientValidator(formCtx.fieldName, fieldValidators);

        // render the default form control for a date column
        var returnHtml = SPFieldDateTime_Edit(ctx);

        // add a spot for our custom error message
        returnHtml += "<span id='MyFieldCustomError' class='ms-formvalidation ms-csrformvalidation'></span>";
        return returnHtml;
    },
    onError: function onError (error) {
        document.getElementById('MyFieldCustomError').innerHTML = "<span role='alert'>" + error.errorMessage + "</span>";
    },
    render: function render () {
        SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
            Templates: {
                Fields: {
                    YourDateField: {
                        'NewForm': MyNamespace.MyFieldFieldOverride.edit,
                        'EditForm': MyNamespace.MyFieldFieldOverride.edit
                    }
                }
            }
        });
    }
}

// handle MDS-enabled or MDS-disabled situations
RegisterModuleInit(SPClientRenderer.ReplaceUrlTokens('~site/path/to/MyFieldValidator.js'), MyNamespace.MyFieldFieldOverride.render);
MyNamespace.MyFieldFieldOverride.render();

Autres conseils

As far as I know, it's impossible to validate only if particular field changes. It's by default that column validation would validate the data in this column when items are saved to this list.

I could achieve your first requirements using this formula:

=IF(ISBLANK([Date]),TRUE,[Date]>=TODAY())
Licencié sous: CC-BY-SA avec attribution
Non affilié à sharepoint.stackexchange
scroll top