Datetimepicker发送两个请求

时间:2018-06-19 17:06:51

标签: jquery django twitter-bootstrap

我有django模板,该模板呈现一种形式:2个datetimepickers,2个multiselect下拉列表和1个select下拉列表。 下拉菜单就像一个超级按钮,但datetimepicker的行为不正确。

案例:我想更改日期。所以: -单击日期时间选择器,然后显示日历(无时间) -点击日期:     -发送新请求 -单击其他位置或其他字段:     -发送与以前相同的请求

恐怕这最终可能会使服务器超载。 我如何避免最后一个额外的请求?

代码:

表格:

class UsageByTypeForm(forms.Form):
def __init__(self, data=None, user=None, *args, **kwargs):
    super().__init__(data=data, *args, **kwargs)

    if user and user.is_authenticated():
        self.setup_mcu_field(user)
        self.setup_client_field(user)

def setup_mcu_field(self, user):
    user_mcus = user.operated_mcus
    if len(user_mcus) > 1:
        mcu_field = self.fields['mcus']
        mcu_field.queryset = user_mcus.order_by('name').exclude(mcu_unico_id__isnull=True)
        mcu_field.initial = mcu_field.queryset
    else:
        del self.fields['mcus']

def setup_client_field(self, user):
    user_clients = user.operated_client_ids
    client_field = self.fields['clients']
    client_field.queryset = Cliente.objects.filter(id__in=user_clients)
    client_field.initial = client_field.queryset

frequency = forms.ChoiceField(
    label=_('Frequency'),
    choices=ReportFrequency.values.items(),
    required=True,
    widget=forms.Select(
        attrs={
            'data-placeholder': _('Frequency'),
            'data-header': _('Select a frequency'),
        }),
)
mcus = forms.ModelMultipleChoiceField(
    queryset=MCU.objects.none(),
    widget=forms.SelectMultiple(
        attrs={
            'data-actions-box': "true",
            'data-header': _('Choose some MCUs'),
        }),
)
clients = forms.ModelMultipleChoiceField(
    queryset=Cliente.objects.none(),
    required=False,
    widget=forms.SelectMultiple(
        attrs={
            'data-header': _('Choose some clients'),
            'data-actions-box': "true",
        }),
)
begin = forms.DateField(
    initial=get_last_month_range()[0],
    widget=forms.TextInput(
        attrs={
            'class': 'form-control',
        }),
)
end = forms.DateField(
    initial=get_last_month_range()[0],
    widget=forms.TextInput(
        attrs={
            'class': 'form-control',
        }),
)

def get_interval(self):
    time_in_advance = self.cleaned_data.get(
        'time_in_advance'
    ) or LAST_MONTH
    return get_time_interval(
        time_in_advance
    )

