javascript 如何将多个值传递给 Angularjs 指令?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15558445/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 01:11:41  来源:igfitidea点击:

How do I pass many values to an Angularjs directive?

javascriptangularjsangularjs-directive

提问by Spencer

I'm creating a reusable bit of html via a directive. The html would have a few variables that I want passed from the original scope. This is done easily by declaring attributes on the directive, then creating an isolate scope and capturing them. The question is, is there a better way to do this for a larger number of variables? I had thought of passing in an object like {firstAttr: $scope.one, secondAttr: $scope.two...}and picking this object apart to get each piece. This works the first time, but the two-way databinding doesn't work (even using the '=').

我正在通过指令创建可重用的 html 位。html 会有一些我想从原始范围传递的变量。这可以通过在指令上声明属性,然后创建隔离范围并捕获它们来轻松完成。问题是,对于大量变量,是否有更好的方法来做到这一点?我曾想过传入一个对象,{firstAttr: $scope.one, secondAttr: $scope.two...}然后把这个对象拆开来得到每一块。这是第一次有效,但双向数据绑定不起作用(即使使用“=”)。

The problem is the thing that is bound is the object, not each of the individual parts of the object. Could I maybe use the compile function in the directive to add each of the attributes to the element or something? so:

问题是绑定的是对象,而不是对象的每个单独部分。我可以使用指令中的 compile 函数将每个属性添加到元素或其他东西吗?所以:

<mydirective databinding="{one:'first one', two:'second one'}">

would be translated into:

会被翻译成:

<mydirective one="first one" two="second one">

That way my databinding would work as expected by capturing the attributes in the directive. How would I go about accomplishing that design, or is there just another way completely to do this?

这样我的数据绑定就可以通过捕获指令中的属性来按预期工作。我将如何完成该设计,或者是否有另一种方法可以完全做到这一点?

回答by Scottmas

The databinding directive idea is an interesting one but it's not the way I would do it since I believe you'd run into directive priority issues, plus the fact that it's very non-standard and would make your code hard to follow for future programmers. There's several ways to do this so I'll discuss 3 different solutions I've used.

数据绑定指令的想法很有趣,但我不会这样做,因为我相信您会遇到指令优先级问题,而且它非常不标准并且会使您的代码难以为未来的程序员遵循这一事实。有几种方法可以做到这一点,所以我将讨论我使用过的 3 种不同的解决方案。

Solution 1

方案一

If you only need one way data binding, the simplest solution is to use angular's scope.$eval function on the string representation of the object inside your directive after interpolating any simple scope variables on it using {{}}. The string representation doesn't even have to be valid JSON, since you'll notice in the example below I don't include quotes around the object keys.

如果您只需要一种方式数据绑定,最简单的解决方案是在使用 {{}} 插入任何简单范围变量之后,在指令内对象的字符串表示上使用 angular 的 scope.$eval 函数。字符串表示甚至不必是有效的 JSON,因为您会注意到在下面的示例中我没有在对象键周围包含引号。

In the view:

在视图中:

<div databinding="{one:'first', two:{{scopeVar}}, complex:[1,2, "Hi"]}"></div>

And in the javascript:

在 javascript 中:

app.directive('databinding', function () {
   return{
      link: function (scope, elm, attrs) {

        console.debug(scope.$eval(attrs['databinding']));

      }
   }
});

Solution 2

解决方案2

Another one-way data binding solution is to create an option object inside the controller and pass it to the directive using "@" (or even "="):

另一种单向数据绑定解决方案是在控制器内创建一个选项对象,并使用“@”(甚至“=”)将其传递给指令:

In the controller:

在控制器中:

$scope.options = {one: "first, two: "second"};

In the view:

在视图中:

<div databinding="options"></div>

And in the javascript:

在 javascript 中:

app.directive('databinding', function () {
   return{
      scope: {

        options: "@" //Can also use = here

      },
      link: function (scope, elm, attrs) {

        console.log(scope.options);

      }
   }
});

Solution 3

解决方案3

If you do need two way data binding, you're mostly out of luck, as there's no elegant way to do it. HOWEVER, if you're in the market for hackish solutions, you can accomplish two way data binding with a method very similar to solution 2 but with a change to the option object.

如果您确实需要双向数据绑定,那么您很不走运,因为没有优雅的方法来做到这一点。但是,如果您在市场上寻找 hackish 解决方案,您可以使用与解决方案 2 非常相似的方法来完成双向数据绑定,但对选项对象进行了更改。

Instead of declaring an option object containing simple primitive data types like strings, create a dummy object inside the option object, which you then declare your variables inside of. Doing it this way, changes to scope variables in your controller will also be realized inside the directive, as demonstrated through the timeouts.

与其声明一个包含简单原始数据类型(如字符串)的选项对象,不如在选项对象中创建一个虚拟对象,然后在其中声明变量。这样做,控制器中作用域变量的更改也将在指令内部实现,如超时所示。

Controller:

控制器:

$scope.someScopeVar = "Declared in controller"    

$scope.options = {
  dummy: {
     one: $scope.someScopeVar,
     two: "second"
  }
}

window.setTimeout(function(){

  $scope.someScopeVar = "Changed in controller";

}, 2000)

View:

看法:

<div databinding="options"></div>

Directive:

指示:

app.directive('databinding', function () {
   return{
      scope: {
        options: "=" //You need to use = with this solution
      },
      link: function (scope, elm, attrs) {

        console.log(scope.options.dummy.one); //Outputs "Declared in controller"

        window.setTimeout(function(){

           console.log(scope.options.dummy.one) //Outputs "Changed in controller"

        }, 5000)

      }
   }
});

This method works since javascript passes objects by reference whereas primitives are copied. By nesting an object in an object the data binding is preserved.

此方法有效,因为 javascript 通过引用传递对象,而原语是复制的。通过在对象中嵌套对象,数据绑定得以保留。

回答by Anoop

You can change scope in directive as follows

您可以按如下方式更改指令中的范围

.('mydirective ', function(){

   var linker = function(scope, element){
        console.log(scope.one, scope.two);    
   }    
   return {
        link: linker,
        scope: {one:"=", two:"="}
   }    
});

回答by Mark Rajcok

The question is, is there a better way to do this for a larger number of variables?

问题是,对于大量变量,是否有更好的方法来做到这一点?

I don't think so. As you already found out, trying to pass them as one object results in the object being databound, not the individual parts.

我不这么认为。正如您已经发现的那样,尝试将它们作为一个对象传递会导致对象被数据绑定,而不是单个部分。

Even if you could get something working with $compile, it would not be obvious to other people reading your code what is going on.

即使您可以使用 $compile 获得一些东西,但其他人阅读您的代码时也不清楚发生了什么。

Another option is to either not create a scope (scope: false, which is the default for directives), or create a new child scope (scope: true), but require that the calling scope must use certain scope property names to use the directive. Then you don't have to specify any attributes. This makes the directive's use much more restrictive, but I think those are your two choice: specify multiple attributes, or require certain scope property names.

另一种选择是不创建范围(scope: false,这是指令的默认值),或者创建新的子范围(scope: true),但要求调用范围必须使用某些范围属性名称才能使用指令。那么您不必指定任何属性。这使得指令的使用更具限制性,但我认为这是您的两个选择:指定多个属性,或需要某些范围属性名称。