Undesired iOS Safari animations: back/forward actions with swipe gestures

Viewed 675

You can see in the next video what I mean: https://www.dropbox.com/s/zu0skpfo2zkrex3/ios_safari_gestures.mp4?dl=0

In this example, when I go forward with the button at the bottom of the browser everything goes fine, the page is displayed correctly. However when I go forward by swiping from right to left the browser performs some undesired animation that causes a sort of flicker.

The configuration of the example of the video is next:

state: 'statistics-consumptions',
        config: {
          resolve: {
              breadCrumbData:  ['$stateParams', 'EquipmentMainService', function($stateParams, EquipmentMainService) {
                   return EquipmentMainService.getBreadcrumbData($stateParams.equipmentId);
              }]
          },
          url: '/statistics-consumptions/{equipmentId}',
          templateUrl: 'app/statistics/consumption/consumptions-test.html'
        }

If I remove the resolve condition then that flicker disapears. Why is this happening? Is it a UI-router issue?

The funny thing is that there are situations when this is not happening. For example, the previously example is a very simplified version of the real case. The configuration of the real case is next.

The state:

 state: 'statistics-consumptions',
        config: {
          resolve: {
              breadCrumbData:  ['$stateParams', 'EquipmentMainService', function($stateParams, EquipmentMainService) {
                   return EquipmentMainService.getBreadcrumbData($stateParams.equipmentId);
              }],
              initialData: ['$stateParams', 'StatisticsConsumptionsService', function($stateParams, StatisticsConsumptionsService) {
                   return StatisticsConsumptionsService.getInitialResources($stateParams.equipmentId);
              }]
          },
          url: '/statistics-consumptions/{equipmentId}',
          templateUrl: 'app/statistics/consumption/consumptions.html',
          controller: 'StatisticsConsumptionsController',
          controllerAs: 'vmStatisticsConsumptionsView',
          title: 'statistics.consumptions.tab.title',
          ncyBreadcrumb: {
              label: 'breadcrumb.equipment.statistics.consumptions',
              parent: 'statistics-general-view({equipmentId: bcEquipmentId})'
          }
        }

The controller. Indeed the important part is the activate function, it receives the data from the resolve objects and initializes the data for the view:

