如何在 django 模板中为循环创建唯一的 javascript 变量名?

Posted

技术标签:

【中文标题】如何在 django 模板中为循环创建唯一的 javascript 变量名?【英文标题】:How can I create unique javascript variable names in a django template for loop? 【发布时间】:2021-06-17 09:33:13 【问题描述】:

我正在使用 django 模板循环访问 hp_tracker 对象。每个 hp_tracker 都有自己的 js 代码,用于通过 ajax 更改值。我几乎可以肯定我应该在 .js 文件中包含此代码,但是我很难找到一种方法来唯一地选择每个 hp_tracker 而无需访问 .js 文件中的 django 模板变量。所以...我将 js 移到了 html 模板本身。我知道这无疑会产生巨大的安全隐患,我也愿意讨论这些问题。

不管怎样,我的问题。我的 js 失败了,因为我声明了不唯一的全局变量(!)。它们被用来控制一些计数器和 setTimeout,我不知道现在如何使用它们来做我想做的事情。

所以 for 循环试图一遍又一遍地重新声明同一个变量。在脚本的其余部分中,我使用的是 JQuery,它非常乐意使用 django 变量 hp_tracker.id ,但 javascript 不是因为变量名称中不允许使用对象 ID 中的“-”字符.

我到底应该怎么做才能解决这个热点问题。有没有办法在没有全局变量的情况下运行我的代码?我可以在不使用对象 ID 的情况下识别我的 for 循环中的对象吗?

<div id="ToolSessionPageWrapper">
<div class="tool-session-page-header">
    <div id=OpenToolSelectionMenuBtn class="arrow-down"></div>
</div>
<div class="tool-session-page-body">
    <div id="HpTrackersViewWrapper" class="tool-body">
        % for hp_tracker in hp_trackers %
            <div class="hp-tracker-box">
                <div id="hp_tracker.id-HpTrackerTitle" class="hp-tracker-title"> hp_tracker.title </div>
                <br />
                <form method="POST" action="% url 'hp_change_value' hp_tracker.id %" id=" hp_tracker.id -HpValueForm">
                    % csrf_token %
                    <div class="hp-control-box">
                        <button type="button" id=" hp_tracker.id -HpValueDecreaseBtn" class="hp-value-change-btn decrease">-</button>
                        <div id="hp_tracker.id-HpValue" class="hp-value"> hp_tracker.hp_value </div>
                        <div id=" hp_tracker.id -HpValueInput"> hp_change_value_form.hp_value </div>
                        <div id=" hp_tracker.id -HpChangeValueCover" class="hp-value hp-change-value-cover"></div>
                        <div id=" hp_tracker.id -HpChangeValue" class="hp-value hp-change-value"></div>
                        <button type="button" id=" hp_tracker.id -HpValueIncreaseBtn" class="hp-value-change-btn increase">+</button>
                    </div>
                </form>
            </div>
            <script>
                #ajax call for HpValueForm#
                function changeHpValue(form) 
                    'use strict';
                    $(form).submit(function (e) 
                        // preventing from page reload and default actions
                        e.preventDefault();
                        // serialize the form data.
                        let serializedData = $(form).serialize();
                        // make POST ajax call
                        $.ajax(
                            type: 'POST',
                            url: '% url 'hp_change_value' hp_tracker.id %',
                            data: serializedData,
                            success: function (response) 
                                let form_instance = JSON.parse(response['form_instance']);
                                let fields = form_instance[0]['fields'];
                                $('#hp_tracker.id-HpValue').empty().prepend(fields.hp_value);
                                console.log('ajaxSuccess');
                            ,
                            error: function (response) 
                                console.log(response["responseJSON"]["error"]);
                            
                        );
                    );
                

                #control timeout before hp_value increase or decrease is submitted#
                let  hp_tracker.id|escapejs hp_add_subtract_value = $('#hp_tracker.id-HpValue').text(),
                    hp_change_value = 0,
                    timeoutHandler;
                function timeoutControl() 
                    clearTimeout(timeoutHandler);
                    timeoutHandler = setTimeout(function () 
                        $('# hp_tracker.id -HpValueInput input').val(hp_add_subtract_value);
                        $('# hp_tracker.id -HpValueForm').submit();
                        $('#hp_tracker.id-HpChangeValue').css('display': 'none');
                        $('#hp_tracker.id-HpChangeValueCover').css('display': 'none');
                        hp_change_value = 0;
                        $('#hp_tracker.id-HpChangeValue').empty().prepend(hp_change_value);
                    , 2000);
                
                #increase the hp value#
                $('# hp_tracker.id -HpValueIncreaseBtn').click(function (e) 
                    'use strict';
                    hp_add_subtract_value++;
                    hp_change_value++;
                    $('#hp_tracker.id-HpChangeValue').css('display': 'inline');
                    $('#hp_tracker.id-HpChangeValueCover').css('display': 'inline');
                    $('#hp_tracker.id-HpChangeValue').empty().prepend(hp_change_value);
                    timeoutControl();
                );

                #decrease the hp value#
                $('# hp_tracker.id -HpValueDecreaseBtn').click(function (e) 
                    'use strict';
                    hp_add_subtract_value--;
                    hp_change_value--;
                    $('#hp_tracker.id-HpChangeValue').css('display': 'inline');
                    $('#hp_tracker.id-HpChangeValueCover').css('display': 'inline');
                    $('#hp_tracker.id-HpChangeValue').empty().prepend(hp_change_value);
                    timeoutControl();
                );

                #submit HpValueForm#
                $('# hp_tracker.id -HpValueForm').on('submit', changeHpValue('# hp_tracker.id -HpValueForm'));
            </script>
        % endfor %
    </div>
