4

I have two javascript codes required by external libraries (jQuery X-editable and FineUploader) where I require my context variables. Therefore I cannot use an external js for this codes.

This is what I'm currently doing on my templates:

some_important_template.html

{% include "includes/editable_fields.html" %}
{% include "includes/fine_upload_template.html" %}

fine_upload_template.html

<script type="text/template" id="qq-template">

    <div class="qq-uploader-selector qq-uploader" qq-drop-area-text="Drop files here">
        <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
            <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
        </div>
        <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
            <span class="qq-upload-drop-area-text-selector"></span>
        </div>
        <div class="qq-upload-button-selector btn btn-info">

            <div>Upload a file</div>
        </div>
        <span class="qq-drop-processing-selector qq-drop-processing">
            <span>Processing dropped files...</span>
            <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
        </span>
        <ul class="qq-upload-list-selector qq-upload-list" aria-live="polite" aria-relevant="additions removals">
            <li>
                <div class="qq-progress-bar-container-selector">
                    <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
                </div>
                <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                <img class="qq-thumbnail-selector" qq-max-size="100" qq-server-scale>
                <span class="qq-upload-file-selector qq-upload-file"></span>
                <span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
                <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
                <span class="qq-upload-size-selector qq-upload-size"></span>
                <button type="button" class="qq-btn qq-upload-cancel-selector btn btn-danger">Cancel</button>
                <button type="button" class="qq-btn qq-upload-retry-selector btn btn-info">Retry</button>
                <button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">Delete</button>
                <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
            </li>
        </ul>

        <dialog class="qq-alert-dialog-selector">
            <div class="qq-dialog-message-selector"></div>
            <div class="qq-dialog-buttons">
                <button type="button" class="qq-cancel-button-selector">Close</button>
            </div>
        </dialog>

        <dialog class="qq-confirm-dialog-selector">
            <div class="qq-dialog-message-selector"></div>
            <div class="qq-dialog-buttons">
                <button type="button" class="qq-cancel-button-selector">No</button>
                <button type="button" class="qq-ok-button-selector">Yes</button>
            </div>
        </dialog>

        <dialog class="qq-prompt-dialog-selector">
            <div class="qq-dialog-message-selector"></div>
            <input type="text">
            <div class="qq-dialog-buttons">
                <button type="button" class="qq-cancel-button-selector btn btn-danger">Cancel</button>
                <button type="button" class="qq-ok-button-selector btn btn-info">Ok</button>
            </div>
        </dialog>
    </div>

</script>

<script>

    var uploader = new qq.FineUploader({
        debug: true,
        element: document.getElementById('fine-uploader'),
        request: {
            endpoint: '{% url "registrations:ajax_upload" registration.pk %}',
            params: {
                'csrfmiddlewaretoken': '{{ csrf_token }}'
            }
        },
        deleteFile: {
            enabled: false,
            endpoint: '/uploads'
        },
        retry: {
           enableAuto: false
        }
    });

</script>

editable_fields.html

<script>

    //turn to inline mode
    $.fn.editable.defaults.mode = 'inline';

    {% if registration.emergency_contact %} 

    $('#contact_first_name').editable({
        name: 'first_name',
        pk: {{registration.emergency_contact.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    $('#contact_last_name').editable({
        name: 'last_name',
        pk: {{registration.emergency_contact.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    {% endif %} 

    {% for parent in registration.tutors.all %}

    $('#parent_first_name_{{ forloop.counter }}').editable({
        name: 'first_name',
        pk: {{parent.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    $('#parent_last_name_{{ forloop.counter }}').editable({
        name: 'last_name',
        pk: {{parent.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    {% for phone in parent.profile.phone_set.all %}

    $('#parent_phone_{{phone.type}}_{{forloop.parentloop.counter}}').editable({
        name: 'number',
        pk: {{phone.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Phone'}"
    });

    {% endfor %}

    {% endfor %}

    {% for phone in registration.emergency_contact.profile.phone_set.all %}

    $('#contact_phone_{{phone.type}}').editable({
        name: 'number',
        pk: {{phone.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Phone'}"
    });

    {% endfor %}

    {% with registration.costumer as costumer %}

    $('#email').editable({
        pk: {{costumer.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    $('#first_name').editable({
        pk: {{costumer.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    $('#last_name').editable({
        pk: {{costumer.id}},
        url: '{% url "profiles:field_inline" %}',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'User'}"
    });

    $('#birth_date').editable({
        pk: {{costumer.profile.id}},
        url: '{% url "profiles:field_inline" %}',
        type: 'combodate',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Profile'}",
    });


    {% with costumer.profile.address as address %}

    $('#address1').editable({
        pk: {{address.id}},
        url: '{% url "profiles:field_inline" %}',
        title: 'Enter Address 1',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Address'}"
    });

    $('#address2').editable({
        pk: {{address.id}},
        url: '{% url "profiles:field_inline" %}',
        title: 'Enter Address 1',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Address'}"
    });

    $('#zip_code').editable({
        pk: {{address.id}},
        url: '{% url "profiles:field_inline" %}',
        title: 'Enter Zip Code',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Address'}"
    });

    $('#city').editable({
        pk: {{address.id}},
        url: '{% url "profiles:field_inline" %}',
        title: 'Enter City',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Address'}"
    });

    $('#estate').editable({
        pk: {{address.id}},
        url: '{% url "profiles:field_inline" %}',
        title: 'Enter State',
        params: "{csrfmiddlewaretoken:'{{csrf_token}}', model: 'Address'}"
    });

    {% endwith %}

    {% endwith %}

</script>

This works but I'm not sure if it follows Django Best Practices.

1 Answer 1

7

It is not a good idea to combine javascript and Django template code.

Instead, write a wrapper function around your javascript that takes all your template variables. I.e. create a javascript file containing:

var wrapper = function (args) {
    //turn to inline mode
    $.fn.editable.defaults.mode = 'inline';

    if (args.registration_emergency_contact) {

        $('#contact_first_name').editable({
            name: 'first_name',
            pk: args.registration_emergency_contact_id,
            url: args.profiles_field_inline,
            params: "{csrfmiddlewaretoken:'" + args.csrf_token + "', model: 'User'}"
        });
     // ...
}

in your view, create the args as a json value:

def myview(...):
    args = {
         'registration_emergency_contact': bool(registration.emergency_contact),
         'registration_emergency_contact_id': registration.emergency_contact.id,
         'profiles_field_inline': reverse(...),
         // ...
    }
    return ... , Context({'args': json.dumps(args)})..

Then in your template file, include the javascript file through a script tag and call the function:

wrapper({{ args|safe }});

This way your javascript contains just javascript, and you can use all available javascript tools to lint/minifiy/transpile/etc., and serve it as a static resource.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! This is what I was looking for. I knew there was an "elegant" way to do this ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.