如何将表单提交事件传播到自定义指令的父级?

时间:2015-04-09 00:07:43

标签: angularjs angularjs-directive

我有一个简单的AngularJS项目,我从用户那里获取输入数据并根据该数据生成图表。我试图弄清楚如何组织代码,使其符合MVC design pattern。特别是,我很难搞清楚如何将表单的提交事件传播给自定义指令的父级。我正在寻找某种回叫机制。

似乎有几个选项,但我还没有让它们中的任何一个工作。我考虑过使用custom directivesui-Router和服务(根据AngularJS: How can I pass variables between controllers?

到目前为止,我一直试图让自定义指令的方法起作用。我有一个自定义指令<input-form>,它是一个表单,在提交时应将其输入传递给另一个自定义指令<index-chart>。我有三个控制器:一个用于主应用,NavigationController,一个用于输入InputController,它们与指令<input-form>相关联,另一个用于输出OutputController #39;绑定到<index-chart>指令。

我认为NavigationController应该知道如何从InputController中提取输入数据并将其传递给OutputControllerInputControllerOutputController应保持不可知,以便可以重复使用。

我想我已经找到了除流量控制之外的所有东西。 <input-form>包含<form ... ng-submit,因此即使我希望它保持不可知,它也负责触发响应用户提交的输入的操作。然而,该行动的代码应该在OutputControllerInputController不应该知道。

如何让NavigationController回复控制器为<input-form>的自定义指令InputController中包含的提交事件?然后NavigationController如何从InputController的实例中提取数据并调用应该呈现图表的OutputController中包含的代码(即下面代码中的renderChart()) ?

以下代码也在Plunker上:http://plnkr.co/edit/wm4suXMcSUE6obYFk3hp?p=preview的index.html

<html ng-app="a3d">
    <div ng-controller="NavigationController as navCtrl">
        <input-form ng-show="navCtrl.shouldShowInputForm()"></input-form>
        <index-chart ng-show="navCtrl.shouldShowOutputChart()"></index-chart>
    </div>
</html>

a3j.js

(function(){
    var app = angular.module('a3d', ['input-form', 'index-chart']);

    app.controller('NavigationController', function(){
        this.inputMode = true;

        this.shouldShowInputForm = function(){
            return this.inputMode;
        };

        this.shouldShowOutputChart = function(){
            return !this.inputMode;
        };

        this.flipMode = function(){
            this.inputMode = !this.inputMode;
        }
    });
})();

输入form.html

<form name="inputForm" ng-controller="InputController as inputCtrl"
                          ng-submit="inputForm.$valid && ???" novalidate>
    <textarea name="topic1Data" ng-model="inputCtrl.inputValues.topic1Data" rows="10" cols="30" required></textarea>
    <button type="submit" class="btn btn-info btn-lg" ng-disabled="!inputForm.$valid">Compare</button>
</form>

inputForm.js

(function(){
    var app = angular.module('input-form', [ ]);

    app.directive('inputForm', function(){
        return {
            restrict: 'E',
            templateUrl: 'input-form.html',

        };
    });

    app.controller('InputController', ['$window', '$log', function($window, $log, appData){
    // ...
    }]);

索引chart.html

<!-- I haven't really gotten to this part yet -->
<div id="indexchart" style="min-width: 310px; max-width: 800px; height: 900px; margin: 0 auto"></div>

indexChart.js

(function(){
    var app = angular.module('index-chart', [ ]);

    app.directive('indexChart', function(){
        return {
            restrict: 'E',
            templateUrl: 'index-chart.html'
        };
    });

    app.controller('OutputController', ['$window', '$log', function($window, $log, appData){
        this.renderChart = function(){

            // This is where the chart should get rendered

        };
    }]);    
})();

1 个答案:

答案 0 :(得分:1)

以下是一种方法 - Plunker

a3j.js

app.controller('NavigationController', function(){
  var navCtrl = this;
  navCtrl.data = null;
});

的index.html

<div ng-controller="NavigationController as navCtrl">
    <input-form data="navCtrl.data"></input-form>
    <index-chart data="navCtrl.data"></index-chart>
</div>

inputForm.js

inputForm.directive('inputForm', function() {
    return {
      restrict: 'E',
      templateUrl: 'input-form.html',
      scope: {data: "="},
      controllerAs: 'inputCtrl',
      bindToController: true,
      controller: function() {
        var inputCtrl = this;
        inputCtrl.inputValues = {topic1Data: 123456789};

        inputCtrl.emitData = function() {
          inputCtrl.data =  inputCtrl.inputValues.topic1Data;
        };
      }
    };
});

输入form.html

<form name="inputForm" ng-submit="inputForm.$valid && inputCtrl.emitData()" novalidate>
  <textarea name="topic1Data" ng-model="inputCtrl.inputValues.topic1Data" rows="10" cols="30" required></textarea>
  <button type="submit" class="btn btn-info btn-lg" ng-disabled="!inputForm.$valid">Compare</button>
</form>

indexChart.js

  indexChart.directive('indexChart', function() {
    return {
      restrict: 'E',
      templateUrl: 'index-chart.html',
      scope: {data: "="},
      controllerAs: 'chartCtrl',
      bindToController: true,
      controller: ['$scope', function($scope) {
        var chartCtrl = this;

        $scope.$watch('chartCtrl.data', function(newValue) {
          if (angular.isDefined(newValue)) {
            console.log(newValue);
          }
        });
      }]
    };
  });

索引chart.html

{{chartCtrl.data}}

需要注意的要点是:

  • 每个指令都有一个带有数据属性的隔离范围
  • NavigationController将相同的值传递给这些指令
  • 可以观察价值的任何变化并采取行动
  • 每个指令都是自包含的,无需单独的控制器
  • 每个指令彼此独立行事