1

This is the scenario :

<export-team>
 <ul>
  <li>
   <button buy-ticket="{{data}}" buy-callback="onBuyTicket()">buy</button>
  </li>
  <li>
   <button buy-ticket="{{data}}" buy-callback="onBuyTicket()">buy</button>
  </li>
 </ul>
</export-team>

The buyTicket directive

(function() {
  'use strict';

  angular
    .module('myApp')
    .directive('buyTicket', buyTicket);

  /** @ngInject */
  function buyTicket($parse, ngDialog, authService, APPCONFIG, $rootScope, shareToken, contestsFactory, shareCurrentTicket, shareIdSession, shareSessionAAMS, $location) {
    var vm = this; 
    var directive = {
      restrict: 'A',      
      link : function(scope, element, attributes) {

        var buyCompatible = attributes['buyCompatible'];


        function addZero(i) {
            if (i < 10) {
                i = "0" + i;
            }
            return i;
        }        

        var buyTicket = function(contest) {          

            var d = new Date();       
            var y = d.getFullYear();
            var m = addZero(d.getMonth()+1);
            var day = addZero(d.getDate());
            var h = addZero(d.getHours());
            var min = addZero(d.getMinutes());
            var s = addZero(d.getSeconds());
            var date = ''+y+m+day+h+min+s+'';
            var transactionId = $rootScope.TRANSACTIONID;

            var currentTOKEN = shareToken.get();
            var data =  {
                  idSessione:currentTOKEN, // ->TOKEN
                  userAgent:navigator.userAgent,
                  sessioneAAMS:contest.aams_session_id, 
                  gameId:APPCONFIG.GAME_ID,
                  transactionId:transactionId,
                  dateTime:date,
                  buyIn:contest.buy_in
              } 

            var dialogLoading = ngDialog.open({ 
              closeByDocument : false,
              closeByEscape : false,
              showClose : false,
              id : 'ft-modal-loading',
              controller: ['$scope', function($scope){
                $scope.bodyUrl = 'app/components/modals/body/loading.html';     
                $scope.title = 'Acquisto Ticket';
                $scope.error = 'Il sistema sta procedendo all\'acquisto del ticket';
              }]
            });




            contestsFactory.buyTicket(data).success(function(response){

              dialogLoading.close();            


              if (response.esito == "0") {    
                if (!buyCompatible) {

                  shareCurrentTicket.set(response.ticketSogei);
                  shareSessionAAMS.set(contest.aams_session_id);
                  shareIdSession.set(contest.id_session);                  
                  $location.path('my-contests/'+contest.id_contest+'/'+contest.contest_status);  
                }      

              } else {
                var message = response.descrizione;                
                var ids = ngDialog.getOpenDialogs();

               var dialogError = ngDialog.open({ 
                  id : "ft-modal-error-2",
                  controller: ['$scope', function($scope){
                    $scope.bodyUrl = 'app/components/modals/body/error.html';     
                    $scope.title = 'Errore';
                    $scope.error = message;
                  }]
                });         
              }
            })
            .error(function(){



                var dialogErrorNotEndled = ngDialog.close('ft-modal-loading');


                ngDialog.open({ 
                  id : 'ft-modal-error',
                  controller: ['$scope', function($scope){
                    $scope.bodyUrl = 'app/components/modals/body/error.html';     
                    $scope.title = 'Errore';
                    $scope.error = 'Il servizio non è attualmente disponibile';
                  }]
                });         
            })            
        }        

        var openConfirmBuyTicket = function(contest) {
          contest = JSON.parse(contest);

            if (ngDialog.isOpen('ft-modal-contest-detail')) {
              ngDialog.close('ft-modal-contest-detail');    
            };



          if (!authService.isLogged()) {
            ngDialog.open({
              controller: ['$scope', function($scope){
                $scope.bodyUrl = 'app/components/modals/body/not_logged.html';     
                $scope.title = 'Spiacenti';
                $scope.error = 'Devi essere loggato per poter partecipare ad un contest';
              }]
            }); 
          } else {
            ngDialog.openConfirm({
              controller: ['$scope', function($scope){
                $scope.title = 'CONFERMA';
                $scope.bodyUrl = 'app/components/modals/body/confirm_buy.html';
                $scope.contest_name = contest.name_contest;
                $scope.buy_in = contest.buy_in;
                $scope.currency = APPCONFIG.CURRENCY_SYMBOL;
              }],
            }).then(function (confirm) {

              buyTicket(contest);

            }, function(reject) {

            });       
          }   

        } 

        element.on('click', function(e){
          var contest = attributes['buyTicket'];
          openConfirmBuyTicket(contest);
        })               
      }
    };

    return directive;
  }

})();

The export directive