模板:

    {% 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">

            <form style="text-align: center" id="UsageByTypeForm" class="form-inline well">

                <div id="#id_begin" class="form-group">
                  {{ form.begin }}
              </div>

              <div id="#id_end" class="form-group">
                  {{ form.end }}
              </div>

              <div id="#id_freq"class="form-group">
                  {{ form.frequency }}
              </div>

              <div id="#id_clients" style="display:inline-block" class="form-group">
                  {{ form.clients }}
              </div>

              <div id="#id_mcus" class="form-group">
                  {{ form.mcus }}
              </div>

            </form>

            <table id="intervalDataTable" class="table table-responsive">
              <thead>
                <tr>
                  <th class="text text-center">{% trans 'Interval' %}</th>
                  <th class="text text-center">{% trans 'Max Licence Usage' %}</th>
                </tr>
              </thead>
              <tbody>
                <tr ng-repeat="data in chartData">
                  {% verbatim %}
                  <td class="text text-center">
                    {[{ data.dataContext.category }]}
                  </td>
                  <td class="text text-center">
                    {[{data.dataContext.capacity}]}
                  </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" src="{% static "js/jquery.datetimepicker.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(){
              $('#UsageByTypeForm select').on(
                'change',
                function() {
                  var tableElement = document.getElementById("tableContainer");
                  var scope = angular.element(tableElement).scope();

                  scope.makeChart();
                  scope.$apply();
                }
              );

              $('#id_begin').datetimepicker({
                closeOnDateSelect: true,
                format: 'Y-m-d',
                lang: 'es',
                timepicker: false,
                onShow:function( ct ){
                    this.setOptions({
                        maxDate:$('#id_end').val()?$('#id_end').val():false
                    }
                  )
                },
              });

              $('#id_end').datetimepicker({
                closeOnDateSelect: true,
                format: 'Y-m-d',
                lang: 'es',
                timepicker: false,
                onShow:function( ct ){
                    this.setOptions({
                        minDate:$('#id_begin').val()?$('#id_begin').val():false
                    }
                  )
                },
              });

              $('#id_begin').change(function(e){
                  var tableElement = document.getElementById("tableContainer");
                  var scope = angular.element(tableElement).scope();

                  scope.makeChart();
                  scope.$apply();
              });

              $('#id_end').change(function(e){
                  var tableElement = document.getElementById("tableContainer");
                  var scope = angular.element(tableElement).scope();

                  scope.makeChart();
                  scope.$apply();
              });


              function collectData(){
                var result = {};
                var reportData = $("#UsageByTypeForm").serializeArray();

                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;
              }

              $("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.formatPercent = function(d){
                return Math.round(d*100)/100 + "%"
            };

            $scope.getUrl = function(){
                var queryString = "?" + $("form").serialize();
                return "{% url 'usage_of_ports_reports_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",
                      "numberFormatter": {
                            "precision": -1,
                            "decimalSeparator": ",",
                            "thousandsSeparator": "",
                          },
                      "listeners": [
                          {
                            "event": "dataUpdated",
                            "method": handleDataUpdated
                          }
                        ],
                        "categoryField": "category",
                        "startDuration": 1,
                        "categoryAxis": {
                          "gridPosition": "start"
                        },
                        "trendLines": [],
                        "graphs": [
                          {
                            "id": "capacity_unit_usage",
                            "title": "{% trans 'Max Licence Usage' %}",
                            "valueField": "capacity",
                            "bullet": "round",
                            "balloonText": "[[value]]",
                          },
                        ],
                        "legend": {
                            "enabled": true
                        },
                        "guides": [],
                        "export" : exportConfiguration,
                        "valueAxes": [
                          {
                            "id": "Hours-Axis",
                            "title": "{% trans 'Number of Ports' %}",
                          },
                        ],
                        "allLabels": [],
                        "titles": [
                          {
                            "id": "Room-Usage",
                            "size": 15,
                            "text": "{% trans 'Max Licence Usage' %}"
                          }
                        ],
                        "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"/>
    <link rel="stylesheet" href="{% static "css/jquery.datetimepicker.min.css"%}">
    <style>
        #UsageByTypeForm .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 %}

1 个答案:

答案 0 :(得分:1)

您正在使用的库可能有一个日期更改事件,因此您不会在基础输入每次更新时都被触发。假设这是jquery bootstrap datetimepicker库,您可以执行以下操作。尚未亲自尝试过此操作,但来自文档“ dp.change-日期更改时触发。”

$('#id_begin').on('dp.change', function(e){ 
    var tableElement = document.getElementById("tableContainer");
    var scope = angular.element(tableElement).scope();
    scope.makeChart();
    scope.$apply();
})

这些事件可以在http://eonasdan.github.io/bootstrap-datetimepicker/Events/中找到。如果您使用其他库,则它们可能会发生类似的事件。

或者,您可以将日期存储在变量中,并在执行工作之前确保日期已更改。类似这样的事情。请记住,完全未经测试

var previousDate = $('#id_begin').val(); //or whatever your default is here
$('#id_begin').change(function(e){
   var currentDate = $(this).val();
   if(previousDate != currentDate) {
     var tableElement = document.getElementById("tableContainer");
     var scope = angular.element(tableElement).scope();
     scope.makeChart();
     scope.$apply();
     previousDate = currentDate;
   }
});