it-swarm.asia

كيفية استدعاء طريقة محددة في توجيه AngularJS؟

لدي توجيه ، إليك الرمز:

.directive('map', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        link: function($scope, element, attrs) {

            var center = new google.maps.LatLng(50.1, 14.4); 
            $scope.map_options = {
                zoom: 14,
                center: center,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            // create map
            var map = new google.maps.Map(document.getElementById(attrs.id), $scope.map_options);
            var dirService= new google.maps.DirectionsService();
            var dirRenderer= new google.maps.DirectionsRenderer()

            var showDirections = function(dirResult, dirStatus) {
                if (dirStatus != google.maps.DirectionsStatus.OK) {
                    alert('Directions failed: ' + dirStatus);
                    return;
                  }
                  // Show directions
                dirRenderer.setMap(map);
                //$scope.dirRenderer.setPanel(Demo.dirContainer);
                dirRenderer.setDirections(dirResult);
            };

            // Watch
            var updateMap = function(){
                dirService.route($scope.dirRequest, showDirections); 
            };    
            $scope.$watch('dirRequest.Origin', updateMap);

            google.maps.event.addListener(map, 'zoom_changed', function() {
                $scope.map_options.zoom = map.getZoom();
              });

            dirService.route($scope.dirRequest, showDirections);  
        }
    }
})

أرغب في الاتصال بـ updateMap() في إجراء المستخدم. زر العمل ليس في التوجيه.

ما هي أفضل طريقة للاتصال updateMap() من وحدة تحكم؟

290
mcbjam

إذا كنت ترغب في استخدام نطاقات معزولة ، يمكنك تمرير كائن تحكم باستخدام ربط ثنائي الاتجاه = لمتغير من نطاق وحدة التحكم. يمكنك أيضًا التحكم في عدة مثيلات لنفس التوجيه على صفحة لها نفس عنصر التحكم.

angular.module('directiveControlDemo', [])

.controller('MainCtrl', function($scope) {
  $scope.focusinControl = {};
})