</div>

【问题讨论】:

查看% for 上的文档。您可以执行 forloop.counter 之类的操作来获取当前循环索引。这应该可以帮助您创建唯一的名称 - docs.djangoproject.com/en/3.1/ref/templates/builtins/#for 啊,是的,我没想到。我去看看! 你好,有必要把django代码放在jquery里面吗? 我在 jQuery 中使用 Django 变量作为选择器来识别由 Django 模板系统动态生成的元素。不过,我对所有想法都持开放态度! 【参考方案1】:

您可以只创建一个适用于所有形式的脚本,而不是创建多个脚本。因此,您可以在 django 代码中进行更改:

<div id="HpTrackersViewWrapper" class="tool-body">
        % for hp_tracker in hp_trackers %
            <div class="hp-tracker-box">
                <div id="hp_tracker.id-HpTrackerTitle" class="hp-tracker-title"> hp_tracker.title </div>
                <br />
                //add data-id ... and a class
                <form method="POST" action="% url 'hp_change_value' hp_tracker.id %" data-id ="hp_tracker.id" class="form_to_submit" id=" hp_tracker.id -HpValueForm">
                    % csrf_token %
                    <div class="hp-control-box">
                        <button type="button" id=" hp_tracker.id -HpValueDecreaseBtn" class="hp-value-change-btn decrease">-</button>
                        <div id="hp_tracker.id-HpValue" class="hp-value"> hp_tracker.hp_value </div>
                        <div id=" hp_tracker.id -HpValueInput"> hp_change_value_form.hp_value </div>
                        <div id=" hp_tracker.id -HpChangeValueCover" class="hp-value hp-change-value-cover"></div>
                        <div id=" hp_tracker.id -HpChangeValue" class="hp-value hp-change-value"></div>
                        <button type="button" id=" hp_tracker.id -HpValueIncreaseBtn" class="hp-value-change-btn increase">+</button>
                    </div>
                </form>
            </div>
            //remove whole script from here 
        % endfor %        
    </div>

然后,您的 jquery 代码将如下所示:

//on submit of form
$(".form_to_submit").submit(function(e) 
  e.preventDefault();
  //get ids..
  var data_id = $(this).data("id")
  let serializedData = $(this).serialize();
  console.log(data_id)
  // make POST ajax call
  $.ajax(
    type: 'POST',
    url: '% url hp_change_value ' + data_id + ' %', //pass here id
    data: serializedData,
    success: function(response) 
      let form_instance = JSON.parse(response['form_instance']);
      let fields = form_instance[0]['fields'];
  $('#' + data_id + '-HpValue').empty().prepend(fields.hp_value); 
   console.log('ajaxSuccess');
    ,
    error: function(response) 
      console.log(response["responseJSON"]["error"]);
    
  );
);


