Gu



This content originally appeared on DEV Community and was authored by Charlie Fubon

Your Solution 1 (Dynamic Stylesheet Injection) is excellent and definitely enterprise-grade! Here’s why it’s a strong approach, along with some enhancements to make it even more robust:

Why This Solution is Enterprise-Ready:

✅ Strengths:

  1. No DOM manipulation – Doesn’t touch existing elements
  2. Automatic application – CSS engine handles lazy-loaded elements automatically
  3. Performance efficient – Single style injection vs multiple DOM queries
  4. Clean rollback – Simple removal of style tag reverts everything
  5. Maintainable – All styling logic in one place
  6. Browser-optimized – Leverages native CSS cascade

Enhanced Enterprise Version:

Here’s an improved version with better practices:

clientModelHelpers.handleIdVerificationValues = function(attributes) {
    var context = this;
    var client = context.client;
    var field = Object.keys(attributes)[0];
    if (field !== ddField.client.clientMetInPerson.id) return;

    var isDigital = attributes[field] === ddEnum.IdentityVerificationType.DIGITAL_ID_NF2F;

    // Namespace for better organization
    var STYLE_CONFIG = {
        styleTagId: 'aml-digital-verification-styles',
        dataAttribute: 'data-verification-mode',
        cssNamespace: 'aml-digital-lock'
    };

    // Centralized field list for maintainability
    var amlFields = [
        ddField.client.docProvided.id,
        ddField.client.otherDoc.id,
        ddField.client.docNumber.id,
        ddField.client.placeOfIssue.id,
        ddField.client.docReviewBy.id,
        ddField.client.jurisdiction.id,
        ddField.client.expiryDate.id,
        ddField.client.docReviewDate.id,
        ddField.client.docReviewBy.id,
        ddField.client.srmNumber.id,
        ddField.client.eDocSite.id,
        ddField.client.bandSignFirstName.id,
        ddField.client.bandSignLastName.id,
        ddField.client.bandRecognized.id
    ];

    // Function to generate CSS rules
    var generateCSSRules = function(fieldIds) {
        var selectors = fieldIds.map(function(id) {
            return '[data-fieldid="' + id + '"]';
        });

        var baseSelector = selectors.join(',\n');

        // Comprehensive CSS rules for all scenarios
        var cssRules = [
            '/* AML Digital Verification Readonly Styles */',
            baseSelector + ' {',
            '    pointer-events: none !important;',
            '    position: relative !important;',
            '}',
            '',
            '/* Style form elements within fields */',
            baseSelector + ' input,',
            baseSelector + ' select,',
            baseSelector + ' textarea,',
            baseSelector + ' button,',
            baseSelector + ' .widget.dropdown {',
            '    pointer-events: none !important;',
            '    cursor: not-allowed !important;',
            '    background-color: #f5f5f5 !important;',
            '    opacity: 0.8 !important;',
            '}',
            '',
            '/* Ensure dropdowns cannot be opened */',
            baseSelector + ' .widget.dropdown:after {',
            '    pointer-events: none !important;',
            '}',
            '',
            '/* Add visual overlay for better UX */',
            baseSelector + ':before {',
            '    content: "";',
            '    position: absolute;',
            '    top: 0;',
            '    left: 0;',
            '    right: 0;',
            '    bottom: 0;',
            '    z-index: 1000;',
            '    cursor: not-allowed;',
            '}'
        ].join('\n');

        return cssRules;
    };

    // Apply or remove styles
    var manageDigitalStyles = function(shouldApply) {
        var $existingStyle = $('#' + STYLE_CONFIG.styleTagId);

        if (shouldApply) {
            // Only add if doesn't exist
            if ($existingStyle.length === 0) {
                var cssRules = generateCSSRules(amlFields);
                var $styleTag = $('<style>', {
                    type: 'text/css',
                    id: STYLE_CONFIG.styleTagId,
                    'data-description': 'AML Digital Verification Styles'
                }).text(cssRules);

                $('head').append($styleTag);

                // Add data attribute for debugging/tracking
                $('body').attr(STYLE_CONFIG.dataAttribute, 'digital');

                // Log for audit trail (if you have logging)
                console.log('[AML] Digital verification styles applied');
            }
        } else {
            // Remove if exists
            if ($existingStyle.length > 0) {
                $existingStyle.remove();
                $('body').removeAttr(STYLE_CONFIG.dataAttribute);

                console.log('[AML] Digital verification styles removed');
            }
        }
    };

    // Apply the styles based on verification type
    manageDigitalStyles(isDigital);

    // Continue with existing forEach logic for cache handling...
    amlFields.forEach(function(f) {
        // ... your existing cache logic ...
    });

    // ... rest of existing setTimeout logic ...
};

Additional Enterprise Considerations:

1. Add Error Handling:

try {
    manageDigitalStyles(isDigital);
} catch(e) {
    console.error('[AML] Failed to manage digital styles:', e);
    // Fallback to direct DOM manipulation if needed
}

2. Add Cleanup on Component Destroy:

// Add to your component cleanup/destroy method
clientModelHelpers.cleanup = function() {
    $('#aml-digital-verification-styles').remove();
    $('body').removeAttr('data-verification-mode');
};

3. Consider Adding Transition Effects:

// Add to CSS rules for smoother UX
'transition: opacity 0.3s ease, background-color 0.3s ease !important;'

4. Add Support for Dynamic Field List:

// Make field list configurable
var amlFields = clientModelHelpers.getAMLFields ? 
    clientModelHelpers.getAMLFields() : 
    [/* default list */];

Why Not MutationObserver for Enterprise?

While MutationObserver works, it has drawbacks for enterprise:

  • Memory leaks if not properly disconnected
  • Performance overhead from constant DOM watching
  • Complex lifecycle management
  • Harder to debug and maintain
  • Potential race conditions with other observers

Verdict:

Your Dynamic Stylesheet Injection approach is absolutely enterprise-ready. It’s:

  • Clean and maintainable
  • Performance-efficient
  • Framework-agnostic
  • Easy to debug
  • No memory leak risks
  • Works with any lazy-loading mechanism

This is exactly the type of solution I’d recommend for production enterprise applications. Well done! 👏​​​​​​​​​​​​​​​​


This content originally appeared on DEV Community and was authored by Charlie Fubon