JS 代码不适用于从 Django 模型中检索到的所有数据
Posted
技术标签:
【中文标题】JS 代码不适用于从 Django 模型中检索到的所有数据【英文标题】:JS code not working on all data retrieved from Django Model 【发布时间】:2020-03-22 08:51:23 【问题描述】:我正在使用 html 页面上的 forloop 从 Django 模型中检索 endDate
字段。
我想检查所有即将到来的 endDate 是否都小于今天的日期。为此,我使用的是 JS 代码。
我的代码只能在检索到的第一个日期执行检查,但它不适用于其他日期。
这是我用于检索数据的 HTML 代码:
% for p in object_list %
<h4> p.jobName </h4>
<p><b style="color: red">Expires On: </b><b> p.endDate </b></p>
<a href=" p.get_absolute_url " target="_blank">View info</a>
<input type="hidden" id="endDate" name="variable" value=" p.endDate ">
<span id="check"></span>
% endfor %
JavaScript 代码检查日期:
<script type="text/javascript">
var endDate = document.getElementById("endDate").value;
var ToDate = new Date();
if(new Date(endDate).getTime()<=ToDate.getTime())
document.getElementById("check").innerHTML = "Expired";
document.getElementById("check").className = "label danger";
else
document.getElementById("check").innerHTML = "Active";
document.getElementById("check").className = "label success";
</script>
我现在有 2 个 p.jobName
。第一个应该显示Expired,而第二个应该显示Active。
我的代码仅适用于第一次约会,即仅适用于计算机管理员。
这是我得到的输出:
谁能告诉我这是什么问题?
谢谢
【问题讨论】:
span#check
是否填充了“活动”文本?
@JaredASutton 是的。它也适用于 Active。问题是它只适用于第一次约会,而不适用于其他人。
您的 JS 代码将只适用于 ID 为 endDate
的单个元素。您的 HTML 是否包含具有相同 ID 的多个元素?如果是这样,那是无效的 HTML,这就是您的 JS 无法正常工作的原因 - getElementById
返回一个 single 元素。如果您希望它适用于多个,请改用一个类,例如getElementsByClassName
。
事实上,我刚刚注意到你也分享了你的 Django 模板代码,所以我可以确认这正是问题所在。我会输入一个如何解决它的答案。
虽然顺便说一句,我不能从这段代码中看出为什么你不能只在 Python 的服务器端做这个日期处理,并在模板中包含适当的逻辑,而不是做它在客户端 JS 中。
【参考方案1】:
扩展我在 cmets 中已经说过的内容:
你的问题的本质在这里:
% for p in object_list %
...
<input type="hidden" id="endDate" name="variable" value=" p.endDate ">
<span id="check"></span>
...
% endfor %
一个 HTML 文档只能有一个特定 ID 的 一个 元素(否则它不能很好地“识别”该元素 - 这是 HTML 规范的一部分)。在您的情况下,每当循环包含多个元素时,您最终都会得到多个元素,所有元素都具有endDate
ID,以及多个具有check
ID 的元素。
像这样重复 ID 以及本身是错误的,可能会产生重大的功能影响 - 正如您在代码中看到的那样。也就是说,由于给定 ID 只应该(至多)一个元素,因此在页面上运行的任何 Javascript 代码都有权假设是这种情况。特别是,document.getElementById 返回一个表示 single HTML 元素的对象,而不像 document.getElementsByClassName 这样的类似方法返回 DOM 节点的“集合”。 (因为类与 ID 不同,可以应用于同一文档中的多个元素。)
简而言之,就是如何解决您遇到的问题。只需将上面的id="endDate"
替换为class="endDate"
,与check
类似,并更改您的javascript 以考虑到这一点。您不仅必须将getElementById
方法更改为getElementsByClassName
,还必须考虑到这会返回一个集合(您可以使用.forEach
循环),并且您需要定位相邻的@ 987654332@ span 而不是第一个,或者任何旧的随机。以下代码是使其工作的一种方法(注意使用 ES6 Array.from
将集合转换为真正的 Array,以便您可以使用 .forEach
):
var endDateElts = Array.from(document.getElementsByClassName("endDate"));
var ToDate = new Date();
endDateElts.forEach(function(dateElt)
var endDate = dateElt.value;
var check = dateElt.nextSibling;
if(new Date(endDate).getTime()<=ToDate.getTime())
check.innerHTML = "Expired";
check.className = "label danger";
else
check.innerHTML = "Active";
check.className = "label success";
);
【讨论】:
好的,我有问题了。您的代码运行良好,但innerHTML
在这种情况下不起作用。我试过console.log(check.innerHTML)
,它给出了正确的结果(两个日期),但它在 HTML 模板上不可见。
这听起来很奇怪。如果它正确地记录到控制台,那么我认为这是一个 CSS 问题,为什么你看不到它。【参考方案2】:
基于
% for p in object_list %
<h4> p.jobName </h4>
<p><b style="color: red">Expires On: </b><b> p.endDate </b></p>
<a href=" p.get_absolute_url " target="_blank">View info</a>
<input type="hidden" id="endDate" name="variable" value=" p.endDate ">
<span id="check"></span>
% endfor %
我假设您有多个具有相同 ID 的对象,因此 JS 只处理第一个 endDate
和 check
对象。
<input type="hidden" id="endDate" name="variable" value=" p.endDate ">
<span id="check"></span>
你应该做什么:
-
使用
document.querySelectorAll()
获取多个DOM元素
具有相同的类名。
遍历NodeList
并执行您希望执行的操作。
const endDates = document.querySelectorAll('.endDate');
const checks = document.querySelectorAll('.check');
let ToDate = new Date();
let i = 0;
for (const endDate of endDates)
if(new Date(endDate.value).getTime()<=ToDate)
checks[i].innerHTML = "Expired";
checks[i].className = "label danger";
else
checks[i].innerHTML = "Active";
checks[i].className = "label";
i++;
<div class="container-1">
<input type="text" class="endDate" name="variable" value="2019-11-29">
<span class="check"></span>
<br>
</div>
<div class="container-2">
<input type="text" class="endDate" name="variable" value="2019-11-24">
<span class="check"></span>
<br>
</div>
<div class="container-3">
<input type="text" class="endDate" name="variable" value="2019-11-27">
<span class="check"></span>
</div>
注意事项
如果可以在 views.py
上进行验证,则不太确定为什么要在前端进行验证。 @Robin Zigmond 给出了一个非常好的建议,即只在后端执行此操作并使用结果填充模板。
【讨论】:
只有当我提供静态不同的输入标签时,您的代码才有效。但就我而言,日期是动态的,所以我不知道它的计数,因此不能使用多个输入标签。 是的,我可以在后端使用它来工作。我只是没有想到它,但感谢@Robin ZIgmond。 太棒了,他的建议确实可行。编码愉快!以上是关于JS 代码不适用于从 Django 模型中检索到的所有数据的主要内容,如果未能解决你的问题,请参考以下文章
django-rest-swagger 是不是不适用于模型序列化器?
Django dumpdata 和 loaddata 不适用于多对多中间模型
Python Django - 模板标签中的 % request.user.is_authenticated % 不适用于 JS