var timeoutHandler;

function timeoutControl(el) 
  clearTimeout(timeoutHandler);
  //get closet form
  var selector = $(el).closest("form")
  //get hp values
  var hp_add_subtract_value = selector.find(".hp-value").text()
  //get id
  var data_id = selector.data('id')
  timeoutHandler = setTimeout(function() 
    $('#' + data_id + '-HpValueInput input').val(hp_add_subtract_value);
    selector.submit();
    selector.find('.hp-change-value').css(
      'display': 'none'
    );
    selector.find('.hp-change-value-cover').css(
      'display': 'none'
    );
    hp_change_value = 0;
    selector.find('.hp-change-value').empty().prepend(hp_change_value);
  , 2000);


$('.increase').click(function(e) 
  var selector = $(this).closest(".hp-control-box")
  var hp_add_subtract_value = parseInt(selector.find(".hp-value").text())
  hp_add_subtract_value++;
  var hp_change_value = selector.find(".hp-change-value").text().trim() != "" ? parseInt(selector.find(".hp-change-value").text().trim()) : 0
  selector.find('.hp-change-value').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value-cover').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value').empty().prepend(hp_change_value);
  timeoutControl(this); //here this refer to increase button which is clickde..
);

$('.decrease').click(function(e) 
  //get closest outer box..
  var selector = $(this).closest(".hp-control-box")
  //use find to get other values..
  var hp_add_subtract_value = parseInt(selector.find(".hp-value").text())
  var hp_change_value = selector.find(".hp-change-value").text().trim() != "" ? parseInt(selector.find(".hp-change-value").text().trim()) : 0

  hp_add_subtract_value--;
  hp_change_value--;
  //change doms ,,,
  selector.find('.hp-change-value').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value-cover').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value').empty().prepend(hp_change_value);
  timeoutControl(this); //refer the button which is clicked
);

演示代码

//on submit of form
$(".form_to_submit").submit(function(e) 
  e.preventDefault();
  //get ids..
  var data_id = $(this).data("id")
  let serializedData = $(this).serialize();
  console.log(data_id)
  // make POST ajax call
  /*$.ajax(
    type: 'POST',
    url: '% url hp_change_value ' + data_id + ' %', //pass here id
    data: serializedData,
    success: function(response) 
      let form_instance = JSON.parse(response['form_instance']);
      let fields = form_instance[0]['fields'];*/
  $('#' + data_id + '-HpValue').empty().prepend(44); //just for demo...
  /* console.log('ajaxSuccess');
    ,
    error: function(response) 
      console.log(response["responseJSON"]["error"]);
    
  );*/
);


var timeoutHandler;

function timeoutControl(el) 
  clearTimeout(timeoutHandler);
  //get closet form
  var selector = $(el).closest("form")
  //get hp values
  var hp_add_subtract_value = selector.find(".hp-value").text()
  //get id
  var data_id = selector.data('id')
  timeoutHandler = setTimeout(function() 
    $('#' + data_id + '-HpValueInput input').val(hp_add_subtract_value);//don't know where is input in your code..:P 
    selector.submit();
    selector.find('.hp-change-value').css(
      'display': 'none'
    );
    selector.find('.hp-change-value-cover').css(
      'display': 'none'
    );
    hp_change_value = 0;
    selector.find('.hp-change-value').empty().prepend(hp_change_value);
  , 2000);


$('.increase').click(function(e) 
  var selector = $(this).closest(".hp-control-box")
  var hp_add_subtract_value = parseInt(selector.find(".hp-value").text())
  hp_add_subtract_value++;
  var hp_change_value = selector.find(".hp-change-value").text().trim() != "" ? parseInt(selector.find(".hp-change-value").text().trim()) : 0
  selector.find('.hp-change-value').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value-cover').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value').empty().prepend(hp_change_value);
  timeoutControl(this); //here this refer to increase button which is clickde..
);

