Showing character lengths next to fields

If there a way to show the number of characters a person has entered into a field alongside a field when a user enters it? I’m asking simply because I have a situation where I need to tell the user that when they write over a certain length the message might not be seen completely. My guess is no, and my use case is pretty unique but I thought I would ask anyway.

Hi, if you insert the below bit of javascript and replace the view_103 and field_240 with your view and field numbers it should work. In this instance the field is limited to 400 characters so it shows that too. If you don’t want this you should be able to remove the 2 instances of “/400” (or change them to what ever character limit you want).

/* Show character count */

$(document).on(“knack-view-render.view_103”, function(event, view, data) {

$( document ).ready(function() {

$(“.kn-form.kn-view.view_103 form #field_240”)

.after( “

0/400

” );

$(“.kn-form.kn-view.view_103 form #field_240”).on(‘input’,function(e){

var $input = $(this);

$input.siblings(‘.typed-chars’).text($input.val().length + “/400”);

});

});

});

Thanks, I will give that a try.

I also added this to the product map:

is it possible that the characters in your post have been autoformatted for " ’ ?

Hi

Yes this happens if you don’t put code inside a code block.

Craig

/* Show character count */

$(document).on("knack-view-render.view_775", function(event, view, data) {

$( document ).ready(function() {

$(".kn-form.kn-view.view_775 form #field_615")

.after( "

0/400
" );

$(".kn-form.kn-view.view_775 form #field_615").on('input',function(e){

var $input = $(this);

$input.siblings('.typed-chars').text($input.val().length + "/400");

});

});

});

Code above (adjusted for my fields).

Can you confirm that the field_name I should take from the corresponding field name in the data table? I have fished the view from Pages and the field from the data table, but I don’t get anything appearing on the page (for example /400, which I would expect by default even if other bits of the code were different or not?

Cheers.

Hi @GSH

I have simplified the function and fixed the formatting errors try this:

    $(document).on("knack-view-render.view_775", function(event, { key: viewId }) {
        const viewElement = $(`#${viewId}`);
        viewElement.find('#field_615').parent().append('<div class=typed-chars />' );

        viewElement.find('#field_615').on('input',function(e) {
            const $input = $(this);
            viewElement.find('.typed-chars').text($input.val().length + "/400");
        });
    });

Let me know how it goes

Craig

Heroic, works perfectly.

If you want to use it a lot we can make it into a reusable function.

Craig

Hi there.

I did something funky to this code (CHATGPT armrest) and added code that means when the character count is exceeded the character count is expanded.

$(document).on("knack-view-render.view_775", function(event, { key: viewId }) {
    const viewElement = $(`#${viewId}`);
    viewElement.find('#field_615').parent().append('<div class="typed-chars" />');

    viewElement.find('#field_615').on('input', function(e) {
        const $input = $(this);
        const charCount = $input.val().length;
        const $charCountElement = viewElement.find('.typed-chars');
        $charCountElement.text(charCount + "/400");

        if (charCount > 400) {
            $charCountElement.css('color', 'red');
        } else {
            $charCountElement.css('color', ''); // Reset to default color
        }
    });
});

I then got carried away to get exactly what I wanted.

This code will create a circle below the field, and it will slowly colour red. When the character count is reached by the user the circle will fill completely red.

You can additionally constrain the user with a validation rule. In my own use case the input restrictions are only a guide (people can put more if they want).

$(document).on("knack-view-render.view_775", function(event, { key: viewId }) {
    const characterLimit = 400;
    const viewElement = $(`#${viewId}`);

    const flexContainer = `
        <div class="input-circle-container" style="display: flex; flex-direction: column; align-items: flex-start;">
            <div class="input-wrapper" style="width: 100%;"></div>
            <div class="circle-text-wrapper" style="display: flex; align-items: center; margin-top: 10px;">
                <style>
                    .circle-progress {
                        width: 20px;
                        height: 20px;
                    }
                    .circle-progress circle {
                        fill: none;
                        stroke-width: 4;
                        stroke-dasharray: 100;
                    }
                    .char-count {
                        margin-left: 5px;
                        font-size: 14px;
                        color: black;
                    }
                </style>
                <svg class="circle-progress" viewBox="0 0 100 100">
                    <circle class="background-circle" r="40" cx="50" cy="50" stroke="#ccc" />
                    <circle class="progress-circle" r="40" cx="50" cy="50" stroke="#000" stroke-dashoffset="100" />
                </svg>
                <div class="char-count">
                    <span class="char-count-number">0</span>/${characterLimit}
                </div>
            </div>
        </div>
    `;

    const $field = viewElement.find('#field_615').parent();
    const $fieldClone = $field.clone();
    $field.replaceWith(flexContainer);
    viewElement.find('.input-wrapper').append($fieldClone);

    const $backgroundCircle = viewElement.find('.background-circle');
    const $progressCircle = viewElement.find('.progress-circle');
    const $charCountNumber = viewElement.find('.char-count-number');

    viewElement.find('#field_615').on('input', function(e) {
        const $input = $(this);
        const charCount = $input.val().length;
        const percentage = Math.min(charCount / characterLimit, 1) * 100;

        // Update circle color and progress
        const color = `rgba(255, 0, 0, ${percentage / 100})`;
        $progressCircle.css('stroke', color);
        $progressCircle.css('stroke-dashoffset', 100 - percentage);

        // Update character count text
        $charCountNumber.text(charCount);

        // Fill circle red if character count is 400 or more
        if (charCount >= characterLimit) {
            $backgroundCircle.css('fill', 'red');
        } else {
            $backgroundCircle.css('fill', 'none');
        }
    });
});

You will need to modify the script above and change this to the VIEW (as seen when looking at the page where the form is) and the specific field, that you want to have the character count appear below.

At the moment this is all set for 400 characters (update the const characterLimit = 400 value).

If there are any real programmers here they might confirm that this code looks alright, from my tests it does do what it is intended, but I don’t want to break others knack apps.

Cheers

Hi @GSH

Looks good. We will probably use this so I have coverted it into a reusable function and split off the CSS

Add this to CSS pane:

.input-circle-container {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.input-wrapper {
    width: 100%;
}

.circle-text-wrapper {
    display: flex;
    align-items: center;
    margin-top: 10px;
}

.circle-progress {
    width: 20px;
    height: 20px;
}

.circle-progress circle {
    fill: none;
    stroke-width: 4;
    stroke-dasharray: 100;
}

Add this to Javascript Window update views and fields for your app:

const fieldsWithCharacterLimit = [
        {
            viewKey: 'view_775',
            fieldKey: 'field_615',
            characterLimit: 400
        },
        {
            viewId: 'view_123',
            fieldId: 'field_456',
            characterLimit: 300
        },
        // Add more views as needed
    ];
    
    fieldsWithCharacterLimit.forEach(({ viewKey, fieldKey, characterLimit }) => {
        $(document).on(`knack-view-render.${viewKey}`, function(event, { key: viewId }) {
            setupCharacterLimit(viewId, fieldKey, characterLimit);
        });
    });
    
    function setupCharacterLimit(viewId, fieldId, characterLimit) {
        const viewElement = $(`#${viewId}`);
        
        const flexContainer = `
            <div class="input-circle-container">
                <div class="input-wrapper"></div>
                <div class="circle-text-wrapper">
                    <svg class="circle-progress" viewBox="0 0 100 100">
                        <circle class="background-circle" r="40" cx="50" cy="50" stroke="#ccc" />
                        <circle class="progress-circle" r="40" cx="50" cy="50" stroke="#000" stroke-dashoffset="100" />
                    </svg>
                    <div class="char-count">
                        <span class="char-count-number">0</span>/${characterLimit}
                    </div>
                </div>
            </div>
        `;
        
        const $field = viewElement.find(`#${fieldId}`).parent();
        const $fieldClone = $field.clone();
        $field.replaceWith(flexContainer);
        viewElement.find('.input-wrapper').append($fieldClone);
        
        const $backgroundCircle = viewElement.find('.background-circle');
        const $progressCircle = viewElement.find('.progress-circle');
        const $charCountNumber = viewElement.find('.char-count-number');
        
        viewElement.find(`#${fieldId}`).on('input', function () {
            const charCount = $(this).val().length;
            const percentage = Math.min(charCount / characterLimit, 1) * 100;
            
            // Update circle color and progress
            const color = `rgba(255, 0, 0, ${percentage / 100})`;
            $progressCircle.css({
                'stroke': color,
                'stroke-dashoffset': 100 - percentage
            });
            
            // Update character count text
            $charCountNumber.text(charCount);
            
            // Fill circle red if character count exceeds limit
            $backgroundCircle.css('fill', charCount >= characterLimit ? 'red' : 'none');
        });
    }```