AngularJS:来自控制器的访问指令数据

时间:2014-03-10 15:10:30

标签: angularjs angularjs-directive angularjs-scope

让我们假设我有一个类似的AngularJS指令:

app.directive('psDIR', [
    function() {
        return {
            template: "<div style='padding: 5px; border: 1px solid red; margin-bottom: 10px;'><p>This is a direcive:</p> <textarea rows='5' cols='50' ng-model='md'></textarea></div>",
            restrict: 'AEC',
            scope: {}
        }
    }
]);

我在一个页面上使用此指令的次数。如何获取ng-model="md"MainCtrl的每个指令实例/范围的值(即我想将此值保存在add()中):

app.controller('MainCtrl', ['$scope',
    function($scope) {
        console.log("init");
        $scope.add = function() {
            console.log($scope);
        }
    }
]);

Plunker演示:http://embed.plnkr.co/Q5bw6CBxPYeNe7q6vPsk/preview

任何建议都非常感谢。

3 个答案:

答案 0 :(得分:3)

由于您正在创建隔离范围,否则您也无法从父范围访问子范围。

将模型作为参数传递出来的方法,如

<div class="psDIR" model='field2'></div> <div class="psDIR" model='field1'></div>

然后在指令中用属性绑定更新它们。请参阅update plunkr

http://plnkr.co/edit/GKZHSDe5J0eCzqlgaf4g?p=preview

答案 1 :(得分:2)

可能的解决方案是使用require

app.directive('psDIR', [
    function() {
        return {
            ...,
            require: "ngController",
            link: function(scope, elem, attrs, ngCtrl) {
              ngCtrl.hook(scope);
            }
        }
    }
]);

对控制器进行必要的更改:

app.controller('MainCtrl', ['$scope',
    function($scope) {
        console.log("init");
        $scope.add = function() {
            var i;
            for( i=0; i < psDirs.length; i++ ) {
              console.log(i + " -> " + psDirs[i].md);
            }
        }

        var psDirs = [];
        this.hook = function(scope) {
          psDirs.push(scope);
        };
    }
]);

在此处试试:http://plnkr.co/edit/zCZ1TOm3aK8V4piCAY6u?p=preview


如果您决定使用此解决方案,我建议在专门的包装器指令中实现“包装器”控制器,以避免在层次结构中的某些其他元素中设置ng-controller的情况。在这种情况下,只需require: "wrapperDirective"

编辑:包装器指令案例的HTML看起来像:

<div wrapper-directive>
    <div class="psDIR"></div>
    <div class="psDIR"></div>
    <button ng-click="add()">Add</button>
</div>

该指令本身使用前一个ng-controller

的代码
app.directive('wrapperDirective', function() {
    return {
        restrict: "A",
        // YOU MAY WANT ISOLATED SCOPE, JUST ADD scope: {},
        controller: ["$scope", function($scope) {
            // SAME CODE AS BEFORE
            console.log("init");
            $scope.add = function() {
                var i;
                for( i=0; i < psDirs.length; i++ ) {
                  console.log(i + " -> " + psDirs[i].md);
                }
            }

            var psDirs = [];
            this.hook = function(scope) {
              psDirs.push(scope);
            };
        }]
    };
});

当然更改require配置:

app.directive('psDIR', [
    ...
    require: "^wrapperDirective",
    link: function(scope, elem, attrs, wrapperDirectiveCtrl) {
        wrapperDirectiveCtrl.hook(scope);
    }

答案 2 :(得分:2)

当您想要在范围(即指令和其他控制器)之间进行通信时,通常正确的做法是使用服务。

您可以在此处查看一个简单的plunker:http://plnkr.co/edit/8Al31Bq9BfoazUCpqhWy?p=preview

psDirs服务保留了指令的注册表:

app.service('psDirs', function() {
  var psDirs = {
    dirs: [],
    register: function (dir) {
      psDirs.dirs.push(dir);
    }
  };

  return psDirs;
});

指令会自行注册并在更改时更新值:

link: function (scope, elm, attr) {
  var dir = { val: "" };
  psDirs.register(dir);

  scope.$watch('md', function (n, o) {
    if (n !== o) {
      dir.val = n;
    }
  });
}

然后您的控制器可以注入psDirs服务并根据需要访问指令注册表。这可以防止脆弱的范围关系,并允许指令注册表服务在其他地方,应用程序的多个控制器和部分中使用。