$('.decrease').click(function(e) 
  //get closest outer box..
  var selector = $(this).closest(".hp-control-box")
  //use find to get other values..
  var hp_add_subtract_value = parseInt(selector.find(".hp-value").text())
  var hp_change_value = selector.find(".hp-change-value").text().trim() != "" ? parseInt(selector.find(".hp-change-value").text().trim()) : 0

  hp_add_subtract_value--;
  hp_change_value--;
  //change doms ,,,
  selector.find('.hp-change-value').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value-cover').css(
    'display': 'inline'
  );
  selector.find('.hp-change-value').empty().prepend(hp_change_value);
  timeoutControl(this); //refer the button which is clicked
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="hp-tracker-box">
  <div id="1-HpTrackerTitle" class="hp-tracker-title">Soemthings ...,,</div>
  <br />
  <!--here added data-id , class as well-->
  <form method="POST" action="% url 'hp_change_value' 1 %" data-id="1" class="form_to_submit" id="1-HpValueForm">
    % csrf_token %
    <div class="hp-control-box">
      <button type="button" id="1-HpValueDecreaseBtn" class="hp-value-change-btn decrease">-</button>
      <div id="1-HpValue" class="hp-value">22</div>
      <div id="1-HpValueInput">23</div>
      <div id="1-HpChangeValueCover" class="hp-value hp-change-value-cover"></div>
      <div id="1-HpChangeValue" class="hp-value hp-change-value"></div>
      <button type="button" id="1-HpValueIncreaseBtn" class="hp-value-change-btn increase">+</button>
    </div>
  </form>
</div>
<div class="hp-tracker-box">
  <div id="1-HpTrackerTitle" class="hp-tracker-title">Soemthings ...,,</div>
  <br />
  <form method="POST" action="% url 'hp_change_value' 2 %" data-id="2" class="form_to_submit" id="2-HpValueForm">
    % csrf_token %
    <div class="hp-control-box">
      <button type="button" id="2-HpValueDecreaseBtn" class="hp-value-change-btn decrease">-</button>
      <div id="2-HpValue" class="hp-value">22</div>
      <div id="2-HpValueInput">23</div>
      <div id="2-HpChangeValueCover" class="hp-value hp-change-value-cover"></div>
      <div id="2-HpChangeValue" class="hp-value hp-change-value"></div>
      <button type="button" id="2-HpValueIncreaseBtn" class="hp-value-change-btn increase">+</button>
    </div>
  </form>
</div>

【讨论】:

【参考方案2】:

@Swati,您的回答并没有完全满足我的需要,但您确实将我推向了正确的方向,并帮助我填补了我对这一切如何运作的理解中的一些漏洞。所以我把你的答案标记为正确,谢谢你的帮助!这是我最终使用的代码(我知道 ajax 错误函数不起作用,但那是另一天......):

html

<div id="ToolSessionPageWrapper">
<div class="tool-session-page-header">
    <div id=OpenToolSelectionMenuBtn class="arrow-down"></div>
</div>
<div class="tool-session-page-body">
    <div id="HpTrackersViewWrapper" class="tool-body">
        % for hp_tracker in hp_trackers %
            <div class="hp-tracker-box">
                <div id="hp_tracker.id-HpTrackerTitle" class="hp-tracker-title"> hp_tracker.title </div>
                <br />
                <form method="POST" action="% url 'hp_change_value' hp_tracker.id %" id=" hp_tracker.id -HpValueForm" data-id=" hp_tracker.id " class="hp-value-change-form">
                    % csrf_token %
                    <div class="hp-control-box">
                        <button type="button" data-id=" hp_tracker.id -HpValueDecreaseBtn" class="hp-value-change-btn decrease">-</button>
                        <div id=" hp_tracker.id -HpValue" class="hp-value"> hp_tracker.hp_value </div>
                        <div id=" hp_tracker.id -HpValueInput"> hp_change_value_form.hp_value </div>
                        <div id=" hp_tracker.id -HpValueChangeCover" class="hp-value hp-change-value-cover"></div>
                        <div id=" hp_tracker.id -HpValueChange" class="hp-value hp-change-value"></div>
                        <button type="button" data-id=" hp_tracker.id -HpValueIncreaseBtn" class="hp-value-change-btn increase">+</button>
                    </div>
                </form>
            </div>
        % endfor %
    </div>