(function() {
  'use strict';

  angular
    .module('myApp')
    .directive('exportTeam', exportTeam);

  /** @ngInject */
  function exportTeam(contestsFactory, ngDialog, APPCONFIG, formatDateFactory) {
    var vm = this; 
    var directive = {
      restrict: 'AE',    
      transclude: true,  
      controller : function($scope) {
        $scope.test = function() {
          alert('hey');
        }
      },
      link : function(scope, element, attributes) {
        element.on('click', function(e){
            var ticket = attributes['exportTeam'];
            var id_session = attributes['idsession'];
            scope.openExportTeamDialog(ticket, id_session, false);
        })


        scope.openExportTeamDialog = function(ticket, aams_session_id, afterSave) {
              ngDialog.open({
                id : 'ft-modal-exportTeam-detail',
                className : 'ngdialog ngdialog-theme-default ft-dialog-exportTeam',
                  controller: ['$scope', 'contestsFactory', 'APPCONFIG', function($scope, contestsFactory, APPCONFIG){
                  $scope.title = "Aggiungi contest compatibili";
                  $scope.bodyUrl = 'app/components/modals/body/exportTeam.html';
                  $scope.contentLoading = true;
                  $scope.currency = APPCONFIG.CURRENCY_SYMBOL;
                  $scope.afterSave = afterSave;         
                  $scope.CompatibleContests = [];
                  contestsFactory.getCompatibleContests(ticket).then(function(response){
                    angular.forEach(response.data[0], function(item, i){
                      var multientryOptions = [];
                      if(item.multientry > 1) { 
                        item.isMultientry = false;
                        var n = parseInt(item.multientry);
                        for (i = 1; i <= n; i++) { 
                            multientryOptions.push({
                              text : i+" team",
                              value : i
                            })
                        }      
                        item.multientryOptions = multientryOptions;                  
                        item.multientryOptionSelected = multientryOptions[0];
                      }else{
                        item.isMultientry = true;
                      };

                    })
                    $scope.CompatibleContests = response.data[0];

                    $scope.contentLoading = false;
                  })


                  }]
              });  

        } 


        scope.openExportTeamDialog('N3E94100A725F9QG', 'M3E921013C6DCFCT', false);


      }
    };

    return directive;
  }

})();

The buy-ticket directive makes an http call, on the response i want to be able to call the onBuyTicket method of the <export> directive.

I'm trying to understand the best way to do that.

Thanks everyone

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Asso
  • 47
  • 8
  • did you have attached a controller to expose directory's api ? – Umer Hayyat Jan 21 '16 at 08:31
  • The parent should have a controller you mean – Asso Jan 21 '16 at 08:32
  • no, you can write a directive which may have a controller for exposing api to outer world. it is not consumer controller it is directive api controller. there is difference between these two. consumer controller is simply controller which consumes your directory and directory controller is a controller which holds all the methods, properties, variables you want to expose to outer world – Umer Hayyat Jan 21 '16 at 08:35
  • can you show your directory code of js? – Umer Hayyat Jan 21 '16 at 08:37
  • if you want to do it, the best way is call action from your controller by directive, i will answer you. – Maher Jan 21 '16 at 08:42
  • @UmerHayyat : sorry code is too big – Asso Jan 21 '16 at 08:46
  • So onBuyTicket should be an api method of the export directive, defined like here: http://stackoverflow.com/questions/18533370/how-to-expose-a-public-api-from-a-directive-that-is-a-reusable-component – Asso Jan 21 '16 at 08:48
  • Is this helpful? https://egghead.io/lessons/angularjs-isolate-scope-expression-binding – Vahid Moradi Jan 21 '16 at 09:00
  • Is your `buy-ticket` directive alway a child of your `export` directive? Do you intent to use the `buy-callback` attribute to specify different methods in the controller of the `export` directive? – georgeawg Jan 21 '16 at 10:13
  • - No, is not always a child of export directive. - Nope, just need one method Thanks @georgeawg – Asso Jan 21 '16 at 10:18
  • @georgeawg any suggestion ? – Asso Jan 21 '16 at 10:32

4 Answers4

0

This sample show to you how can call an function from your directive

In this sample you can see we just insert data in our directive, and then we handle the data and other action in the directive.

var app = angular.module("app", []);
        app.controller("ctrl", function ($scope) {

            $scope.dataFromYourController = [
                { name: "Concert Jennifer", value: 200 },
                { name: "007", value: 100 }
            ];

        })
        .directive("export", function () {
            var template = "<div>" +
                "<ul>" +
                "<li ng-repeat=\"array in arrays\">" +
                    "<button ng-click=\"onBuyTicket()\">buy Ticket {{array.name}}</button><hr>" +
                "</li>" +
                "</ul>" +
                "</div>";
            return {
                restrict: "E",
                template: template,
                scope: {
                    data: "="
                },
                link: function (scope, elem, attrs, ngModel) {
                    scope.arrays = scope.data;

                    scope.onBuyTicket = function () {
                      alert("calling function from directive");
                    }

                }
            };
        })