.directive('focusin', function factory() {
  return {
    restrict: 'E',
    replace: true,
    template: '<div>A:{{internalControl}}</div>',
    scope: {
      control: '='
    },
    link: function(scope, element, attrs) {
      scope.internalControl = scope.control || {};
      scope.internalControl.takenTablets = 0;
      scope.internalControl.takeTablet = function() {
        scope.internalControl.takenTablets += 1;
      }
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="directiveControlDemo">
  <div ng-controller="MainCtrl">
    <button ng-click="focusinControl.takeTablet()">Call directive function</button>
    <p>
      <b>In controller scope:</b>
      {{focusinControl}}
    </p>
    <p>
      <b>In directive scope:</b>
      <focusin control="focusinControl"></focusin>
    </p>
    <p>
      <b>Without control object:</b>
      <focusin></focusin>
    </p>
  </div>
</div>
358
Oliver Wienand

على افتراض أن زر الإجراء يستخدم نفس وحدة التحكم $scope كتوجيه ، فقط حدد الدالة updateMap في $scope داخل وظيفة الارتباط. يمكن لوحدة التحكم الخاصة بك استدعاء هذه الوظيفة عند النقر فوق زر الإجراء.

<div ng-controller="MyCtrl">
    <map></map>
    <button ng-click="updateMap()">call updateMap()</button>
</div>
app.directive('map', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div></div>',
        link: function($scope, element, attrs) {
            $scope.updateMap = function() {
                alert('inside updateMap()');
            }
        }
    }
});

fiddle


وفقًا لتعليق @ FlorianF ، إذا كان التوجيه يستخدم نطاقًا معزولًا ، فستكون الأمور أكثر تعقيدًا. في ما يلي إحدى الطرق لجعلها تعمل: أضف سمة set-fn إلى توجيه map الذي سيسجل وظيفة التوجيه مع وحدة التحكم:

<map set-fn="setDirectiveFn(theDirFn)"></map>
<button ng-click="directiveFn()">call directive function</button>
scope: { setFn: '&' },
link: function(scope, element, attrs) {
    scope.updateMap = function() {
       alert('inside updateMap()');
    }
    scope.setFn({theDirFn: scope.updateMap});
}
function MyCtrl($scope) {
    $scope.setDirectiveFn = function(directiveFn) {
        $scope.directiveFn = directiveFn;
    };
}

fiddle

71
Mark Rajcok

على الرغم من أنه قد يكون من المغري فضح كائن على النطاق المعزول للتوجيه لتسهيل الاتصال به ، إلا أن القيام به قد يؤدي إلى تشويش رمز "السباغيتي" ، خاصة إذا كنت بحاجة إلى ربط هذا الاتصال عبر عدة مستويات (وحدة التحكم ، التوجيه ، إلى التوجيه المتداخل ، إلخ.)

لقد ذهبنا في الأصل إلى هذا المسار ، ولكن بعد إجراء المزيد من الأبحاث وجدت أنه من المنطقي وأنتج كودًا أكثر قابلية للصيانة وقابلة للقراءة لفضح الأحداث والخصائص التي سيستخدمها التوجيه للاتصال عبر خدمة ثم استخدام $ watch على خصائص تلك الخدمة في التوجيه أو أي عناصر تحكم أخرى قد تحتاج إلى الاستجابة لتلك التغييرات للاتصال.

يعمل هذا التجريد بشكل جيد للغاية مع إطار حقن التبعية الخاص بـ AngularJS ، حيث يمكنك ضخ الخدمة في أي عناصر تحتاج إلى الاستجابة لتلك الأحداث. إذا نظرت إلى ملف Angular.js ، سترى أن التوجيهات الموجودة هناك تستخدم أيضًا الخدمات و $ watch بهذه الطريقة ، فهي لا تعرض الأحداث عبر النطاق المعزول.

أخيرًا ، في حالة احتياجك للتواصل بين التوجيهات التي تعتمد على بعضها البعض ، أوصي بمشاركة وحدة تحكم بين تلك التوجيهات كوسيلة للاتصال.

ويكي AngularJS لأفضل الممارسات يذكر أيضًا هذا:

استخدم فقط. $ broadcast () و. $ emit () و. $ on () للأحداث الذرية الأحداث ذات الصلة على مستوى العالم عبر التطبيق بالكامل (مثل مصادقة المستخدم أو إغلاق التطبيق). إذا كنت ترغب في أحداث خاصة بالوحدات النمطية أو الخدمات أو التطبيقات المصغّرة ، فيجب أن تفكر في الخدمات أو أدوات التحكم في التوجيه أو Libs للجهات الخارجية

  • $ domain. $ watch () يجب أن يحل محل الحاجة إلى الأحداث
  • خدمات الحقن وطرق الاتصال مباشرة مفيدة أيضًا للاتصال المباشر
  • التوجيهات قادرة على التواصل مباشرة مع بعضها البعض من خلال وحدات تحكم التوجيه
34
Always Learning

بناءً على إجابة Oliver - قد لا تحتاج دائمًا إلى الوصول إلى الأساليب الداخلية للتوجيه ، وفي هذه الحالات قد لا ترغب في إنشاء كائن فارغ وإضافة عنصر control إلى التوجيه فقط لمنعه من إلقاء خطأ (cannot set property 'takeTablet' of undefined).

قد ترغب أيضًا في استخدام الطريقة في أماكن أخرى داخل التوجيه.

أود إضافة فحص للتأكد من وجود scope.control ، وتعيين الطرق بطريقة مماثلة لنموذج كشف الوحدة

app.directive('focusin', function factory() {
  return {
    restrict: 'E',
    replace: true,
    template: '<div>A:{{control}}</div>',
    scope: {
      control: '='
    },
    link : function (scope, element, attrs) {
      var takenTablets = 0;
      var takeTablet = function() {
        takenTablets += 1;  
      }

      if (scope.control) {
        scope.control = {
          takeTablet: takeTablet
        };
      }
    }
  };
});
15
CheapSteaks

أن نكون صادقين ، لم أكن مقتنعا حقا بأي من الإجابات في هذا الموضوع. لذلك ، إليك حلولي:

توجيه معالج (مدير) النهج

هذه الطريقة غير ملائمة لمعرفة ما إذا كان التوجيه $scope هو مشترك أو معزول

factory لتسجيل مثيلات التوجيه

angular.module('myModule').factory('MyDirectiveHandler', function() {
    var instance_map = {};
    var service = {
        registerDirective: registerDirective,
        getDirective: getDirective,
        deregisterDirective: deregisterDirective
    };

    return service;

    function registerDirective(name, ctrl) {
        instance_map[name] = ctrl;
    }

    function getDirective(name) {
        return instance_map[name];
    }

    function deregisterDirective(name) {
        instance_map[name] = null;
    }
});

رمز التوجيه ، وعادة ما أضع كل المنطق الذي لا يتعامل مع DOM داخل وحدة تحكم التوجيه. وتسجيل مثيل تحكم داخل معالجنا

angular.module('myModule').directive('myDirective', function(MyDirectiveHandler) {
    var directive = {
        link: link,
        controller: controller
    };

    return directive;

    function link() {
        //link fn code
    }

    function controller($scope, $attrs) {
        var name = $attrs.name;

        this.updateMap = function() {
            //some code
        };

        MyDirectiveHandler.registerDirective(name, this);

        $scope.$on('destroy', function() {
            MyDirectiveHandler.deregisterDirective(name);
        });
    }
})

رمز القالب

<div my-directive name="foo"></div>

الوصول إلى مثيل وحدة التحكم باستخدام factory وتشغيل الطرق المكشوفة للجمهور

angular.module('myModule').controller('MyController', function(MyDirectiveHandler, $scope) {
    $scope.someFn = function() {
        MyDirectiveHandler.get('foo').updateMap();
    };
});

نهج الزاوي

أخذ ورقة من كتاب الزاوي على كيفية التعامل معها

<form name="my_form"></form>

باستخدام $ parse وتسجيل جهاز التحكم على نطاق $parent. لا تعمل هذه التقنية على توجيهات $scope المعزولة.

angular.module('myModule').directive('myDirective', function($parse) {
    var directive = {
        link: link,
        controller: controller,
        scope: true
    };

    return directive;

    function link() {
        //link fn code
    }

    function controller($scope, $attrs) {
        $parse($attrs.name).assign($scope.$parent, this);

        this.updateMap = function() {
            //some code
        };
    }
})

الوصول إليه داخل جهاز التحكم باستخدام $scope.foo

angular.module('myModule').controller('MyController', function($scope) {
    $scope.someFn = function() {
        $scope.foo.updateMap();
    };
});
12
Mudassir Ali

متأخرة بعض الشيء ، ولكن هذا حل ذو نطاق معزول و "أحداث" لاستدعاء دالة في التوجيه. هذا الحل مستوحى من هذا SO post by satchmorun ويضيف وحدة نمطية وواجهة برمجة تطبيقات.

//Create module
var MapModule = angular.module('MapModule', []);

//Load dependency dynamically
angular.module('app').requires.Push('MapModule');

إنشاء واجهة برمجة تطبيقات للتواصل مع التوجيه. يضيف addUpdateEvent حدثًا إلى صفيف الأحداث ويدعو updateMap كل وظيفة حدث.

MapModule.factory('MapApi', function () {
    return {
        events: [],

        addUpdateEvent: function (func) {
            this.events.Push(func);
        },

        updateMap: function () {
            this.events.forEach(function (func) {
                func.call();
            });
        }
    }
});

(ربما يتعين عليك إضافة وظيفة لإزالة الحدث.)

في التوجيه ، قم بتعيين مرجع إلى MapAPI وإضافة $ scope.updateMap كحدث عند استدعاء MapApi.updateMap.

app.directive('map', function () {
    return {
        restrict: 'E', 
        scope: {}, 
        templateUrl: '....',
        controller: function ($scope, $http, $attrs, MapApi) {

            $scope.api = MapApi;

            $scope.updateMap = function () {
                //Update the map 
            };

            //Add event
            $scope.api.addUpdateEvent($scope.updateMap);

        }
    }
});

في وحدة التحكم "الرئيسية" ، أضف مرجعًا إلى MapApi واتصل فقط بـ MapApi.updateMap () لتحديث الخريطة.

app.controller('mainController', function ($scope, MapApi) {

    $scope.updateMapButtonClick = function() {
        MapApi.updateMap();    
    };
}
10
AxdorphCoder

يمكنك تحديد سمة DOM التي يمكن استخدامها للسماح للتوجيه بتحديد وظيفة في النطاق الأصل. يمكن للنطاق الأصل استدعاء هذه الطريقة كأي طريقة أخرى. هنا الغطاس. وأدناه هو رمز ذات الصلة.

clearfn هي سمة موجودة في عنصر التوجيه حيث يمكن للنطاق الأصل أن يمرر خاصية النطاق التي يمكن أن يحددها التوجيه بعد ذلك إلى دالة تنجز السلوك المطلوب.

<!DOCTYPE html>
<html ng-app="myapp">
  <head>
    <script data-require="[email protected]*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <style>
      my-box{
        display:block;
        border:solid 1px #aaa;
        min-width:50px;
        min-height:50px;
        padding:.5em;
        margin:1em;
        outline:0px;
        box-shadow:inset 0px 0px .4em #aaa;
      }
    </style>
  </head>
  <body ng-controller="mycontroller">
    <h1>Call method on directive</h1>
    <button ng-click="clear()">Clear</button>
    <my-box clearfn="clear" contentEditable=true></my-box>
    <script>
      var app = angular.module('myapp', []);
      app.controller('mycontroller', function($scope){
      });
      app.directive('myBox', function(){
        return {
          restrict: 'E',
          scope: {
            clearFn: '=clearfn'
          },
          template: '',
          link: function(scope, element, attrs){
            element.html('Hello World!');
            scope.clearFn = function(){
              element.html('');
            };
          }
        }
      });
    </script>
  </body>
</html>
5
Trevor

مجرد استخدام نطاق. $ الوالد لربط وظيفة تسمى وظيفة التوجيه

angular.module('myApp', [])
.controller('MyCtrl',['$scope',function($scope) {

}])
.directive('mydirective',function(){
 function link(scope, el, attr){
   //use scope.$parent to associate the function called to directive function
   scope.$parent.myfunction = function directivefunction(parameter){
     //do something
}
}
return {
        link: link,
        restrict: 'E'   
      };
});

في HTML

<div ng-controller="MyCtrl">
    <mydirective></mydirective>
    <button ng-click="myfunction(parameter)">call()</button>
</div>
2
ramon prata

يمكنك إخبار اسم الطريقة بالتوجيه لتحديد ما تريد الاتصال به من وحدة التحكم ولكن دون عزل النطاق ،

angular.module("app", [])
  .directive("palyer", [
    function() {
      return {
        restrict: "A",
        template:'<div class="player"><span ng-bind="text"></span></div>',
        link: function($scope, element, attr) {
          if (attr.toPlay) {
            $scope[attr.toPlay] = function(name) {
              $scope.text = name + " playing...";
            }
          }
        }
      };
    }
  ])
  .controller("playerController", ["$scope",
    function($scope) {
      $scope.clickPlay = function() {
        $scope.play('AR Song');
      };
    }
  ]);
.player{
  border:1px solid;
  padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div ng-controller="playerController">
    <p>Click play button to play
      <p>
        <p palyer="" to-play="play"></p>
        <button ng-click="clickPlay()">Play</button>

  </div>
</div>
2
Naveen raj

اختبارنأمل أن يساعد هذا شخص ما.

نهجي البسيط (فكر في العلامات كرمزك الأصلي)

<html>
<div ng-click="myfuncion"> 
<my-dir callfunction="myfunction">
</html>

<directive "my-dir">
callfunction:"=callfunction"
link : function(scope,element,attr) {
scope.callfunction = function() {
 /// your code
}
}
</directive>
1
Santosh Kumar

ربما ليس هذا هو الخيار الأفضل ، ولكن يمكنك القيام بـ angular.element("#element").isolateScope() أو $("#element").isolateScope() للوصول إلى نطاق و/أو جهاز التحكم في التوجيه الخاص بك.

0
Alex198710

سيكون الحل التالي مفيدًا عندما يكون لديك وحدات تحكم (الأصل والتوجيه (معزولة)) بتنسيق 'controller As'

قد يجد شخص ما هذا مفيدًا ،

التوجيه:

var directive = {
        link: link,
        restrict: 'E',
        replace: true,
        scope: {
            clearFilters: '='
        },
        templateUrl: "/temp.html",
        bindToController: true, 
        controller: ProjectCustomAttributesController,
        controllerAs: 'vmd'
    };
    return directive;

    function link(scope, element, attrs) {
        scope.vmd.clearFilters = scope.vmd.SetFitlersToDefaultValue;
    }
}

تحكم التوجيه:

function DirectiveController($location, dbConnection, uiUtility) {
  vmd.SetFitlersToDefaultValue = SetFitlersToDefaultValue;

function SetFitlersToDefaultValue() {
           //your logic
        }
}

كود html:

      <Test-directive clear-filters="vm.ClearFilters"></Test-directive>
    <a class="pull-right" style="cursor: pointer" ng-click="vm.ClearFilters()"><u>Clear</u></a> 
//this button is from parent controller which will call directive controller function
0
Raunak Mali

كيفية الحصول على وحدة تحكم التوجيه في وحدة تحكم صفحة:

  1. اكتب توجيهًا مخصصًا للحصول على مرجع إلى وحدة تحكم التوجيه من عنصر DOM:

    angular.module('myApp')
        .directive('controller', controller);
    
    controller.$inject = ['$parse'];
    
    function controller($parse) {
        var directive = {
            restrict: 'A',
            link: linkFunction
        };
        return directive;
    
        function linkFunction(scope, el, attrs) {
            var directiveName = attrs.$normalize(el.prop("tagName").toLowerCase());
            var directiveController = el.controller(directiveName);
    
            var model = $parse(attrs.controller);
            model.assign(scope, directiveController);
        }
    }
    
  2. استخدامه في html وحدة تحكم الصفحة:

    <my-directive controller="vm.myDirectiveController"></my-directive>
    
  3. استخدم وحدة التحكم في التوجيه في وحدة تحكم الصفحة:

    vm.myDirectiveController.callSomeMethod();
    

ملاحظة: يعمل الحل المعطى فقط لوحدات تحكم توجيهات العناصر (يتم استخدام اسم العلامة للحصول على اسم التوجيه المطلوب).

0
Robert J