[Answered ]-Set dynamic values from a dictionary for select values inside a Django template using Javascript or other method

1👍

To achieve what you want without refreshing the page it is necessary to use AJAX.

Starting with your template. Since you are going to populate dynamically based on choices, it is not necessary to have one box for each QuerySet. You can clear and repopulate them using JS.

templates.html:

<body>
    <div class="col-md-3 mx-md-5">
        <h2 class="h5 nm-text-color fw-bold mb-4">Choose usage or model:</h2>
        <select required aria-label="Select usage or model"
                id="usage_model_select" class="form-select" onchange="populate_lists()">
            <option value="" selected>----</option>
            <option value="usage">Usage</option>
            <option value="model">Model</option>
        </select>
    </div>
    
    {#  usage or model select div #}
    <div class="col-md-3 mx-md-5">
        {#  usage select div #}
        <div class="usage visually-hidden" id="usage_div">
            <h2 class="h5 nm-text-color fw-bold mb-4">Select options:</h2>
            <select required aria-label="Select usage" class="form-select"
                    name="usage_select" onchange="populate_lists()" id="select_options">
                <option value="" selected>----</option>
            </select>
        </div>
    </div>
    
    {# select sub_usage or pump_type div #}
    <div class="col-md-3 mx-md-5">
        {#  sub_usage select div #}
        <div class="sub_usage visually-hidden" id="sub_usage_div">
            <h2 class="h5 nm-text-color fw-bold mb-4">Sub selection:</h2>
            <select required aria-label="Select sub_usage" class="form-select" id="sub_usage_select" name="sub_usage_select">
                <option selected>All sub-selections</option>
            </select>
        </div>
    </div>

    <div>
        <input type="submit" value="Next" id="submit" class="btn btn-primary">
    </div>
</body>

templates.html <script>: (CSRF with AJAX | Get Select element | Populate Select element | Clear Select element)

<script>
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    // Clear SelectionBoxes
    function removeOptions(selectElement, initial) {
        var i, L = selectElement.options.length - 1;
        for(i = L; i >= 0; i--) {
            selectElement.remove(i);
        }
        var opt = document.createElement('option');
        opt.value = "";
        opt.innerHTML = initial;
        selectElement.appendChild(opt);
    }

    function populate_lists() {
        const url = '/solution/ajax/';
        const csrftoken = getCookie('csrftoken');

        var e = document.getElementById("usage_model_select");
        var selectedOption = e.value;
        if (selectedOption == "" ) {
            removeOptions(document.getElementById("select_options"), "----");
            removeOptions(document.getElementById("sub_usage_select"), "All sub-usages from this usage");
            return
        }

        var e = document.getElementById("select_options");
        var option = e.value;
        if (option == "" ) {
            option = null
        }
        
        // Send AJAX Request
        fetch(url, {
            method: 'POST',
            headers: {
                'X-CSRFToken': csrftoken,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                "select": selectedOption,
                "option": option,
            }),
        })
        .then((response) => response.json())
        .then((data) => {
            var select = document.getElementById("select_options");
            removeOptions(select, "----");
            var selected_usage_name = null

            for (var i = 0; i<=data.select.length-1; i++){
                var opt = document.createElement('option');
                opt.value = data.select[i]['id'];
                opt.innerHTML = data.select[i]['name'];
                
                if (data.select[i]['id'] == data.selected_option) {
                    selected_usage_name = data.select[i]['name'];
                    opt.selected = true
                }
                select.appendChild(opt);
            }

            if (data.sub_select != null) {
                var select = document.getElementById("sub_usage_select");
                removeOptions(select, `All sub-usages from ${selectedOption} ${selected_usage_name}`);

                for (var i = 0; i<=data.sub_select.length-1; i++){
                    var opt = document.createElement('option');
                    opt.value = data.sub_select[i]['id'];
                    opt.innerHTML = data.sub_select[i]['name'];
                    select.appendChild(opt);
                }
                console.log(data.sub_select)
            }
            
        })
        .catch((error) => {
            console.error('Error:', error);
        });
    }
</script>

views.py:

def solution_ajax(request):
    data = json.loads(request.body)
    sub_select = None

    if data['select'] == 'usage':
        select = list(Usage.objects.all().values())

        if data['option'] is not None:
            sub_select = list(SubUsage.objects.filter(usage__id=data['option']).values())

    elif data['select'] == 'model':
        select = list(MainModel.objects.all().values())

        if data['option'] is not None:
            sub_select = list(PumpType.objects.filter(model__id=data['option']).values())

    return JsonResponse({
        'select': select,
        'selected_option': data['option'],
        'sub_select': sub_select,
    })
    

def solution_main(request):
    return render(request, "solutions/solution_main.html") 

Note, I’ve made some extra features such as clearing the select options, although not for all events.

Merry xmas.

👤Niko

Leave a comment