</div>

js

// ajax call for HpValueForm
$('.hp-value-change-form').submit(function(e) 
    'use strict';
    e.preventDefault();
    let data_id = $(this).attr("data-id");
    // serialize the form data.
    let serializedData = $(this).serialize();
    // make POST ajax call
    $.ajax(
        type: 'POST',
        url: $(this).attr('action'),
        data: serializedData,
        success: function (response) 
            let form_instance = JSON.parse(response['form_instance']);
            let fields = form_instance[0]['fields'];
            $("#" + data_id + "-HpValue").empty().prepend(fields.hp_value);
            console.log('ajaxSuccess');
        ,
        error: function (response) 
            console.log(response["responseJSON"]["error"]);
        
    );
);



//control timeout before hp_value increase or decrease is submitted
localStorage.setItem('hp_change_value', '0');
let timeoutHandler;

function timeoutControl(element) 
    'use strict';
    clearTimeout(timeoutHandler);
    // select the closest for to the clicked button
    let selector = $(element).closest('.hp-value-change-form');

    // assign the unique django object id to a variable
    let data_id = selector.attr("data-id");

    // get the hp change value from local storage
    let hp_change_value = parseInt(localStorage.getItem('hp_change_value'));

    // get the current hp value being provided by django context
    let hp_initial_value = parseInt($("#" + data_id + "-HpValue").text());

    // calculate the amount to be entered into the hp value change form
    let hp_add_subtract_value = hp_initial_value + hp_change_value;

    // After a 2 second delay submit the form and reset the change value to 0
    timeoutHandler = setTimeout(function () 
        $('#' + data_id + '-HpValueInput input').val(hp_add_subtract_value);
        $('#' + data_id + '-HpValueForm').submit();
        $('#' + data_id + '-HpValueChange').css('display': 'none');
        $('#' + data_id + '-HpValueChangeCover').css('display': 'none');
        localStorage.setItem('hp_change_value', '0');
    , 2000);

// increase the hp value with each button click - value is not submitted until 
// after a 2 second delay via timeoutControl()
$('.hp-value-change-btn.increase').click(function (e) 
    'use strict';
    let selector = $(this).closest('.hp-control-box');
    let hp_change_value = parseInt(localStorage.getItem('hp_change_value'));
    hp_change_value++;
    localStorage.setItem('hp_change_value', hp_change_value.toString());
    $(selector.find('.hp-change-value')).css('display': 'inline');
    $(selector.find('.hp-change-value-cover')).css('display': 'inline');
    $(selector.find('.hp-change-value')).empty().prepend(hp_change_value);
    timeoutControl(this);

);

// decrease the hp value with each button click - value is not submitted until 
// after a 2 second delay via timeoutControl()
$('.hp-value-change-btn.decrease').click(function (e) 
    'use strict';
    let selector = $(this).closest('.hp-control-box');
    let hp_change_value = parseInt(localStorage.getItem('hp_change_value'));
    hp_change_value--;
    localStorage.setItem('hp_change_value', hp_change_value.toString());
    $(selector.find('.hp-change-value')).css('display': 'inline');
    $(selector.find('.hp-change-value-cover')).css('display': 'inline');
    $(selector.find('.hp-change-value')).empty().prepend(hp_change_value);
    timeoutControl(this);

);

【讨论】:

以上是关于如何在 django 模板中为循环创建唯一的 javascript 变量名?的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何工具可以自动在Django中为模型创建模板

在一个 <Input> 标签中为多个按钮创建多个 ID

如何为 django 模板中的单个按钮的 for 循环中的按钮提供唯一 id?

如何在 django 中为模板应用背景图像

Python - 如何在 django 模板中为所有值并排显示两个键的字典值

Django模板:循环并打印对象的所有可用属性?