(function() {
  'use strict';

  angular
    .module('app.statistics')
    .controller('StatisticsConsumptionsController', StatisticsConsumptionsController);

  StatisticsConsumptionsController.$inject = ['$rootScope', '$scope', '$stateParams', '$state', 'StatisticsConsumptionsService', 'toastr', 'ngDialog',
                                              'EQUIPMENT_TYPE_ORION', 'UtilsService', 'breadCrumbData', 'initialData', 'EQUIPMENT_TYPE_UNILAV'];

  /**
   * Controller to manage all actions related to the search of consumptions
   */
  function StatisticsConsumptionsController($rootScope, $scope, $stateParams, $state, StatisticsConsumptionsService, toastr, ngDialog,
                                            EQUIPMENT_TYPE_ORION, UtilsService, breadCrumbData, initialData, EQUIPMENT_TYPE_UNILAV) {
      var vm = this;

      vm.auxCurrentPage = 0;
      vm.consumptions = null; // for the table
      vm.deleteEquipmentData = deleteEquipmentData;
      vm.deleteEquipmentDataConfirmDialog = deleteEquipmentDataConfirmDialog;
      vm.dateFormat = 'yyyy/MM/dd';
      vm.deleteWebData = deleteWebData;
      vm.deleteWebDataConfirmDialog = deleteWebDataConfirmDialog;
      vm.endDatePopupOpened = false;
      vm.exportData = exportData;
      vm.exportDataConfirmDialog = exportDataConfirmDialog;
      vm.equipmentFormulas = [];
      vm.formulaSelected = {};
      vm.isOrionEquipment = false;
      vm.openEndDatePopup = openEndDatePopup;
      vm.openStartDatePopup = openStartDatePopup;
      vm.pageSizeSelectorOptions = [];
      vm.pumps = [];
      vm.pumpSelected = {};
      vm.receiveConsumptionsDialog = receiveConsumptionsDialog;
      vm.search = search;
      vm.searchObject = {equipmentId: null, startDate: null, endDate: null, washer: null, formula: null, pump: null, page: 0, size: 0};
      vm.security = {};
      vm.startDatePopupOpened = false;
      vm.totalItems = 0;
      vm.updateAfterWasherSelection = updateAfterWasherSelection;
      vm.washers = [];
      vm.washerFormulas = [];
      vm.washerSelected = {};
      vm.webId = '';

      activate();

      /**
       * Initialization actions
       */
      function activate() {
          // Breadcrumb
          $scope.bcEquipmentId = breadCrumbData.data.equipmentId;
          $scope.bcEquipmentName = breadCrumbData.data.equipmentName;
          $scope.bcInstallationName = breadCrumbData.data.installationName;
          $scope.bcEquipmentInstallationId = breadCrumbData.data.installationId;

          vm.washers = initialData.data[0];
          vm.equipmentFormulas = initialData.data[1];
          vm.pumps = initialData.data[2];
          vm.searchObject.equipmentId = $stateParams.equipmentId;
          vm.searchObject.startDate = initialData.data[3];
          vm.searchObject.endDate = initialData.data[4];
          vm.pageSizeSelectorOptions = initialData.data[5];
          vm.isOrionEquipment = initialData.data[6] === EQUIPMENT_TYPE_ORION;

          // Combo boxes 
          vm.washerSelected = vm.washers[0];
          vm.pumpSelected = vm.pumps[0];

          // We filter the formulas for the washer selected
          vm.washerFormulas = [];
          if (vm.isOrionEquipment) {
            vm.washerFormulas = initialData.data[7];
          } else {
            for (var i = 0; i < vm.equipmentFormulas.length; i++) {
                if (vm.equipmentFormulas[i].washerNumber === vm.washerSelected.number ||
                        initialData.data[6] === EQUIPMENT_TYPE_UNILAV) {
                    vm.washerFormulas.push(vm.equipmentFormulas[i]);
                }
            }
          }

          // Security
          vm.security = initialData.data[8];

          vm.webId = initialData.data[9];

          $rootScope.cmcBaseForm.equipmentId = $stateParams.equipmentId;

          // Default page size
          vm.searchObject.size = vm.pageSizeSelectorOptions[0];

          // Formulas combo box 
          vm.formulaSelected = vm.washerFormulas[0];

          vm.auxCurrentPage = initialData.data[10].number + 1; // The front end page (Bootstrap pagination element) is one position ahead respect server pagination
          vm.searchObject.size = initialData.data[10].size;
          vm.totalItems = initialData.data[10].totalElements;
          vm.consumptions = initialData.data[10].content;
      }

      /**
       * Deletes the list of consumption records
       */
      function deleteEquipmentData() {
          $rootScope.cmcBaseForm.commActionId = $rootScope.CMC_ACTION_IDENTIFIER.CMC_ACTION_DELETE_CONSUMPTIONS;
          $scope.cc.startCommProcess($rootScope.cmcBaseForm);
      }

      /**
       * Confirm dialog to delete the list of consumptions of the equipment
       */
      function deleteEquipmentDataConfirmDialog() {
          $scope.confirmTitle = 'consumption.list.delete.equipment.data.confirm.title';
            ngDialog.openConfirm({
                    template: 'app/core/template/confirm.action.template.html',
                    scope: $scope
                }).then(
                    function() {
                        deleteEquipmentData();
                    }, function() {}
                );
      }

      /**
       * Deletes a bunch of consumption records from the server
       */
      function deleteWebData() {
          vm.searchObject.washer = vm.washerSelected.number;
          vm.searchObject.formula = vm.formulaSelected.number;
          vm.searchObject.pump = vm.pumpSelected.number;

          StatisticsConsumptionsService.deleteWebData(vm.searchObject)
            .then(
                    function() {
                        vm.auxCurrentPage = 1;
                        vm.totalItems = 0;
                        vm.consumptions = [];

                        toastr.success('consumption.list.web.data.deleted');
                    }
            );
      }

      /**
       * Opens the confirm dialog to delete the current consumptions
      */
      function deleteWebDataConfirmDialog(form) {
        if (!form.$valid) {
            return;
        }
        $scope.confirmTitle = 'consumption.list.delete.web.data.confirm.title';
        ngDialog.openConfirm({
            template: 'app/core/template/confirm.action.template.html',
            scope: $scope
        }).then(
            function() {
                deleteWebData();
            }, function() {}
        );
      }

       /**
       * Export a bunch of consumption records
       */
      function exportData() {
          vm.searchObject.washer = vm.washerSelected.number;
          vm.searchObject.formula = vm.formulaSelected.number;
          vm.searchObject.pump = vm.pumpSelected.number;

          StatisticsConsumptionsService.exportData(vm.searchObject)
            .then(
                    function(response) {
                        UtilsService.downloadFile(response.data.fileName);
                    }
            );
      }

     /**
     * Opens the confirm dialog to export the current records shown
     */
    function exportDataConfirmDialog(form) {
        if (!form.$valid) {
            return;
        }

        if (vm.totalItems <= 0) {
            toastr.warning('consumption.list.export.no.data.to.export');
            return;
        }

        $scope.confirmTitle = 'consumption.list.export.data.confirm.title';
        ngDialog.openConfirm({
            template: 'app/core/template/confirm.action.template.html',
            scope: $scope,
            resolve: {
                breadCrumbData:  ['$stateParams', 'EquipmentMainService', function($stateParams, EquipmentMainService) {
                   return EquipmentMainService.getBreadcrumbData($stateParams.equipmentId);
                }]
            },
        }).then(
            function() {
                exportData();
            }, function() {}
        );
    }

    /**
     * Opens the dialog to select the consumptions to receive
     */
    function receiveConsumptionsDialog() {
        $scope.equipmentId = $stateParams.equipmentId;
        ngDialog.open({
            name: 'receiveConsumptionsDialog',
            template: 'app/statistics/consumption/consumption.list.receive.data.dialog.html',
            className: 'ngdialog-theme-default',
            controller: 'ReceiveConsumptionsController',
            controllerAs: 'vmReceiveConsumptions',
            scope: $scope,
            resolve: {
                initialData: ['$stateParams', 'StatisticsConsumptionsService', function($stateParams, StatisticsConsumptionsService) {
                   return StatisticsConsumptionsService.getConsumptionDataToReceive($stateParams.equipmentId);
                }]
            }
        });
    }

      /**
       * Performs the search according to the filters selected
       */
      function search(form) {
          if (form != null && !form.$valid) {
              return;
          }

          // The front end page (Bootstrap pagination element) is one position ahead respect server pagination
          if (vm.auxCurrentPage !== 0) {
              vm.searchObject.page = vm.auxCurrentPage - 1;
          } else {
              vm.searchObject.page = vm.auxCurrentPage;
          }

          vm.searchObject.washer = vm.washerSelected.number;
          vm.searchObject.formula = vm.formulaSelected.number;
          vm.searchObject.pump = vm.pumpSelected.number;

          StatisticsConsumptionsService.searchConsumptions(vm.searchObject)
            .then(
                    function(response) {
                        vm.auxCurrentPage = response.data.number + 1; // The front end page (Bootstrap pagination element) is one position ahead respect server pagination
                        vm.searchObject.size = response.data.size;
                        vm.totalItems = response.data.totalElements;
                        vm.consumptions = response.data.content;
                    }
            );
      }

      /**
       * Opens the popup to select the start date
       */
      function openStartDatePopup() {
        vm.startDatePopupOpened = true;
      }

      /**
       * Opens the popup to select the end date
       */
      function openEndDatePopup() {
        vm.endDatePopupOpened = true;
      }

      /**
       * Performs the required actions when one washer is selected
       */
      function updateAfterWasherSelection() {
          vm.washerFormulas = []; 
          if (vm.washerSelected != null && vm.washerSelected.number > 0) {
              vm.washerFormulas.push(vm.equipmentFormulas[0]);
          }
          for (var i = 0; i < vm.equipmentFormulas.length; i++) {
                if (vm.equipmentFormulas[i].washerNumber === vm.washerSelected.number) {
                    vm.washerFormulas.push(vm.equipmentFormulas[i]);
                }
          }
          vm.formulaSelected = vm.washerFormulas[0];
      }
  }
})();

