0

Assuming a typical Ionic action sheet service call:

app.controller('MainCtrl', function($scope, $ionicActionSheet) {
  $scope.showDetails = function() {
    $ionicActionSheet.show({
     buttons: [
       { text: 'Complete' }
     ],
     destructiveText: 'Delete',
     titleText: 'Update Todo',
     cancelText: 'Cancel',
     buttonClicked: function(index) {
       return true;
     }
   });
  }
})

... how can I make the actions more diverse by calling methods from two different controllers? Say I have a controller that loads content and one that loads a comment modal, I might want to call their respective methods like so:

buttonClicked: function(index) {
   if (index == 0) {
       // call method from controller 1
   } else if (index == 1) {
       // call method from controller 2
   }
 }

Given the controllers' isolated scopes, I cannot simply call $scope.scopeMethod() like I otherwise might. I've looked into $broadcast and $emit, but those techniques seem like pollution of $rootScope and otherwise inefficient.

Based on attempted solutions below, I've put together a simple demo: http://codepen.io/anon/pen/yYgPXQ

Thanks much.

Community
  • 1
  • 1
isherwood
  • 58,414
  • 16
  • 114
  • 157

2 Answers2

1

Not really sure exactly what you are needing but I think what you want is a service method to wrap the action sheet service call:

app.factory('myActions', function ($ionicActionSheet) {
    function showActionSheet(params, callback) {
        $ionicActionSheet.show({
            buttons: [{
                text: params.text
            }],
            destructiveText: params.action,
            titleText: params.title,
            cancelText: 'Cancel',
            buttonClicked: function (index) {
               if(callback){
                   callback();
               }
               return true;
            }
        });

    }

    return showActionSheet;

});

In controller:

$scope.showDetails = function() {
   myActions({text:'Delete'}, $scope.doSomething);
}

$scope.doSomething = function(){
   alert('I did it!');
}

If this isn't quite what you want regarding the button callback...events aren't horrible if not abused or button callback could also be wired to other service methods that might be injected in the controllers

charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • This looks like a good start, but I'm not clear on how the callback can have method calls from multiple controllers. Say the `buttonClicked` function needs to call `$scope.someMethod()` from each of two controllers. – isherwood Sep 28 '15 at 16:57
  • Can those controller methods be ported to a service? `$scope.someMethod = anotherService.someMethod`. Also are those methods updating data that is in service(s)? – charlietfl Sep 28 '15 at 16:59
  • I'm considering that. It might be helpful if you explained a bit more in your answer. – isherwood Sep 28 '15 at 20:56
  • Not sure what to explain though. Not sure what your methods do. I'm not familiar at all with ionic and this particular service so not really sure what it does – charlietfl Sep 28 '15 at 21:02
  • More familiar though with using services to keep controllers as lean as possible and just reference service functions in controllers whenever there is a need to share those methods – charlietfl Sep 28 '15 at 21:03
  • Fair enough. I'll chew on it some more. – isherwood Sep 28 '15 at 21:04
  • If viable to throw a plunker together that outlines the issue maybe that would help – charlietfl Sep 28 '15 at 21:07
1

If I understand the question you want to use different methods according to the action of the action sheet.

I would use a service for that. In angular services are:

Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.

Technically $ionicActionSheet is a service.

Services are singleton so, once created, they can be used within your application and, eventually, can share data as well.

The easiest way to create a service is:

app.factory('myService', function() {

    var factory = {}; 

    factory.method1 = function() {
            //..
        }

    factory.method2 = function() {
            //..
        }

    return factory;
});

Here we've created an object which exports 2 methods: method1 and method2. Once you've defined your service you can inject it in your controller and use its members:

app.controller('MainCtrl', function($scope, $ionicActionSheet, myService) {
  $scope.showDetails = function() {
    $ionicActionSheet.show({
     buttons: [
       { text: 'Complete' }
     ],
     destructiveText: 'Delete',
     titleText: 'Update Todo',
     cancelText: 'Cancel',
     buttonClicked: function(index) {
    myService.method1();
        return true;
     }
   });
  }
});

The new service myService is injected here:

