我有一个Django模板,用于渲染AmChart图表。该图表由dataLoader从Django内部的URL(返回带有数据的JSON)加载。如果链接返回错误(例如服务器关闭),则图表将冻结在“正在加载数据”部分,并且如果发送了新请求(例如,通过修改表单),并获得了正确的响应,则图表将仍然冻结在“加载数据”部分。
是否有一种方法可以在出现这些错误之后用新数据再次呈现图表,而无需刷新整个页面?
已知事物: 该URL为图表提供正确的json。 当链接返回status ='(failed)'
时,就会发生这种情况模板:
{% extends "reporting_base.html" %}
{% load static %}
{% load i18n %}
{% block container %}
<div class="container-fluid">
<div class="row">
<div id="chartdiv" style="width: 100%; height: 800px; background-color: #FFFFFF;" ></div>
</div>
<div id="tableContainer"
class="container-fluid"
style="margin-top: 2%;"
data-ng-app="videoconferenceRoomsUsage"
ng-controller="videoconferenceRoomsUsageController">
{% if campaign %}
<div class="row form-inline well">
<h3 id="reportName">{{ campaign }}<h3>
{% if campaign.created_by == user %}
<a data-url="{% url 'create_campaign' %}?campaign={{campaign.pk}}" id="saveChanges" class="btn btn-success" href="#">
<span class="glyphicon glyphicon-save"></span>
{% trans 'Save changes' %}
</a>
<a data-toggle="modal" data-target="#createCampaignModal" id="editCampaign" class="btn btn-primary" href="#">
<span class="glyphicon glyphicon-edit"></span>
{% trans 'Edit campaign' %}
</a>
<a data-url="{% url 'remove_campaign' campaign.pk %}" data-redirect-url="{% url 'reporting_home' %}" id="deleteCampaign" class="btn btn-danger" href="#">
<span class="glyphicon glyphicon-remove"></span>
{% trans 'Delete' %}
</a>
{% endif %}
</div>
{% endif %}
<form style="text-align: center" id="problemsEvolutionForm" class="form-inline well">
<div class="form-group">
{{ form.frequency }}
</div>
<div style="display:inline-block" class="form-group">
{{ form.clients }}
</div>
<div class="form-group">
{{ form.time_in_advance }}
</div>
<div class="form-group">
{{ form.sites }}
</div>
<div class="form-group">
<label>
{{ form.ignore_weekends }}
{{ form.ignore_weekends.label }}
</label>
</div>
<div class="form-group">
<label>
{{ form.ignore_test_calls }}
{{ form.ignore_test_calls.label }}
</label>
</div>
<div class="form-group">
{% if user.is_staff and not campaign %}
<a data-toggle="modal" data-target="#createCampaignModal" class="btn btn-primary" href="">{% trans 'Create campaign' %}</a>
{% endif %}
</div>
</form>
<div class="modal fade" id="createCampaignModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">
{% if campaign %}
{% trans 'Edit campaign' %}
{% else %}
{% trans 'Create campaign' %}
{% endif %}
</h4>
</div>
<div class="modal-body">
<form id="createCampaignForm" class="form form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-2 control-label" for="id_name">{{ create_campaign_form.name.label }}</label>
<div class="col-sm-10">
{{ create_campaign_form.name }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="id_description">
{{ create_campaign_form.description.label }}
</label>
<div class="col-sm-10">
{{ create_campaign_form.description }}
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="id_public">
{{ create_campaign_form.public.label }}
</label>
<div class="col-sm-10">
{{ create_campaign_form.public }}
</div>
</div>
<input type="hidden" name="codename" value="videoconference-rooms-usage">
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans 'Close' %}</button>
<button data-url="{% url 'create_campaign' %}{% if campaign %}?campaign={{campaign.pk}}{% endif %}" id="createCampaign" type="button" class="btn btn-primary">{% trans 'Save' %}</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<table id="intervalDataTable" class="table table-responsive">
<thead>
<tr>
<th class="text text-center">{% trans 'Interval' %}</th>
<th class="text text-center">{% trans 'Time (Hours)' %}</th>
<th class="text text-center">{% trans 'Quantity of reservations' %}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="data in chartData">
{% verbatim %}
<td class="text text-center">
{[{ data.category }]}
</td>
<td class="text text-center">
{[{ formatHours(
data.dataContext.hours)
}]}
</td>
<td class="text text-center">
{[{ data.dataContext.reservations }]}
</td>
{% endverbatim %}
</tr>
</tbody>
</table>
</div>
</div>
{% endblock container %}
{% block override_js %}
<script type="text/javascript" src="{% static "amcharts/amcharts.js" %}"></script>
<script type="text/javascript" src="{% static "amcharts/serial.js" %}"></script>
<script type="text/javascript" src="{% static "amcharts/plugins/dataloader/dataloader.min.js" %}"></script>
<script src="{% static "vendor/bootstrap-select/js/bootstrap-select.min.js" %}"></script>
<script src="{% static "vendor/bootstrap-select/js/i18n/defaults-es_CL.min.js" %}"></script>
<script type="text/javascript">
Array.prototype.removeValue = function(val) {
for (var i = 0; i < this.length; i++) {
if (this[i] === val) {
this.splice(i, 1);
i--;
}
}
return this;
};
$.ajaxSetup({ traditional: true });
$(document).ready(
function(){
$('#problemsEvolutionForm select,#problemsEvolutionForm input').on(
'change',
function() {
var tableElement = document.getElementById("tableContainer");
var scope = angular.element(tableElement).scope();
scope.makeChart();
scope.$apply();
}
);
var initialState = $("tableContainer").html()
$("#saveChanges").click(function(){
var saveChangesUrl = $(this).data('url');
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'Click OK to save' %}",
type: "info",
showCancelButton: true,
cancelButtonText: "{% trans 'Cancel' %}",
closeOnConfirm: false,
showLoaderOnConfirm: true,
},
function(){
var data = collectData();
$.post(
saveChangesUrl,
data,
function(result){
swal(
{
title: "{% trans 'Saved!' %}",
text: "{% trans 'Your campaign has been saved!' %}",
type: "success"
}
);
}
).fail(function(){
swal({
title: "Error!",
text: "{% trans 'An unexpected error has happened, please try again in a couple of minutes. If the problem persists, contact support.' %}",
type: "error",
confirmButtonText: "OK"
});
});;
});
});
$("#deleteCampaign").click(function(){
var deleteCampaignUrl = $(this).data('url');
var redirectUrl = $(this).data('redirect-url');
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'You will not be able to recover this campaign!' %}",
type: "warning",
showCancelButton: true,
cancelButtonText: "{% trans 'Cancel' %}",
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Delete' %}",
closeOnConfirm: false
},
function(){
$.post(
deleteCampaignUrl,
{},
function(response){
if(response == 'Deleted'){
function redirectToHome(){
window.location = redirectUrl;
}
setTimeout(redirectToHome, 5000);
swal(
{
title: "{% trans 'Deleted!' %}",
text: "{% trans 'Your campaign has been deleted!' %}",
type: "success"
},
redirectToHome
);
}
}
).fail(function(){
swal({
title: "Error!",
text: "{% trans 'An unexpected error has happened' %}",
type: "error",
confirmButtonText: "OK"
});
});
});
});
$("#createCampaignForm input,#createCampaignForm textarea").addClass('form-control');
function collectData(){
var result = {};
var campaignData = $("#createCampaignForm").serializeArray();
var reportData = $("#problemsEvolutionForm").serializeArray();
for (var i = 0; i < campaignData.length; i++){
result[campaignData[i]['name']] = campaignData[i]['value'];
}
for(var j=0; j<reportData.length; j++){
var key = reportData[j]['name'];
if(key === 'sites' || key === 'mcus' || key === 'clients'){
if(result[key] === undefined){
result[key] = [];
}
result[key].push(reportData[j]['value']);
}
else{
result[key] = reportData[j]['value'];
}
}
return result;
}
$("#createCampaign").on('click', function(){
var data = collectData();
var url = $(this).data('url');
$.post(
url,
data,
function(result){
$('#createCampaignModal').modal('hide');
var reportName = $("#id_name").val();
if($("h3#reportName").length > 0){
$("h3#reportName").html(reportName);
}
swal(
{
title: "{% trans 'Saved!' %}",
text: "{% trans 'Your campaign has been saved!' %}",
type: "success"
}
);
}
)
});
$("select").selectpicker(
{
size: 15,
lang: 'en-us',
deselectAllText: "{% trans 'Deselect all' %}",
selectAllText: "{% trans 'Select all' %}",
noneSelectedText: "{% trans 'Nothing selected' %}"
}
);
var hiddenSites = [];
$("select#id_clients").on(
'changed.bs.select',
function(){
var clientIds = $(this).val();
if(clientIds === null){
clientIds = [];
for(var k=0; k<hiddenSites.length; k++){
$(hiddenSites[k]).appendTo("#id_sites");
}
hiddenSites = [];
$("#id_sites").selectpicker('refresh');
return;
}
for(var i=0; i<clientIds.length; i++){
var clientId = clientIds[i];
var selectedItem = $("select#id_clients>option[value=" + clientId + "]");
var clientName = selectedItem.text();
var openBracketIndex = clientName.indexOf('(');
if(openBracketIndex !== -1){
clientName = clientName.slice(openBracketIndex+1, -1)
}
if(clientName !== undefined){
var foundIndex = null;
for(var j=0; j<hiddenSites.length; j++){
var currentSiteName = hiddenSites[j];
if(currentSiteName.attr('label') === clientName){
foundIndex = j;
var optGroups = $("select#id_sites").find(">optgroup");
if(optGroups.length === 0){
$(hiddenSites[j]).appendTo("#id_sites");
}
else{
var lastOptItem = optGroups.last();
var lastOptName = lastOptItem.attr('label');
var firstOptItem = optGroups.first();
var firstOptName = firstOptItem.attr('label');
if(clientName > lastOptName){
$(hiddenSites[j]).appendTo("#id_sites");
}
else if(clientName < firstOptName){
$(hiddenSites[j]).prependTo("#id_sites");
}
else{
var spliceIndex = foundIndex;
foundIndex = null;
$.each(
optGroups,
function(i, optItem){
var wrappedOptItem = $(optItem);
if(wrappedOptItem.attr('label') > clientName){
wrappedOptItem.before($(hiddenSites[j]));
hiddenSites.splice(spliceIndex, 1);
return false;
}
}
);
}
}
break;
}
}
if(foundIndex !== null){
hiddenSites.splice(foundIndex, 1)
}
}
}
var deselectedItems = $("select#id_sites>optgroup");
for(var l=0; l<deselectedItems.length; l++){
var notSelectedClientItem = deselectedItems[l];
var notSelectedClientName = notSelectedClientItem.label;
var notSelectedClientId = $("select#id_clients>option:contains('" + notSelectedClientName + "')").val();
if(notSelectedClientId !== null){
var found = false;
for(var m=0; m<clientIds.length; m++){
if(clientIds[m] === notSelectedClientId){
found = true;
break;
}
}
if(!found){
hiddenSites.push($(notSelectedClientItem).remove());
}
}
}
$("#id_sites").selectpicker('refresh');
});
}
);
function handleDataUpdated(event){
var tableElement = document.getElementById("tableContainer");
var scope = angular.element(tableElement).scope();
if(event.chart !== undefined && scope !== undefined)
{
var chartData = event.chart.chartData;
var invertedChartData = [];
for(var i=chartData.length - 1; i>=0; i--){
invertedChartData.push(chartData[i]);
}
scope.chartData = invertedChartData;
scope.$apply();
}
}
var app = angular.module(
'videoconferenceRoomsUsage',
[]
);
app.config(
function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
}
);
app.controller(
'videoconferenceRoomsUsageController',
[
'$scope',
function($scope) {
$scope.chartData = [];
$scope.getHours = function(d){
return (Math.round(d * 100 / 3600) / 100) + "h";
};
$scope.formatHours = function(d){
return Math.round(d*100)/100 + "h"
}
$scope.getUrl = function(){
var queryString = "?" + $("form").serialize();
return "{% url 'new_reservations_json' %}" + queryString;
};
$scope.makeChart = function(){
if($scope.chart !== undefined){
var chart = $scope.chart;
chart.dataLoader.url = $scope.getUrl();
chart.dataLoader.loadData();
}
else{
$scope.chart = AmCharts.makeChart(
"chartdiv",
{
"type": "serial",
"listeners": [
{
"event": "dataUpdated",
"method": handleDataUpdated
}
],
"categoryField": "category",
"startDuration": 1,
"categoryAxis": {
"gridPosition": "start"
},
"trendLines": [],
"graphs": [
{
"color": "RGB(152,72,7)",
"colorField": "color",
"fillAlphas": 1,
"id": "Hours",
"labelText": "[[value]]",
"lineColor": "rgb(152,72,7)",
"lineColorField": "color",
"title": "{% trans 'Conference hours' %}",
"type": "column",
"valueAxis": "Hours-Axis",
"valueField": "hours"
},
{
"bulletBorderThickness": 0,
"color": "rgb(250, 120,15)",
"cursorBulletAlpha": 0,
"customBullet": "",
"fillColors": "rgb(250, 120,15)",
"id": "Room-Quantity",
"labelText": "[[value]]",
"lineColor": "rgb(250, 120,15)",
"title": "{% trans 'Quantity of reservations' %}",
"valueAxis": "Room-Quantity-Axis",
"valueField": "reservations"
}
],
"legend": {
"enabled": true,
"useGraphSettings": true,
},
"guides": [],
"export" : exportConfiguration,
"valueAxes": [
{
"id": "Hours-Axis",
"title": "{% trans 'Time (Hours)' %}",
"position": "right",
},
{
"id": "Room-Quantity-Axis",
"title": "{% trans 'Quantity of reservations' %}"
}
],
"allLabels": [],
"balloon": {},
"titles": [
{
"id": "Room-Usage",
"size": 15,
"text": "{% trans 'New Reservations' %}"
}
],
"dataLoader": {
"url": $scope.getUrl(),
"format": "json",
}
}
);
}
};
$scope.makeChart();
}
]
);
</script>
{% endblock %}
{% block extra_css %}
<link href="{% static "vendor/bootstrap-select/css/bootstrap-select.min.css" %}" rel="stylesheet"/>
<style>
#problemsEvolutionForm .form-group {
margin-left: 20px;
}
#id_call_type, #id_videoconference_mode{
list-style: none;
text-align: left;
padding-left: 10px;
padding-top: 4px;
}
</style>
{% endblock extra_css %}
答案 0 :(得分:0)
这很奇怪。尝试完全清除并重新创建图表。
$scope.makeChart = function(){
if($scope.chart !== undefined){
// clear chart
$scope.chart.clear();
$scope.chart = undefined;
}
$scope.chart = AmCharts.makeChart("chartdiv", {
"type": "serial",
// ...
"dataLoader": {
"url": $scope.getUrl(),
"format": "json"
}
});
}
希望这会有所帮助!