And the view:

<form name="consumptionSearchForm" ng-submit="vmStatisticsConsumptionsView.search(consumptionSearchForm)" novalidate>
    <!-- Buttons -->
    <div class="main-actions-bar">
        <div class="hidden-xs">
            <button class="btn btn-primary" type="submit" translate>consumption.list.search.button</button>
            <button class="btn btn-danger" ng-disabled="!vmStatisticsConsumptionsView.security.admin && vmStatisticsConsumptionsView.security.statistics != CLIENT_PERMISSIONS.TOTAL" type="button" ng-click="vmStatisticsConsumptionsView.deleteWebDataConfirmDialog(consumptionSearchForm)" translate>consumption.list.delete.web.data.button</button>
            <button class="btn btn-danger" ng-disabled="!vmStatisticsConsumptionsView.security.admin && vmStatisticsConsumptionsView.security.statistics != CLIENT_PERMISSIONS.TOTAL" type="button" ng-click="vmStatisticsConsumptionsView.deleteEquipmentDataConfirmDialog()" translate>consumption.list.delete.equipment.data.button</button>
            <button class="btn btn-success" ng-disabled="!vmStatisticsConsumptionsView.security.admin && vmStatisticsConsumptionsView.security.statistics == CLIENT_PERMISSIONS.VIEW" type="button" ng-click="vmStatisticsConsumptionsView.receiveConsumptionsDialog()" translate>consumption.list.receive.consumptions.button</button>
            <button class="btn btn-info" type="button" ng-click="vmStatisticsConsumptionsView.exportDataConfirmDialog(consumptionSearchForm)" translate>consumption.list.export.data.button</button>
        </div>
        <div class="dropdown visible-xs-block">
            <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{{'generic.group.actions' | translate}}
                <span class="caret"></span>
            </button>
            <ul class="dropdown-menu">
                <li><a ng-click="vmStatisticsConsumptionsView.search(consumptionSearchForm)" translate>consumption.list.search.button</a></li>
                <li><a disable-link="!vmStatisticsConsumptionsView.security.admin && vmStatisticsConsumptionsView.security.statistics != CLIENT_PERMISSIONS.TOTAL" ng-click="vmStatisticsConsumptionsView.deleteWebDataConfirmDialog(consumptionSearchForm)" translate>consumption.list.delete.web.data.button</a></li>
                <li><a disable-link="!vmStatisticsConsumptionsView.security.admin && vmStatisticsConsumptionsView.security.statistics != CLIENT_PERMISSIONS.TOTAL" ng-click="vmStatisticsConsumptionsView.deleteEquipmentDataConfirmDialog()" translate>consumption.list.delete.equipment.data.button</a></li>
                <li><a disable-link="!vmStatisticsConsumptionsView.security.admin && vmStatisticsConsumptionsView.security.statistics == CLIENT_PERMISSIONS.VIEW" ng-click="vmStatisticsConsumptionsView.receiveConsumptionsDialog()" translate>consumption.list.receive.consumptions.button</a></li>
                <li><a ng-click="vmStatisticsConsumptionsView.exportDataConfirmDialog(consumptionSearchForm)" translate>consumption.list.export.data.button</a></li>
            </ul>
        </div>
    </div>

    <div class="container-fluid">
        <h3 translate>generic.search.title</h3>

        <!-- Filters -->
        <div class="row">
            <!-- Start date -->
            <div class="col-lg-3 col-sm-4 col-xs-12">
                <div class="form-group">
                    <label for="startDatePicker" translate>generic.start.date</label>
                    <div class="input-group" ng-class="{'has-error': consumptionSearchForm.startDatePicker.$invalid && (consumptionSearchForm.startDatePicker.$dirty || consumptionSearchForm.$submitted)}">
                        <input type="text"
                            class="form-control"
                            id="startDatePicker"
                            name="startDatePicker"
                            uib-datepicker-popup="{{vmStatisticsConsumptionsView.dateFormat}}"
                            ng-model="vmStatisticsConsumptionsView.searchObject.startDate"
                            is-open="vmStatisticsConsumptionsView.startDatePopupOpened"
                            ng-required="true"
                            current-text="{{'date.picker.today' | translate}}"
                            clear-text="{{'date.picker.reset' | translate}}"
                            close-text="{{'date.picker.close' | translate}}"
                            alt-input-formats="['dd/MM/yyyy']"/>
                        <span class="input-group-btn">
                            <button type="button" class="btn btn-default" ng-click="vmStatisticsConsumptionsView.openStartDatePopup()"><i class="glyphicon glyphicon-calendar"></i></button>
                        </span>
                    </div>
                    <div ng-if="consumptionSearchForm.$submitted || consumptionSearchForm.startDatePicker.$dirty" ng-messages="consumptionSearchForm.startDatePicker.$error" class="msg-has-error">
                        <div ng-message="required" translate>generic.required.field</div>
                        <div ng-message="date" translate>generic.date.field</div>
                    </div>
                </div>
            </div>

            <!-- End date -->
            <div class="col-lg-3 col-sm-4 col-xs-12">
                <div class="form-group">
                    <label for="startDatePicker" translate>generic.final.date</label>
                    <div class="input-group" ng-class="{'has-error': consumptionSearchForm.endDatePicker.$invalid && (consumptionSearchForm.endDatePicker.$dirty || consumptionSearchForm.$submitted)}">
                        <input type="text"
                            class="form-control"
                            id="endDatePicker"
                            name="endDatePicker"
                            uib-datepicker-popup="{{vmStatisticsConsumptionsView.dateFormat}}"
                            ng-model="vmStatisticsConsumptionsView.searchObject.endDate"
                            is-open="vmStatisticsConsumptionsView.endDatePopupOpened"
                            ng-required="true"
                            current-text="{{'date.picker.today' | translate}}"
                            clear-text="{{'date.picker.reset' | translate}}"
                            close-text="{{'date.picker.close' | translate}}"
                            alt-input-formats="['dd/MM/yyyy']"/>
                        <span class="input-group-btn">
                            <button type="button" class="btn btn-default" ng-click="vmStatisticsConsumptionsView.openEndDatePopup()"><i class="glyphicon glyphicon-calendar"></i></button>
                        </span>
                    </div>
                    <div ng-if="consumptionSearchForm.$submitted || consumptionSearchForm.endDatePicker.$dirty" ng-messages="consumptionSearchForm.endDatePicker.$error" class="msg-has-error">
                        <div ng-message="required" translate>generic.required.field</div>
                        <div ng-message="date" translate>generic.date.field</div>
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <!-- Washer selector -->
            <div ng-if="!vmStatisticsConsumptionsView.isOrionEquipment" class="col-lg-3 col-sm-4 col-xs-12">
                <div class="form-group">
                    <label for="washerSelect" translate>consumption.list.washer.selector</label>
                    <select name="washerSelect"
                        id="washerSelect"
                        class="form-control"
                        ng-model="vmStatisticsConsumptionsView.washerSelected"
                        ng-change="vmStatisticsConsumptionsView.updateAfterWasherSelection()"
                        ng-options="washerSelected.description for washerSelected in vmStatisticsConsumptionsView.washers">
                    </select>
                </div>
            </div>

            <!-- Formula selector -->
            <div class="col-lg-3 col-sm-4 col-xs-12">
                <div class="form-group">
                    <label for="formulaSelect" translate>consumption.list.formula.selector</label>
                    <select name="formulaSelect"
                        id="formulaSelect"
                        class="form-control"
                        ng-model="vmStatisticsConsumptionsView.formulaSelected"
                        ng-options="formulaSelected.description for formulaSelected in vmStatisticsConsumptionsView.washerFormulas">
                    </select>
                </div>
            </div>

            <!-- Pump selector -->
            <div class="col-lg-3 col-sm-4 col-xs-12">
                <div class="form-group">
                    <label for="pumpSelect" translate>consumption.list.pump.selector</label>
                    <select name="pumpSelect"
                        id="pumpSelect"
                        class="form-control"
                        ng-model="vmStatisticsConsumptionsView.pumpSelected"
                        ng-options="pumpSelected.description for pumpSelected in vmStatisticsConsumptionsView.pumps">
                    </select>
                </div>
            </div>
        </div>

        <!-- Table of consumptions -->
        <h3 translate>consumption.list.table.title</h3>

        <!-- Page size selector -->
        <div class="form-group form-inline">
            <label for="pageSizeSelect" translate>consumption.list.page.size.selector</label>
            <select name="pageSizeSelect"
                id="pageSizeSelect"
                class="form-control"
                ng-model="vmStatisticsConsumptionsView.searchObject.size"
                ng-change="vmStatisticsConsumptionsView.search(consumptionSearchForm)"
                ng-options="size for size in vmStatisticsConsumptionsView.pageSizeSelectorOptions">
            </select>
        </div>

        <!-- Table with consumption results -->
        <div class="table-responsive">
             <table class="table table-hover">
                <thead>
                    <tr>
                        <th translate>consumption.list.table.head.date</th>
                        <th translate>consumption.list.table.head.washer</th>
                        <th translate>consumption.list.table.head.formula</th>
                        <th translate>consumption.list.table.head.pump</th>
                        <th translate>consumption.list.table.head.executions</th>
                        <th translate>consumption.list.table.head.volume</th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="consumption in vmStatisticsConsumptionsView.consumptions">
                        <td>{{consumption.date}}</td>
                        <td>{{consumption.washer}}</td>
                        <td>{{consumption.formula}}</td>
                        <td>{{consumption.pump}}</td>
                        <td>{{consumption.executions}}</td>
                        <td>{{consumption.volume}}</td>
                    </tr>
                </tbody>
            </table>
        </div>


        <!-- Number of results -->
        <div>
            <span>{{('generic.number.of.records' | translate) + ': ' + vmStatisticsConsumptionsView.totalItems}}</span>
        </div>

        <!-- Pagination -->
        <!-- Big screen -->
        <uib-pagination total-items="vmStatisticsConsumptionsView.totalItems"
            ng-model="vmStatisticsConsumptionsView.auxCurrentPage"
            ng-change="vmStatisticsConsumptionsView.search(consumptionSearchForm)"
            class="pagination-sm hidden-xs"
            items-per-page="vmStatisticsConsumptionsView.searchObject.size"
            max-size="10"
            force-ellipses="true"
            previous-text="{{'pagination.previous.button' | translate}}"
            next-text="{{'pagination.next.button' | translate}}">
        </uib-pagination>

        <!-- Small screen -->
        <uib-pagination total-items="vmStatisticsConsumptionsView.totalItems"
            ng-model="vmStatisticsConsumptionsView.auxCurrentPage"
            ng-change="vmStatisticsConsumptionsView.search(consumptionSearchForm)"
            class="pagination-sm visible-xs-block"
            items-per-page="vmStatisticsConsumptionsView.searchObject.size"
            max-size="3"
            previous-text="{{'pagination.previous.button' | translate}}"
            next-text="{{'pagination.next.button' | translate}}">
        </uib-pagination>
    </div>
