注意:对于帖子的篇幅很抱歉,但我决定不在单独的问题中将其分解的原因是因为我发现如果没有像这样的复杂问题,这些问题很难解决。我感到眼花缭乱,有点害怕,我试图强迫Angular为我做一些不是' Angular方式的东西。 任何建议都会受到高度赞赏,并且可能会让我与Angular一起走上正轨。
我的问题如下:
我有一个动态生成的表单,由myFormCtrl
控制。我想要非常模块化:我想随时随地使用它。这意味着,有时我需要按原样放置它,有时我需要动态地嵌套表单(比如当我更改表单值,出现其他子表单时),或者控制两个单独的表单作为一个在父控制器的视图中,一个“保存”#39;两个按钮。 myFormCtrl
使用$scope.type_id
和$scope.rowid
来了解它应该从数据库中显示哪条记录。然后,记录由服务提取Ajax,并保存在myFromCtrl
$scope.formItems
下。保存后,表单会使用type_id和scope凭据将数据发送回服务器(通过服务),因此restful api知道将记录放在何处。
理论上,在Angular.js中很容易做到。
它肯定会出现在每种面向对象的语言中:父类可以调用getFormValues()
myFormCtrl
的公共方法。现在无法在Angular中完成:父母无法读取孩子的范围。
对我而言,似乎这并不是一个简单的“如何在控制器之间进行通信”。问题。我知道这个问题的答案是服务,事件,范围继承。
此外,我发现每个解决方案似乎都出现了许多其他问题。
所以我有一个myFormCtrlBase类,它做基本的东西,而其他更高级的类扩展了这个。我还有formControls.html
和formLayout.html
部分。第一个包含ng-switch,并根据$scope.formItem.controltype
提供适当的输入元素,第二个包含常用表单的html布局,ng-including formControls.html位于正确的位置。它在formItems"中使用ng-repeat =" formItem,以便formControls.html' s $scope.formItem
来自。
当我希望表单具有不同的布局时,我创建customFormLayout.html
由myFormCtrl
类控制的部分ng。
第一个问题:如果我的表单布局不能放入ng-repeat怎么办?
类似于需要将表单元素分散放置在页面上,或者表单布局不适合ng-repeat循环。我的formControls.html
仍然需要$scope.formItem
才能使用。 Easy OO解决方案:parent将formItem放在孩子的范围内。
我的解决方案:我创建了一个<formItemScopeChanger formItemScope="formItems[1]">
指令,它将formItems [1]作为属性,并将其转换为$ scope.formItem变量。这个解决方案感觉很乱:指令不应该像这样使用。似乎没有Angulary。 这真的是最好的解决方案吗?
第二个问题: ng-init真的那么邪恶吗?
说,表单不会放在$routeProvider
的视图中,而是放在自定义部分:rent-a-car.html中。在这里,我希望有一个表格,用户可以选择一辆车,另一个表格,我可以在那里找到他的联系人。这两种表单适用于不同的$scope.type_id
,因此需要有两种不同的形式:
<h1>Rent a car!</h1>
<div ng-controller="myFormCtrl" ng-init="type_id='rentOrder'">
<div ng-include="'formLayout.html'"></div>
</div>
<h2>Your contact information</h2>
<div ng-controller="myFormCtrl" ng-init="type_id='User';rowid='{{userData.rowid}}'">
<div ng-include="'formLayout.html'"></div>
</div>
Angular docs sais,ng-init唯一合适的用法是对ng-repeat值进行别名处理。我不知道上面这个例子的问题是什么 - 它仍然是最干净的解决方案,不是吗?
我使用与嵌套表单相同的技术 - 我将控制器放入模板中,通过ng-init从html初始化,并使用ng-if条件显示/隐藏。
顺便说一句,这是我在编写新控制器(扩展myFormCtrlBase
)时发现的唯一真正的初始化技术。在OO语言中,父级会写入子级的范围,然后对其进行初始化。
也许我的方法受到我以前使用的语言和编程技术的影响,并且绝对是错误的。
有些人会说,从父作用域中获取初始值!&#39;,但我似乎无法理解这是如何安全有效的。我需要对每个范围属性执行$scope.type_id=($scope.type_id || $routeParams.type_id)
,这是第一个:真的不好看,第二个:有风险。也许这是一个简单模板中的单个表单,但是在范围层次结构中的某个地方,有可能找到一个完全不同的type_id。也许它将是一个完全不同的控制器的type_id。
我不知道如何在我的范围变量中使用&#39; -s会有所帮助。我和我看到的风险相同。
第三个问题:如何处理rentACar.html提交?
当我在rentACar.html页面上点击“保存”按钮时,rentACarCtrl
(负责视图模型的控制器)应该以某种方式检索两个表单的值,并处理验证和提交。我似乎无法理解常见的咒语控制器如何通过服务进行通信。适用于此。仅适用于这两种形式的服务?
我是否在正确的轨道上?这些解决方案中的每一个都显得古怪。我感到迷茫:))
+ 1问题:即使在这一切麻烦之后,我似乎无法找到一个很好的理由让Angular不会让父母称儿童的公共事物。有充分的理由吗?在每个真正的OO js框架中,上述大多数问题都会有一个简单的答案。
答案 0 :(得分:0)
您需要考虑如何测试每个组件的逻辑。问问自己,这些“特征”中的每一个都是孤立的。
一些提示可帮助您重回正轨:
尝试并远离“基础”控制器,我已经使用范围继承击中了许多死胡同,逻辑变得混乱且难以理解。这也会影响测试,因为你发现自己必须站起来比测试所需的更多的对象
在范围继承(父控制器)上支持共享状态的单例(角度服务)
在使用ng-include之前创建一个指令并绑定到共享服务状态(更喜欢与范围继承的服务进行交互)
当另一个服务或控制器现在需要关于从指令触发的事件时,请使用事件模式。共享服务(状态)可以侦听这些事件
您的要求非常复杂,我想提供帮助,尝试一次关注一个功能并提供一些代码,一旦您提供了一些示例,我可以向您展示如何使用共享服务和事件模式< / p>
此外,采取测试第一种方法通常会揭示出最佳的“角度方式”。
答案 1 :(得分:0)
感谢Mark-Sullivan,以及大量的工作,尝试和错误尝试,整个事情已归结为此。我想得到Mark以及其他Angular大师的反馈意见。你觉得怎么样?
你没有在Angular.js中进行类/原型继承。很难测试,这是一个大问题。对于那些正在Angular寻找“继承”的人,我建议:
您的基类是控制器。无论如何,控制器是一个抽象模型,所以它非常适合这个目的。在控制器中使用$ scope.init()函数,但不要从那里调用它!
如果您想“扩展”控制器的功能,请使用指令。在你的指令link()函数中,调用控制器的$ scope.init()。 (编译时,angular首先运行控制器,然后执行指令链接功能)。如果范围有
$scope.name='base'
,则在指令链接中您可以重新定义$scope.name=child
,然后运行$ scope.init()。但是等等!但这只允许单级继承。 - 是的,这是真的。但是,如果您正在寻找多级继承,则应使用服务。
多级继承不是别的,而是在分层类结构中共享相同的代码。为此,请使用服务,并将依赖注入器中的这些服务引入您的指令中。太容易了。这应该易于实现,易于理解,并且测试运行顺畅。
指令是非常强大的工具,因为您可以动态地将部分与控制器结合起来。