JavaScript UI Libraries & Blazor Components Suite – Smart UI Forums Text Boxes & Inputs password input field complexity validation and strength example

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #103994
    Patrick Hume
    Participant

    hi,

    encase anyone else ever need an answer to only enable form input if password strength if met

    Index

        <script src="js/complexityCheck.js?version=1.0.05"></script>
        <script src="_content/Smart.Blazor/js/smart.blazor.js"></script>
        <script src="_content/Smart.Blazor/js/smart.elements.js"></script>
    

    the input password feild

    <label for="password">Password</label>
    <template id="tooltip-password">
    	<span style="font-weight:bold; color:red">{{value}}</span>
    </template>
    <PasswordTextBox Required Class="form-control" id="password" TooltipTemplate="tooltip-password" Placeholder="Enter password" @bind-Value="user.Password" ShowPasswordIcon ShowPasswordStrength Name="password"></PasswordTextBox>
    <ValidationMessage For="@(() => user.Password)" />
    

    the form submit button

    <button type="submit" id="submit" disabled="@(!isComplexityValid)" class="btn btn-primary">
    	<span class="sr-only">Register</span>
    </button>
    

    using customStrength

    script: js/complexityCheck.js

    const symbols = /['<>@!#$%^&*()_+\]\[\{}?:;|'"\\,.\/~`\-=']+/;
    const numerical = /.*[0-9].*/;
    const upperCase = /.*[A-Z].*/;
    const lowerCase = /.*[a-z].*/;
    
    (function (global) {
        global.customStrength = function (dotNetObject) {
            setTimeout(function () {
                document.querySelector("smart-password-text-box").passwordStrength = function (password, allowedSymbols) {
                    const passwordLength = password.length;
                    let message = null;
                    // debugger;
                    if (passwordLength < 3) {
                        message = 'short';
                    } else if (passwordLength < 7) {
                        message = 'weak';
                    } else if (!new RegExp(symbols).exec(password)) {
                        message = 'complexity week - missing at least 1 symbol, ' + allowedSymbols;
                    } else if (!new RegExp(numerical).exec(password)) {
                        message = 'complexity week - missing at least 1 numerical value, 0 - 9';
                    } else if (!new RegExp(upperCase).exec(password)) {
                        message = 'complexity week - missing at least 1 upper case character;
                    } else if (!new RegExp(lowerCase).exec(password)) {
                        message = 'complexity week - missing at least 1 lower case character';
                    }
                    if (message) {
                        dotNetObject.invokeMethodAsync('CallbackComplexityCheck', false)
                        return message;
                    }
                    dotNetObject.invokeMethodAsync('CallbackComplexityCheck', true)
                    return 'strong';
                }
            }, 0);
            return true;
        }
    })(window);
    
     protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await JSRuntime.InvokeAsync<bool>("customStrength", DotNetObjectReference.Create(this));
            }
            await base.OnAfterRenderAsync(firstRender);
        }
    

    the @code block

        private bool isComplexityValid = false;
        [JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
        public void CallbackComplexityCheck(bool valid)
        {
            if (isComplexityValid != valid)
            {
                isComplexityValid = valid;
                StateHasChanged();
            }
        }
    

    the css to change input fields outline colour based on strength

    smart-password-text-box {
        background-clip: content-box;
        box-sizing: border-box;
    }
    
    smart-password-text-box[show-password-strength] .smart-password-short  {
          border: red solid 3px;
    }
    
    smart-password-text-box[show-password-strength] .smart-password-weak  {
        border: orange solid 3px;
    }
    
    smart-password-text-box[show-password-strength] .smart-password-far  {
        border: yellow solid 3px;
    }
    
    smart-password-text-box[show-password-strength] .smart-password-good {
        border: deepskyblue solid 3px;
    }
    
    smart-password-text-box[show-password-strength] .smart-password-strong  {
        border: green solid 3px;
    }
    
    smart-password-text-box smart-tooltip .smart-tooltip-content {
        border-radius: 3px;
    }
    

    I hope this helps someone one day the effort of working this out themselves like I had to

    • This topic was modified 1 year, 5 months ago by Patrick Hume. Reason: missing info
    • This topic was modified 1 year, 5 months ago by Patrick Hume. Reason: add image example
    • This topic was modified 1 year, 5 months ago by Patrick Hume.
    • This topic was modified 1 year, 5 months ago by Patrick Hume.
    • This topic was modified 1 year, 5 months ago by Patrick Hume.
    • This topic was modified 1 year, 5 months ago by Patrick Hume.
    • This topic was modified 1 year, 5 months ago by Patrick Hume.
    #104002
    Patrick Hume
    Participant

    seams i got the cass wrong to make that work poperly –

    smart-password-text-box {
        background-clip: content-box;
        box-sizing: border-box;
    }
    
        smart-password-text-box[show-password-strength] {
            border: red solid 3px;
        }
    
            smart-password-text-box[show-password-strength] .smart-password-short {
                border: red solid 3px;
            }
    
            smart-password-text-box[show-password-strength] .smart-password-weak {
                border: #C27BA0 solid 3px;
            }
    
            smart-password-text-box[show-password-strength] .smart-password-far {
                border: orange solid 3px;
            }
    
            smart-password-text-box[show-password-strength] .smart-password-better {
                border: yellow solid 3px;
            }
    
            smart-password-text-box[show-password-strength] .smart-password-good {
                border: deepskyblue solid 3px;
            }
    
            smart-password-text-box[show-password-strength] .smart-password-strong {
                border: green solid 3px;
            }
    
        smart-password-text-box smart-tooltip .smart-tooltip-content {
            border-radius: 3px;
        }
    

    then the js file needs to be

    (function (global) {
        global.customStrength = function (dotNetObject) {
            let allowedSymbols = '<>@!#$%^&*()_+[]{}?:;|\'"\\,./~`-=';
            const passwordTextBox = document.querySelector("smart-password-text-box").messages = {
                'en': {
                    'passwordStrength': 'Password strength',
                    'short': 'Short',
                    'weak': 'complexity Week - missing art least 1 symbol, ' + allowedSymbols,
                    'far': 'complexity Fair - missing at least 1 numerical value, 0 - 9',
                    'better': 'complexity Better - missing at least 1 upper case characture, A- Z',
                    'good': 'complexity Good - missing at least 1 lower case characture, a - z',
                    'strong': 'Strong =)',
                    'showPassword': 'Show password'
                }
            };
            setTimeout(function () {
                passwordTextBox.passwordStrength = function (password, allowedSymbols) {
                    const passwordLength = password.length;
                    let message = null;
                    // debugger;
                    if (passwordLength < 7) {
                        message = 'short';
                    } else if (!new RegExp(symbols).exec(password)) {
                        message = 'weak';
                    } else if (!new RegExp(numerical).exec(password)) {
                        message = 'far';
                    } else if (!new RegExp(upperCase).exec(password)) {
                        message = 'better';
                    } else if (!new RegExp(lowerCase).exec(password)) {
                        message = 'good';
                    }
                    if (message) {
                        dotNetObject.invokeMethodAsync('CallbackComplexityCheck', false)
                        return message;
                    }
                    dotNetObject.invokeMethodAsync('CallbackComplexityCheck', true)
                    return 'strong';
                }
            }, 0);
            return true;
        }
    })(window);
    

    This will allow one to customise the message in the tooltip template whilst still applying styling the the input

    #104014
    Patrick Hume
    Participant

    I thought I would update this with a complete solution with a few weeks for a better UXI experience.

    This ensures the password field is not red on page load, then if the user types in it and then deletes its contents it will then appear red to indicate that it is required the same behaviour as other required fields, also fix the styling so that the password *’s are indented and appears the same as the default blazor form-control class, also adds the field highlight when password field is selected. The submit button is only enabled when the complexity is ‘Strong’, and when the submit is clicked it displays a spinning bootstrap icon on the submit button and disables it to prevent re-clicking. Assumes the submit action will call a service that returns a result object or response, this can then be used to display the smart blazor badge to give feedback on the Ui to the user.

    I hope this helps someone one day

    complexityCheck.js

    const symbols = /['<>@!#$%^&*()_+\]\[\{}?:;|'"\\,.\/~`\-=']+/;
    const numerical = /.*[0-9].*/;
    const upperCase = /.*[A-Z].*/;
    const lowerCase = /.*[a-z].*/;
    
    (function (global) {
        global.customStrength = function (dotNetObject) {
            const allowedSymbols = '<>@!#$%^&*()_+[]{}?:;|\'"\\,./~`-=';
            const passwordField = document.querySelectorAll("smart-password-text-box")[0];
            const passwordConfirm = document.querySelectorAll("smart-password-text-box")[1];
            // Remove the red border on the page load
            passwordConfirm.style.border = '';
            // Set the border to red if the field is cleared and outline green if the field has a value
            // Assumes that any value will be the same is the same as the first password field & relies on 
            // MVC data attestations [Compare( to enforce this at time of form submit
            passwordConfirm.addEventListener('change', function (event) {
                if (event.detail.value) {
                    this.style.border = "#26b050 solid 1.5px";
                } else {
                    this.style.border = "red solid 3px";
                }
            });
            passwordField.messages = {
                'en': {
                    'passwordStrength': 'Password strength',
                    'short': 'Short',
                    'init': 'init',
                    'weak': 'complexity Week - missing at least 1 symbol, ' + allowedSymbols,
                    'far': 'complexity Fair - missing at least 1 numerical value, 0 - 9',
                    'better': 'complexity Better - missing at least 1 upper case characture, A- Z',
                    'good': 'complexity Good - missing at least 1 lower case characture, a - z',
                    'strong': 'Strong =)',
                    'showPassword': 'Show password'
                }
            };
            // indent password text to match the styling of other from controls 
            passwordField.style.textIndent = '0.7rem'
            setTimeout(function () {
                passwordField.passwordStrength = function (password, allowableSymbols) {
                    const passwordLength = password.length;
                    let message = null;
                    //debugger;                
                    passwordField.children[0].classList.remove("smart-password-better");
                    if (passwordLength < 7) {
                        message = 'short';
                    } else if (!new RegExp(symbols).exec(password)) {
                        message = 'weak';
                    } else if (!new RegExp(numerical).exec(password)) {
                        message = 'far';
                    } else if (!new RegExp(upperCase).exec(password)) {
                        message = 'better';
                    } else if (!new RegExp(lowerCase).exec(password)) {
                        message = 'good';
                    }
                    //console.log(message);
                    if (message) {
                        dotNetObject.invokeMethodAsync('CallbackComplexityCheck', false)
                        return message;
                    }
                    dotNetObject.invokeMethodAsync('CallbackComplexityCheck', true)
                    return 'strong';
                }
            }, 0);
            // remove red border on page load, the timer allows js to wire up before removing the class that's added by the js
            setTimeout(function () {
                passwordField.children[0].classList.remove("smart-password-short");
            }, 10);
            return true;
        }
    })(window);
    

    index.html

        
    <script src="js/complexityCheck.js"></script>
        <script src="_content/Smart.Blazor/js/smart.blazor.js"></script>
        <script src="_content/Smart.Blazor/js/smart.elements.js"></script>
    

    razor page example

    <EditForm Model="SomeModel" OnValidSubmit="ProcessMyForm">
            <DataAnnotationsValidator />
            <div class="mb-3">
                <label for="password">New Password</label>
                <template id="tooltip-password">
                    <span>{{value}}</span>
                </template>
                <PasswordTextBox Required id="password" TooltipArrow TooltipTemplate="tooltip-password" Placeholder="Enter password" @bind-Value="SomeModel.Password" ShowPasswordIcon ShowPasswordStrength Name="password"></PasswordTextBox>
                <ValidationMessage For="@(() => SomeModel.Password)" />
            </div>
            <div class="mb-3">
                <label for="confirmPassword">Confirm New Password</label>
                <PasswordTextBox Class="form-control" Required Placeholder="Confirm password" @bind-Value="SomeModel.ConfirmPassword" ShowPasswordIcon Name="confirmPassword"></PasswordTextBox>
                <ValidationMessage For="@(() => SomeModel.ConfirmPassword)" />
            </div>
            <button type="submit" id="submit" disabled="@(!isComplexityValid || loading)" class="btn btn-primary">
                @if (loading)
                {
                    <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                    <span class="sr-only">Processing...</span>
                }
                else
                {
                    <span class="sr-only">Submit</span>
                }
            </button>
        </EditForm>
    
    <div>
        <span class="@($"smart-badge {messageCssClass}")">@message</span>
    </div>
    <br />
    @code {
    
        private string message = string.Empty;
        private bool isComplexityValid = false;
        private bool loading = false;
        private string messageCssClass = string.Empty;
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await JSRuntime.InvokeAsync<bool>("customStrength", DotNetObjectReference.Create(this));
            }
            await base.OnAfterRenderAsync(firstRender);
        }
    
        private async Task ProcessMyForm()
        {
            loading = true;
            var result = await // call some service here !
    
            if (result.Success)
            {
                messageCssClass = "smart-badge-success";
      
            }
            else
            {
                messageCssClass = "smart-badge-danger";
            }
            loading = false;
            message = result.Message;
            StateHasChanged();
        }
    
        [JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
        public void CallbackComplexityCheck(bool valid)
        {
            if (isComplexityValid != valid)
            {
                isComplexityValid = valid;
                StateHasChanged();
            }
        }
    
    • This reply was modified 1 year, 4 months ago by Patrick Hume.
    • This reply was modified 1 year, 4 months ago by Patrick Hume.
Viewing 3 posts - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.