如何将表单提交事件传播到自定义指令的父级?
How propagate form submit event to parent of custom directive?
我有一个简单的 AngularJS 项目,我从用户那里获取输入数据并根据该数据生成图表。我正在尝试弄清楚如何组织代码以使其符合 MVC design pattern。特别是,我一直在弄清楚如何将表单的提交事件传播到自定义指令的父级。我正在寻找某种回调机制。
似乎有多种选择,但我还没有让其中的任何一种发挥作用。我考虑过使用 custom directives, ui-Router, and services (as per AngularJS: How can I pass variables between controllers?)
到目前为止,我一直在尝试使自定义指令的方法起作用。我有一个自定义指令 <input-form>
,它是一种表单,在提交时应将其输入传递给另一个自定义指令 <index-chart>
。我有三个控制器:一个用于主应用 NavigationController
,一个用于与指令 <input-form>
相关联的输入 InputController
,另一个用于与 OutputController
相关联的输出 OutputController
=17=]指令。
我认为 NavigationController
应该知道如何从 InputController
中提取输入数据并将其传递给 OutputController
。 InputController
和 OutputController
应该保持不可知,这样它们就可以被重用。
我想我已经想通了除了流量控制之外的所有东西。 <input-form>
包含 <form ... ng-submit
,因此尽管我希望它保持不可知,但它负责触发响应用户提交的输入的操作。然而,该操作的代码应该在 OutputController
中,而 InputController
不应该知道。
如何让 NavigationController
响应控制器为 InputController
的自定义指令 <input-form>
中包含的提交事件?然后 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){
// ...
}]);
index-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
};
}]);
})();
这是一种方法 - 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}}
主要注意事项有:
- 每个指令都有一个带有 data 属性
的隔离作用域
- NavigationController 将相同的值传递给这些指令
- 可以观察值的任何变化并采取行动
- 每个指令都是独立的,不需要单独的控制器
- 每个指令相互独立
我有一个简单的 AngularJS 项目,我从用户那里获取输入数据并根据该数据生成图表。我正在尝试弄清楚如何组织代码以使其符合 MVC design pattern。特别是,我一直在弄清楚如何将表单的提交事件传播到自定义指令的父级。我正在寻找某种回调机制。
似乎有多种选择,但我还没有让其中的任何一种发挥作用。我考虑过使用 custom directives, ui-Router, and services (as per AngularJS: How can I pass variables between controllers?)
到目前为止,我一直在尝试使自定义指令的方法起作用。我有一个自定义指令 <input-form>
,它是一种表单,在提交时应将其输入传递给另一个自定义指令 <index-chart>
。我有三个控制器:一个用于主应用 NavigationController
,一个用于与指令 <input-form>
相关联的输入 InputController
,另一个用于与 OutputController
相关联的输出 OutputController
=17=]指令。
我认为 NavigationController
应该知道如何从 InputController
中提取输入数据并将其传递给 OutputController
。 InputController
和 OutputController
应该保持不可知,这样它们就可以被重用。
我想我已经想通了除了流量控制之外的所有东西。 <input-form>
包含 <form ... ng-submit
,因此尽管我希望它保持不可知,但它负责触发响应用户提交的输入的操作。然而,该操作的代码应该在 OutputController
中,而 InputController
不应该知道。
如何让 NavigationController
响应控制器为 InputController
的自定义指令 <input-form>
中包含的提交事件?然后 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){
// ...
}]);
index-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
};
}]);
})();
这是一种方法 - 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}}
主要注意事项有:
- 每个指令都有一个带有 data 属性 的隔离作用域
- NavigationController 将相同的值传递给这些指令
- 可以观察值的任何变化并采取行动
- 每个指令都是独立的,不需要单独的控制器
- 每个指令相互独立