app.controller('MainCtrl', function($scope, $ionicActionSheet, myService)

and it's called when the button is clicked:

myService.method1();

Sometimes you might find services created with the keywork .service:

app.service('myService', function() {

}

For the differences you can read more here.

If want to see a working example you can check this plunker.

dataService is a service which returns an array of object which will be shown in your view. When the users presses the complete button dataService.markAsComplete(id) will be called. This method will set the element of the array as completed. Same thing will happen when you press delete. This time dataService.deleteCity(id) will be called and the element in the array will be marked as deleted.

Your $scope.showDetails would look like this:

$scope.showDetails = function(id) {
   $ionicActionSheet.show({
     buttons: [{
       text: 'Complete'
     }],
     destructiveText: 'Delete',
     titleText: 'Update Todo',
     cancelText: 'Cancel',
     buttonClicked: function(index) {
     if (index === 0)
     {
         $scope.cities = dataService.markAsComplete(id);
         return true;
     } 
     return false;
   },
   destructiveButtonClicked : function() {
       $scope.cities = dataService.deleteCity(id);
       return true;
   }      
});

UPDATE:

Following our conversation I've create a codepen where you can see how an action sheet calls a services, fetches some data, opens a modal which shows the data.

Your controller depends on some services: $ionicActionSheet, $ionicModal and our custom CommentSrvc (those services have been injected):

.controller('AppCtrl', function($scope, $ionicActionSheet, $ionicModal, CommentSrvc) {
     $scope.modal = null;
     $scope.comments = [];
}); 

As you can see it defines 2 elements: our modal and a list of comments which will be fetched by the service.

The action sheet will open a modal:

$ionicActionSheet.show({
  titleText: 'My Title',
  buttons: [{
    text: 'Upload'
  }, {
    text: 'Comments'
  }],
  buttonClicked: function(index) {
    if (index == 0) {
      // Upload
      return false;
    } else if (index == 1) {
      // Comments
      $scope.openModal();
    }

    return true;
  },
  cancelText: 'Cancel',
  cancel: function() {
    console.log('CANCELLED');
  }
});

as you can see in $scope.openModal();

The modal has been created before:

  function createModal() {
    $ionicModal.fromTemplateUrl('comments-modal.html', {
      scope: $scope,
      animation: 'slide-in-up'
    }).then(function(modal) {
      $scope.modal = modal;
    });
  }

and saved in our scope.

Now, when the modal is opened (before showing) it will call the service, fetch the data and put the array of data in the $scope.comments list, as you can see here:

$scope.openModal = function() {
    CommentSrvc.fetchData()
      .then(function(result) {
        console.log(result);
        $scope.comments = result;
        $scope.modal.show();
      })
      .catch(function(reason) {
        $scope.comments = [];
        // Show error here!     
      });
};

CommentSrvc.fetchData() will return a promise cause, presumably, we're going to call some sort of $http service there. If the operation is successful the call back (see .then branch) will feed the returned data in $scope.comments and open the modal: $scope.modal.show().

The service does not do much here. It's just exposing a method fetchData which returns an array of items.
I've used a promise cause promises can be chained and $http returns promises, anyway:

  function fetchData() {
    var deferred = $q.defer();

    var data = [{your data}];

    deferred.resolve(data);

    return deferred.promise;
  }

Last I've changed your modal comments-modal.html using a directive ng-repeat to show all the data stored in $scope.comments:

<div class="item item-avatar" href="#" ng-repeat="comment in comments">
    <img src="../img/{{comment.image}}">
    <h2>{{comment.title}}</h2>
    <p>{{comment.body}}</p>
</div>
LeftyX
  • 35,328
  • 21
  • 132
  • 193
  • Thank you for the very thorough answer. This is along the lines of the followup suggestion by charlietfl. My remaining struggle is figuring out where the modal methods live. If I call the modal in the service method, am I calling methods inside the service, or in the controller? What does that look like? – isherwood Sep 29 '15 at 14:38
  • I don't think you should call the modal in your service. The modal is part of the controller and it should live there. The modal is in the controller and it should call the service. The controller should get the result and update the UI. – LeftyX Sep 29 '15 at 14:58
  • @isherwood: any feedback on this? Cheers. – LeftyX Sep 30 '15 at 13:09
  • I know it's the right approach, but I haven't been able to get it to work. First person to show a modal opening from a service between controllers gets the pot o' gold. Here's a starter pen: http://codepen.io/anon/pen/yYgPXQ – isherwood Sep 30 '15 at 14:01
  • [Here](http://codepen.io/anon/pen/EVZooW?editors=101) it is. Good luck with that. You're going to face a hell of a lot of problems with that. Cheers. – LeftyX Sep 30 '15 at 15:49
  • It seems we have a misunderstanding. I'm trying to implement your approach. You seem to think I'm trying to direct you otherwise. That's not the case. I'm looking to take your advice. – isherwood Sep 30 '15 at 16:04
  • My bad. I've updated my answer with a link to a [codepen](http://codepen.io/anon/pen/VvPqKM?editors=101) and some more info how to integrate all those pieces. Hope it helps. Cheers. – LeftyX Oct 01 '15 at 10:43
  • While I greatly appreciate your substantial effort, one piece is still missing... the second controller. My question specifically asks how to call methods from two separate controllers in the action sheet. In my case, a page controller and a separate comments controller. Right now I have all comment handling in the page controller. The goal is to pull it out into its own file. – isherwood Oct 01 '15 at 13:05