8
\$\begingroup\$

I have the same functionality in two controllers and I want to refactor to place it in a shared method that both controllers can access. I was thinking on creating a separate service called "Camera" and inject that service as a dependecy into both controllers as I'm currently doing with "Login". Is this a good approach?

  .controller('pictureOfTheDamageCtrl', function ($scope, $cordovaCamera, $ionicPopup, $rootScope, $timeout, Login, $ionicLoading) {
    $rootScope.width = document.getElementsByTagName('ion-content')[0].clientWidth;

    $scope.takePicture = function () {
      var options = {
        quality: 75,
        destinationType: Camera.DestinationType.DATA_URL,
        sourceType: Camera.PictureSourceType.CAMERA,
        allowEdit: false,
        targetWidth: 1024,
        targetHeight: 567,
        encodingType: Camera.EncodingType.JPEG,
        popoverOptions: CameraPopoverOptions,
        saveToPhotoAlbum: false
      };

      $cordovaCamera.getPicture(options).then(function (imageURI) {
        $rootScope.damage = "data:image/jpeg;base64," + imageURI;
      }, function (err) {
        $ionicPopup.alert({
          title: 'Camera',
          template: 'Something went wrong: ' + err
        });
      });
    }

  })      
  .controller('pictureOfTheVehicleCtrl', function ($scope, $cordovaCamera, $ionicPopup, $rootScope, $timeout, Login, $ionicLoading) {
    $rootScope.width = document.getElementsByTagName('ion-content')[0].clientWidth;

    $scope.takePicture = function () {
      var options = {
        quality: 75,
        destinationType: Camera.DestinationType.DATA_URL,
        sourceType: Camera.PictureSourceType.CAMERA,
        allowEdit: false,
        targetWidth: 1024,
        targetHeight: 567,
        encodingType: Camera.EncodingType.JPEG,
        popoverOptions: CameraPopoverOptions,
        saveToPhotoAlbum: false
      };

      $cordovaCamera.getPicture(options).then(function (imageURI) {
        $rootScope.vehicle = "data:image/jpeg;base64," + imageURI;
      }, function (err) {
        $ionicPopup.alert({
          title: 'Camera',
          template: 'Something went wrong: ' + err
        });
      });
    }

  })
\$\endgroup\$
1
\$\begingroup\$

Looks ok, but here are some suggestions.

Your picture configuration looks the same for both controllers. You could move that out to an angular constant/value. If you anticipate the API mutating that config object, you can always shallow-copy them with Object.assign.

Next, proceed with your service. I'd move everything into it. All your controller has to do is call the API and receive the data URL. Move the ionic popup warning into the service as well for a centralized handling of the popup.

Another thing is the use of $rootScope. It's a quick way to share values, but like globals, $rootScope is modifiable everywhere. Your app is depending on data that may or may not be there and depends on changes whose origins you may not know. For small apps, that's fine as two-way binding is really handy but just in case your app becomes big, you might consider moving off data into a service/factory to draw a line between data and presentation.

.value('PICTURE_SETTINGS', {
  quality: 75,
  destinationType: Camera.DestinationType.DATA_URL,
  sourceType: Camera.PictureSourceType.CAMERA,
  allowEdit: false,
  targetWidth: 1024,
  targetHeight: 567,
  encodingType: Camera.EncodingType.JPEG,
  popoverOptions: CameraPopoverOptions,
  saveToPhotoAlbum: false
})
.factory('cameraFactory', function($cordovaCamera, $ionicPopup, PICTURE_SETTINGS){

  return {
    takePicture: function(){
      $cordovaCamera.getPicture(Object.assign({}, PICTURE_SETTINGS)).then(function(imageURI) {
        return "data:image/jpeg;base64," + imageURI;
      }, function(err) {
        $ionicPopup.alert({
          title: 'Camera',
          template: 'Something went wrong: ' + err
        });
      });
    }
  }
})
.controller('pictureOfTheDamageCtrl', function($scope, $rootScope, cameraFactory) {
  $rootScope.width = document.getElementsByTagName('ion-content')[0].clientWidth;

  scope.takePicture = function() {
    cameraFactory.takePicture().then(function(imageURI) {
      $rootScope.damage = imageURI;
    });
  }

})
.controller('pictureOfTheVehicleCtrl', function($scope, $rootScope, cameraFactory) {
  $rootScope.width = document.getElementsByTagName('ion-content')[0].clientWidth;

  $scope.takePicture = function() {
    cameraFactory.takePicture().then(function(imageURI) {
      $rootScope.vehicle = imageURI;
    });
  }

})
\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer but I cannot make it work. If I include the new PICTURE_SETTINGS value into my services.js file, then I got an "Uncaught ReferenceError: Camera is not defined". I've included the ngCordova dependency within the module signature but still same error. I've tried without the PICTURE_SETTINGS value and replacing the "Camera" properties by its numeric values and it works but the image is not displayed. \$\endgroup\$ – tribet Jan 7 '16 at 18:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.