Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UI Bootstrap checkbox and radio slow on ipad

Trying to implement Checkbox and Radio buttons from http://angular-ui.github.io/bootstrap/ but it is very slow (about a second) to react.

Is there something I can do to make it react more quickly? Or another library that does the same thing more reliably?


EDIT: Demo ... and jsFiddle source

The demo loads bootstrap ui, and fastclick, which is initialised in one area and not the other. You can see the input fields behave as expected - fast with fastclick, slow without. The toggle buttons behave slowly everywhere.

angular.module('MyApp', ['ui.bootstrap']);

function EditingPageCtrl($scope) {
    $scope.radioModelA = undefined;
    $scope.radioModelB = undefined;
    $scope.fast1 = "this field works quickly, because of fastclick...";
    $scope.fast2 = "this field is slow, because no fastclick";
    $scope.$watch('radioModelA', function (newValue, oldValue) {
        //alert(newValue);    
    });
}
like image 263
Billy Moon Avatar asked Jun 26 '14 16:06

Billy Moon


1 Answers

Internally, the btn-radio directive is attaching a click handler via JavaScript. FastClick doesn't hijack the touch event and trigger a click because FastClick doesn't support labels. Here is the btnRadio source:

angular.module('ui.bootstrap.buttons', [])

  .constant('buttonConfig', {
    activeClass:'active',
    toggleEvent:'click'
  })

  .directive('btnRadio', ['buttonConfig', function (buttonConfig) {
  var activeClass = buttonConfig.activeClass || 'active';
  var toggleEvent = buttonConfig.toggleEvent || 'click';

  return {

    require:'ngModel',
    link:function (scope, element, attrs, ngModelCtrl) {

      var value = scope.$eval(attrs.btnRadio);

      //model -> UI
      scope.$watch(function () {
        return ngModelCtrl.$modelValue;
      }, function (modelValue) {
        if (angular.equals(modelValue, value)){
          element.addClass(activeClass);
        } else {
          element.removeClass(activeClass);
        }
      });

      //ui->model
      element.bind(toggleEvent, function () {
        if (!element.hasClass(activeClass)) {
          scope.$apply(function () {
            ngModelCtrl.$setViewValue(value);
          });
        }
      });
    }
  };
}])

Solution 1

ngTouch hooks into the ng-click directive. So... it's a little janky, but if you use ngTouch instead of FastClick, you can get improved performance by adding an ng-click attribute:

 <label ng-model="radioModelA" ng-click="radioModelA=true" btn-radio="true" class="btn btn-silver">Yes</label>
 <label ng-model="radioModelA" ng-click="radioModelA=false" btn-radio="false" class="btn btn-silver">No</label>

Solution 2

A more elegant solution is to inject btn-radio's configuration constant and add a touch event:

.config(function(buttonConfig) {
    buttonConfig.toggleEvent = 'touchstart click';
});

Solution 3

Use <button> elements instead of <label>s and you can use either FastClick or ngTouch to avoid the mobile browser delay.


Also check this out: the vanilla ui-bootstrap demo seems faster than yours, because of the way that it's styled.

like image 200
Gil Birman Avatar answered Oct 16 '22 11:10

Gil Birman