<!doctype html>
<html ng-app="app" ng-controller="ctrl">
<head>
</head>
<body>
  
    <h1>call action from your directive</h1>
    <export data="dataFromYourController"></export>


    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>  
</body>
</html>
Maher
  • 2,517
  • 1
  • 19
  • 32
  • Thanks @Maher , my need is that the onBuyTicket method to be specified in the export directive, not in the parent controller, called from the buy-ticket directive – Asso Jan 21 '16 at 09:10
  • you can use $parent property to access the parent – eesdil Jan 21 '16 at 09:25
0

Use the $parent

<button buy-ticket="{{data}}" buy-callback="$parent.onBuyTicket()">buy</button>

So the expor directive something like:

var directive = { 
 restrict: 'AE',
 template: '<ng-tansclude></ng-transclude>',
 transclude: true,
 controller : function($scope) { 
   $scope.onBuyTicket = function() { 
    alert('hey'); 
   } 
 } 
}

UPDATED:

see the plunker:

https://plnkr.co/edit/fmyJ4oPLvTiI0TzO7h1b?p=preview

It really depends what you can call and what you cannot based on the scopes... here if you would remove the scope from the export directive would work without the $parent also as export would share the same scope as the parent (main view)

eesdil
  • 1,931
  • 3
  • 16
  • 25
  • but if you have a function on the export's controller like onBuyTicket() than you should be able to access it using the $parent property, as the newly created scope's created by the export directive's scope. Can it be that you dont define transclude in your example directive? – eesdil Jan 21 '16 at 10:18
  • You mean transclude in the buy-ticket directive ? – Asso Jan 21 '16 at 10:23
  • No, you have to use transclude in the export directive. This makes it possible to call the parent controller. – eesdil Jan 21 '16 at 10:24
  • So would be like : var directive = { restrict: 'AE', transclude: true, controller : function($scope) { $scope.onBuyTicket = function() { alert('hey'); } } } And how can I call that onBuyTicket() in the buy in directive ? – Asso Jan 21 '16 at 10:28
  • thats ok, but also you have to put the transclude tag into the template. . And after you can use the $parent as it is suggested. – eesdil Jan 21 '16 at 10:30
  • Sorry, i can still do that in the link function of the buy-ticket directive ? – Asso Jan 21 '16 at 10:33
  • not sure I understand in that case. You would like to call a function in export directive if the buy-ticket is generating the buy-callback event. Or not? – eesdil Jan 21 '16 at 10:35
  • The buy-ticket directive makes an http call, on the response i want to call a method of the export directive (Note, the buy-ticket directive is not always a child directive of the export, i want to do that only if it's a child) The method can be specified in an attribute or not, that sis not important – Asso Jan 21 '16 at 10:38
0

@eesdil

var directive = {
  restrict: 'AE',    
  transclude: true,  
  controller : function($scope) {
    $scope.onBuyTicket = function() {
      alert('hey');
    }
  }
}

Ho can I call that from the buy-ticket directive ?

Asso
  • 47
  • 8
0

The best way to communicate events from a child directive to a parent directive (or controller) is to use the $emit method of the scope.

What you want to do is take an ng-click event, get additional information with an $http call, and $emit an event with the additional information to be used by your parent directive (or controller).

HTML

<button buy-ticket="data" ng-click="onBuyTicket()">buy</button>

The directive:

angular.module("myApp").directive("buyTicket", function($http) {
    function linkFn(scope,elem,attrs) {
        scope.onBuyTicket = function() {
            var buyData = scope.$eval(attrs.buyTicket);
            var url = someFunction(buyData);
            $http.get(url).then (function (response) {
                var httpData = response.data;
                scope.$emit("buyTicket.click", buyData, httpData);
            });
        };
    };
    return {
        restrict: "AE",
        link: linkFn
    };
});

In the parent controller:

$scope.$on("buyTicket.click", function (buyData, httpData) {
    console.log(buyData);
    console.log(httpData);
}); 

Notice that I used the $eval method to get the data from the variable named by the buy-ticket attribute.

When choosing a name for the event, I recommend including the name of the directive in the event's name. It makes it clear the source of the event and is unlikely to be duplicated elsewhere.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Yes, but I would wrap it into some helper function not to be bound too much to $scope.$emit. As example in angular2 you dont have $emit anymore. Maybe worth to consider rxjs for eventing. – eesdil Jan 21 '16 at 12:40