</form>

Well, this complete example is not causing any flickering when going forward with the swipe gesture, but now comes what drives me crazy. It seems like any small change to the controller or the view makes the flickering effect appear again.

For example just remove the last line of the activate function: vm.consumptions = initialData.data[10].content; This line simply initializes the data that is displayed in the table of the view. So if this data is empty at the beginning, why is this causing this flickering effect?

Even more strange. Now leave the controller untouched, go to the view and simply remove the table displayed there:

<div class="table-responsive">
             <table class="table table-hover">
                <thead>
                    <tr>
                        <th translate>consumption.list.table.head.date</th>
                        <th translate>consumption.list.table.head.washer</th>
                        <th translate>consumption.list.table.head.formula</th>
                        <th translate>consumption.list.table.head.pump</th>
                        <th translate>consumption.list.table.head.executions</th>
                        <th translate>consumption.list.table.head.volume</th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="consumption in vmStatisticsConsumptionsView.consumptions">
                        <td>{{consumption.date}}</td>
                        <td>{{consumption.washer}}</td>
                        <td>{{consumption.formula}}</td>
                        <td>{{consumption.pump}}</td>
                        <td>{{consumption.executions}}</td>
                        <td>{{consumption.volume}}</td>
                    </tr>
                </tbody>
            </table>
        </div>

And the flickering appears again! But not only the table, keep the table and remove one of the combo boxes:

<!-- Formula selector -->
            <div class="col-lg-3 col-sm-4 col-xs-12">
                <div class="form-group">
                    <label for="formulaSelect" translate>consumption.list.formula.selector</label>
                    <select name="formulaSelect"
                        id="formulaSelect"
                        class="form-control"
                        ng-model="vmStatisticsConsumptionsView.formulaSelected"
                        ng-options="formulaSelected.description for formulaSelected in vmStatisticsConsumptionsView.washerFormulas">
                    </select>
                </div>
            </div>

And the flickers is there again. But not all of them because if I remove the first row with the date filters, then the flickering does not come up (???):

Do you have any idea? I'd appreciate any comment because I am completely lost and I'd like to get rid of this effect in iOS.

Thank you.

0 Answers
Related