Error: Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <script>
JavascriptDjangoDjango Templatesvue.jsJavascript Problem Overview
I am using Vuejs and I keep getting this warning in the console. Also no data is loaded because of this warning. I checked the code for unwanted tags but did not find any.
Is this because of the javascript code or I have something wrong in my html?
Here is my code:
> HTML
<div class="row">
<div class="col-sm-12" style="margin-top: 20px;">
<form class="form-inline" method="GET" action=".">
<div class="col-sm-3" style="float: right;"><h4>Date:</h4>
<input class="form-control" style="padding-bottom:0px;" type="text" id="datepicker" readonly="true" name="date" value="2016-06-30">
<input type="submit" class="btn btn-primary btn-sm" value="Submit" >
</div>
</form>
<div class="col-sm-2" style="float: right; margin-top:40px;">
<button class="btn btn-info" type="button" id="csv_export">Click to Export</button>
</div>
</div>
<div class="col-sm-12" style="margin:20px;">
<table class="table table-sm table-striped table-bordered" id="absent-list">
<thead>
<tr>
<th>#</th>
<th style="text-align: center; font-size: 15px;">Full Name</th>
<th style="text-align: center; font-size: 15px;">Section</th>
<th style="text-align: center; font-size: 15px;">Person Called</th>
<th style="text-align: center; font-size: 15px;">Person Relation</th>
<th style="text-align: center; font-size: 15px;">Phone Number</th>
<th style="text-align: center; font-size: 15px;">Absent Reason</th>
<th style="text-align: center; font-size: 15px;">Remarks</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-show="loading" class="text-center">
<td colspan="7">
<i class="fa fa-spinner fa-spin fa-4x"></i>
</td>
</tr>
<tr v-for="record in absent_followback_records">
<td style="text-align: center; font-size: 15px;" scope="row"> {{$index + 1}}</td>
<td style="text-align: center; font-size: 15px;">{{record.student_name}}</td>
<td style="text-align: center; font-size: 15px;">{{record.student_section}}</td>
<td style="text-align: center;">{{record.person_called}}</td>
<td style="text-align: center;">{{record.person_relation}}</td>
<td style="text-align: center;">{{record.phone_number}}</td>
<td style="text-align: center;">{{record.absent_reason_name}}</td>
<td style="text-align: center;">{{record.remarks}}</td>
<td style="text-align: center;"><a href="#" v-on:click="editAbsentFollowbackRecord($index)" data-toggle="modal" data-target="#absent-followback-edit"> Edit </a></td>
</tr>
</tbody>
</table>
</div>
</div>
<script src="/static/js/jquery-ui.min.js"></script>
<script src="/static/js/jquery.plugin.min.js"></script>
<script src="/static/js/jquery.datepick.min.js"></script>
<script src="https://cdn.jsdelivr.net/vue/latest/vue.js"></script>
<script src="/static/js/csrftoken.js"></script>
<script src="/static/js/jquery.TableCSVExport.js"></script>
<script type="text/javascript">
var absentFollowbackListAPiUrl = "/student/api/absent/followback/list/11/";
var absent_reason = jQuery.parseJSON('[{"model": "studentprofile.absentreason", "pk": 1, "fields": {"created": "2016-05-08T06:09:42.410Z", "modified": "2016-05-08T06:09:42.410Z", "reason_name": "sick"}}, {"model": "studentprofile.absentreason", "pk": 2, "fields": {"created": "2016-05-08T06:09:42.416Z", "modified": "2016-05-08T06:09:42.416Z", "reason_name": "arrived late"}}, {"model": "studentprofile.absentreason", "pk": 3, "fields": {"created": "2016-05-08T06:09:42.419Z", "modified": "2016-05-08T06:09:42.419Z", "reason_name": "work at home"}}, {"model": "studentprofile.absentreason", "pk": 4, "fields": {"created": "2016-05-08T06:09:42.423Z", "modified": "2016-05-08T06:09:42.423Z", "reason_name": "public holiday"}}]');
var profile_value = false;
</script>
<script type="text/javascript" src="/static/js/student/student-followback.js"></script>
> absent-followback.js file
$(function() {
$( "#datepicker" ).datepick({dateFormat: 'yyyy-mm-dd'});
});
$('#csv_export').click(function (e) {
e.preventDefault();
$('#absent-list').TableCSVExport({
delivery: 'download',
filename: 'absent-list(' + $( "#datepicker" ).val() + ').csv'
});
});
var vm = new Vue({
el: 'body',
data: {
absent_followback_records: [],
followbackRecordIndex: 'off',
absentReasonList: absent_reason,
loading: false,
currentData: {},
profile: profile_value,
listApiUrl: absentFollowbackListAPiUrl
},
methods: {
populateData: function(api_url){
var self = this;
$.get(api_url, function(data){
self.absent_followback_records = data;
self.loading = false;
});
},
getAbsentFollowbackRecord: function () {
var self = this;
self.loading = true;
var date = $( "#datepicker" ).val();
var api_url = self.listApiUrl + '?date=' + date;
self.populateData(api_url);
},
getProfileAbsentFollowbackRecord: function (event) {
var self = this;
self.loading = true;
var expanded = $(event.target).attr('aria-expanded');
if (expanded == 'false'){
$(event.target).html('Hide Details');
var studentId = $(event.target).attr('studentId');
var api_url = self.listApiUrl + '?student_id=' + studentId;
self.populateData(api_url);
}
else{
$(event.target).html('Show Details');
}
},
editAbsentFollowbackRecord: function (followbackRecordIndex) {
var self = this;
self.currentData = self.absent_followback_records[followbackRecordIndex];
self.followbackRecordIndex = followbackRecordIndex;
},
updateAbsentFollowbackRecord: function (followbackRecordIndex){
var self = this;
var updateData = self.currentData;
var absent_date = updateData.date;
var student_id = updateData.student;
var post_url = updateData.update_url;
var person_called = updateData.person_called;
var person_relation = updateData.person_relation;
var phone_number = updateData.phone_number;
var absent_reason = updateData.absent_reason;
var remarks = updateData.remarks;
if (person_called){
var data = {
student: parseInt(student_id),
date: absent_date,
person_called: person_called,
person_relation: person_relation,
phone_number: phone_number,
absent_reason: parseInt(absent_reason),
remarks: remarks
};
$('#updateAbsentFollowback').html('<i class="fa fa-spinner fa-spin"></i> Saving').attr('class', 'btn btn-primary disabled');
$.ajax({
url: post_url,
type: "PUT",
data: JSON.stringify(data),
dataType: 'json',
contentType: "application/json",
success: function(responseData) {
$('#updateAbsentFollowback').html('Save').attr('class', 'btn btn-success');
if (self.profile == true){
api_url = self.listApiUrl + '?student_id=' + student_id;
self.populateData(api_url);
}
else{
self.getAbsentFollowbackRecord();
}
},
error: function( xhr, status, errorThrown ) {
console.log(errorThrown);
}
});
}
}
},
ready() {
if (this.profile != true){
this.getAbsentFollowbackRecord();
}
}
})
Javascript Solutions
Solution 1 - Javascript
You can use script tag in this way and it will work fine.
I was facing the same problem when I used <script></script>
tag without specifying its type.
After using the type attribute Vue did not warn me for critical error:
<script type="application/javascript">
// your code
</script>
Solution 2 - Javascript
I think the answer is in you question title. Just get rid of all the <script>
tags in the template, put them outside of the template.
In this case you are using body
as the template and you are putting scripts inside your template (body
)
The easy solution is to change the el: 'body'
to el: '#wrapper'
and edit your html to
<body>
<div id="wrapper">
...
</div>
<script ... >
<script ... >
</body>
Solution 3 - Javascript
Make sure you have a closing tag on your root element. I just spent the last 6 hours systematically removing things and pulling my hair out. Turns out I had deleted my closing at some point and Vue was interpreting
Solution 4 - Javascript
a pair of mismatched tags (div, span) can cause this error.
<div id="app">
<div>{{ a }} </span>
</div>
Solution 5 - Javascript
It is because of script tag in your app scope. In my case it was because of google captcha that was in my scope. Google captcha iframe contains script tag
Solution 6 - Javascript
VueJs doesn't allow
Solution 7 - Javascript
My suggestion is a little specific, as I'm using Vue JS v2 in conjunction with jQuery v3.
I'm using jQuery to load the instance of my application with something simple like this:
$(() => {
new Vue({
name: 'MyApp',
el: '#app' // which is my main HTML element for my entire page app
});
});
So, this won't initiate until the entire document is loaded.
In my footer, I'm changing any offending script tags with this before the entire document is loaded, but after my closing main HTML tag:
$('main script:not([type="application/javascript"])').attr('type', 'application/javascript');
This did the trick for me without having to parse any output from offending tags and doing anything more extravagant.
This can be extrapolated out, using the native document selectors if you're not using jQuery, like my example.
Solution 8 - Javascript
(Edit first check for mismatched/unclosed tags within your template, as others have said. Vue can be very picky with that)
Might be a simple as an explicit closure of the component's tag:
Version: [email protected]
Error there:
...body html...
<bme-form-projval
show_debug_elements="Y"
form_name="batchform"
>
...body html...
still there:
<bme-form-projval
show_debug_elements="Y"
form_name="batchform"
/>
Error solved:
<bme-form-projval
show_debug_elements="Y"
form_name="batchform"
>
</bme-form-projval>
Solution 9 - Javascript
Ensure all HTML Tags in the page are opened and closed properly.
Solution 10 - Javascript
Although changing "script" to "script type="application/javascript"" makes the warning disappeared, it causes the page not to finish loading. Therefore, it would not be a good idea to use it!
Solution 11 - Javascript
This code generate this error too!
<!--[if lte IE 8]>
<div>...</div>
<![endif]-->
Solution 12 - Javascript
Check your browser source code, maybe something else has been added to the framework you are using. In my case, I did not remove the rails layout template.