【问题标题】:Angular JS directives with isolate scopes and internal controllers具有隔离范围和内部控制器的 Angular JS 指令
【发布时间】:2016-02-17 17:39:42
【问题描述】:

我已经有一段时间没有接触过 Angular js 了,当我写的时候,我们使用了 typescript 的风格,这对我来说非常简单。现在想写vanilla angular js,感觉有点迷茫。

问题:
我有一个指令,在其隔离范围内有一些变量,我基本上想绑定到这个指令,该指令是在每个<ul> 内部产生的一个点击事件。我尝试直接在 ng-click 上绑定一个函数并使用链接元素等。点击时绑定,但似乎我做错了什么,因为第一种方式没有任何反应,第二种方式双向绑定变量未定义。

这里是: https://plnkr.co/edit/OOBMs8pYONLjUE9lQXla?p=preview

activity-header.html

<div>
<h4>
Activity Name: {{activity.activity_name}}
</h4>

<h6>    
Activity Start Date: {{activity.activity_start_date}}
</h6>

<h6>        
Activity End Date: {{activity.activity_end_date}}
</h6>

<h6>
Participants: {{activity.participants}}
</h6>
</div>

activity-header.js

var app = angular.module('mainApp');

/*
app.controller('activityHeaderCtrl', ['$scope', function($scope) {
    $scope.activity='';
    $scope.msg='';
    $scope.check = function() {
            alert($scope.msg);
        };
}]);
*/

app.directive('activityHeader', function() {
    return {
        restrict: 'AE',
        templateUrl: 'activity-header.html',
        controller: ['$scope', Controller],
        scope: {
            activity:'=',
            msg:'='         
        },
        link: function($scope, $element, attrs) {
        $element.bind('click', function($scope) {
            alert($scope.msg);
        })}
    };        
    function Controller($scope) {
        $scope.check = function() {
            alert($scope.msg);
        };

    }
});

index.html

<html ng-app="mainApp">

    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
    <script src="script-main.js"></script>
    <script src="activity-header.js"></script>

<body>

    <div ng-controller="ctrl">

        <h1>
            Major Bla bla System    
        </h1>

        <ul>        
            <li ng-repeat="x in events">                
                <div activity-header activity="x" msg="greetingsfriend" ng-click="check()"></div>
            </li>
        </ul>    

        <h6>
            Beta v.0.2
        </h6>

    </div>

</body>

</html>

script-main.js

var app = angular.module('mainApp', []);

app.controller('ctrl', function ($scope) {

    //$scope.events = ["Elections", "Protest", "Martial Law", "X-mas Celebration"];
    $scope.events = [
        {"activity_name": "Elections", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1453"},
        {"activity_name": "Martial Law", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1821"},
        {"activity_name": "Protest", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1940"},
        {"activity_name": "X-mas Celebration", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "2009"}
    ];

    $scope.salute = function () {
        alert('hello there');
    };

});

(顺便说一句,我使用的是 Mozilla Firefox,否则我必须在 node.js 上托管它以获取相同的来源策略,不知道如何在 chrome/internet explorer 中将其关闭)。

【问题讨论】:

  • greetingsfriend 应该是什么?它没有在控制器中定义为能够双向绑定到隔离范围。请注意,由于重复使用 var app 而没有 &lt;head&gt;,演示会引发错误
  • 天哪,我希望那是字面意思...我忘了''?
  • 如果你希望它是一个字符串,你需要在隔离范围内使用@ 而不是=
  • 感谢您的反馈。关于如何处理点击的任何想法?

标签: angularjs controller directive isolate-scope


【解决方案1】:

取决于你想要获得什么。

例如,如果您想在单击时绑定指令的功能,则不需要链接功能。您可以简单地使用 ng-click 绑定对外部 div 的单击。看这个例子:http://jsbin.com/sanova/edit?html,js,output

但是如果你想在你的父控制器上调用一个函数,你需要通过你的指令上的一个属性来传递对该函数的引用。看这个例子:http://jsbin.com/peqasu/edit?html,js,output

如您所见,我在两个示例中都在指令模板的外部 div 上放置了一个 ng-click 指令。单击时,将调用指令控制器上的检查功能。在第一个示例中,只是简单地提醒消息,在第二个示例中调用 greetFunction 作为指令的属性传递。

【讨论】:

  • 你帮了我很多忙。我花了一些时间才弄清楚你的意思,但反馈非常好。现在的引用非常清晰,并且 check() 在该范围内根本无法访问,但是在您提到的指令级别,它现在可以找到它。最后一件事,如果我不要求太多。我什么时候直接使用该函数,什么时候使用链接:元素绑定等。两者都完全好吗?谢谢!!!
  • 我添加了另一个答案来解释这个概念
【解决方案2】:

关于如何处理点击的任何想法?

您的问题是您使用$scope 作为单击处理函数中第一个参数的名称。该名称将覆盖链接函数中的 $scope 参数。

    //BAD
    link: function($scope, $element, attrs) {
    $element.bind('click', function($scope) {
        alert($scope.msg);
    })}

像这样修复你的代码:

    //GOOD
    link: function(scope, element, attrs) {
        element.on('click', function clickHandler(event) {
            console.log(scope.msg);
        });
    }

AngularJS jqLite 使用JQuery Event Object 作为第一个参数而不是$scope 调用点击处理程序。


这是处理指令事件的正确方法吗?
为什么 ng-click 事件无法调用我在指令控制器中的函数?

ng-click 指令绑定到父作用域中的函数。

要将点击事件绑定到指令范围内的函数,请使用element.on()。这就是ng-click 从浏览器获取事件的方式。看source code

【讨论】:

  • 首先感谢您的帮助,非常感谢!我将标记为答案,但你能向我解释一下这是处理指令事件的正确方法吗?
  • 我的意思是为什么 ng-click 事件不能调用我在指令控制器中的函数? -> 函数控制器($scope) { $scope.check = function() { alert($scope.msg); };
  • ng-click 指令绑定到父作用域上的函数。查看我的更新。
【解决方案3】:

首先您需要了解智能组件和哑组件(指令)之间的区别。

这里你可以读到一篇很好的文章,解释了Redux的创建者Dan Abramov写的smart和dumb组件的区别:https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

当您了解这种差异时,您可以尝试编写更多愚蠢的组件和不那么聪明的组件。这意味着您需要保留父组件上的所有逻辑并将其传递给您的哑组件。

在前面的例子中,我们只在第二个例子中这样做。事实上,在该示例中,我们将逻辑(我们的检查函数)保留在父组件中,并且只传递对它的引用。以这种方式,活动标题组件不知道单击完成后要做什么。它只知道它必须调用一个函数,这个函数做什么不是它的问题。

这是在复杂应用程序中使用的好方法,因此您可以以不同的方式重用组件,只需更改引用函数。

【讨论】:

  • 感谢您的解释和文章!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-04
  • 2019-10-21
相关资源
最近更新 更多