繁体   English   中英

Angular.js控制器

[英]Angular.js controllers

注意:很抱歉,文章的篇幅不大,但我之所以决定不将其细分为单独的问题,是因为如果没有这样的复杂问题,我很难解决这些问题。 我很眼花,乱,有点害怕,我试图迫使Angular为我做一些事情,这不是“ Angular方式”。 任何建议将不胜感激,并且可能使我在Angular上走上正确的道路。

我的问题如下:我有一个动态生成的表单,由myFormCtrl控制。 我想变得非常模块化:我想随时随地使用它。 这意味着,有时我需要按原样放置它,有时我需要动态嵌套表单(例如当我更改表单值并且出现其他子表单时),或者将两个单独的表单作为一个控件由父控制器查看,两个控件都有一个“保存”按钮。 myFormCtrl使用$scope.type_id$scope.rowid来知道应从数据库显示哪个记录。 记录然后由服务通过Ajax获取,并保存在myFromCtrl$scope.formItems 保存后,表单将使用type_id和作用域凭据将数据发送回服务器(通过服务),因此,宁静的api知道将记录放置在何处。

从理论上讲,在Angular.js中确实很容易做到。 绝对会使用每种面向对象的语言:父类可以调用myFormCtrlgetFormValues()的公共方法。 现在,这无法在Angular中完成:父级无法读取子级的范围。

对我而言,这似乎不是一个简单的“如何在控制器之间进行通信”的问题。 我知道该问题的答案是服务,事件,范围继承。

此外,我发现sofer的每个解决方案似乎还会出现许多其他问题。

因此,我有一个myFormCtrlBase类,该类可以处理基本内容,而其他更高级的类则对此类进行了扩展。 我也有一个formControls.html和一个formLayout.html部分。 第一个包含ng-switch,并基于$scope.formItem.controltype提供适当的输入元素,第二个包含常见表单的html布局,在正确的位置ng-包括formControls.html。 它利用ng-repeat =“ formItems中的formItems”,因此这就是formControls.html的$scope.formItem来源。

例如,当我希望表单具有不同的布局时,我将创建由myFormCtrl类由ng控制的customFormLayout.html部分。

第一个问题:如果我的表单布局不能放在ng-repeat中怎么办?

例如,当需要将表单元素分散放置在整个页面上,或者表单布局不适合ng-repeat循环时。 我的formControls.html仍然希望可以使用$scope.formItem 简便的OO解决方案:父级将formItem置于子级范围内。 我的解决方案:我创建了一个<formItemScopeChanger formItemScope="formItems[1]">指令,该指令将formItems [1]作为属性,并将其转换为$ scope.formItem变量。 这种解决方案让人感到混乱:指令不能像这样使用。 似乎不是很有角度。 这真的是最好的解决方案吗?

第二个问题: 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的文档说,ng-init的唯一适当用法是在对ng-repeat值进行别名时。 我看不到上面的示例有什么问题- 它仍然是最干净的解决方案,不是吗?

我对嵌套表单使用了相同的技术-我将一个控制器与一个模板放在一起,由ng-init从html初始化,并使用ng-if条件显示/隐藏。

顺便说一句,这是我在编写新控制器(扩展myFormCtrlBase )之后发现的唯一真正的初始化技术。 在OO语言中,父级将写入子级的范围,然后对其进行初始化。 也许我的方法受到以前使用的语言和编程技术的影响,这是绝对错误的。

有人会说,“从父级作用域获取初始化值!”,但我似乎不明白这将是如何安全有效的。 我需要对每个作用域属性都执行$scope.type_id=($scope.type_id || $routeParams.type_id) ,这是第一:看起来真的很不好,第二:是有风险的。 也许这是一个简单模板中的单一形式,但是在范围层次结构中的某处,有可能会找到完全不同的type_id。 也许它将是一个完全不同的控制器的type_id。

我看不到在范围变量中使用'。'会有什么帮助。 我的风险与我看到的相同。

第三个问题:如何处理rentACar.html提交?

当点击我的rentACar.html页面上的Save按钮时, rentACarCtrl (负责视图模型的控制器)应该以某种方式检索这两个表单的值,并处理验证和提交。 我似乎无法理解常见的口头禅“控制器通过服务进行通信”将在这里适用。 仅针对这两种形式的服务?

我在正确的轨道上吗? 这些解决方案中的每一个似乎都是古怪的。 我感到失落 :)

+ 1个问题:尽管经历了这么多麻烦,但我似乎仍然找不到Angular不允许父母称呼孩子的公共物品的充分理由。 是否有充分的理由? 在大多数真正的OO js框架中,上述大多数问题都可以轻松解决。

您需要考虑如何测试每个组件的逻辑。 问问自己,这些“功能”中的每一个如何独立发挥作用。

一些提示可帮助您重回正轨:

  • 试着说远离“基本”控制器,我在范围继承方面遇到了很多死胡同,逻辑变得混乱且难以遵循。 这也会影响测试,因为您发现自己必须站起来比测试所需的更多物体

  • 在范围继承(父控制器)中偏向于共享状态的单例(角度服务)

  • 在使用ng-include之前,创建一个指令并绑定到共享服务状态(优先于作用域继承与服务交互)

  • 当另一个服务或控制器现在需要有关指令触发的事件时,请使用事件模式。 共享服务(状态)可以侦听那些事件

您的要求非常复杂,我想为您提供帮助,尝试一次专注于一项功能并提供一些代码,一旦提供了一些示例,我将向您展示如何使用共享服务和事件模式。

同样,采用测试优先的方法通常会揭示最佳的“角度方式”。

多亏了马克·沙利文(Mark-Sullivan),以及大量的工作,反复试验的尝试,整个事情归结为这一点。 我想从Mark和其他Angular专家那里得到反馈。 你怎么看?

您无需在Angular.js中进行类/原型继承。 这很难测试,那就是个大问题。 对于那些在Angular中寻找“继承性”的人,我建议这样做:

您的基类是控制器 控制器无论如何都是抽象模型,因此非常适合该目的。 在您的控制器中使用$ scope.init()函数,但不要从那里调用它!

如果要“扩展”控制器的功能,请使用指令 在您的指令link()函数中,调用控制器的$ scope.init()。 (编译时,先运行角度控制器,然后运行指令链接功能)。 如果scope具有$scope.name='base' ,则可以在指令链接中重新定义$scope.name=child ,然后运行$ scope.init()。

可是等等! 但这仅允许单级继承。 - 是的,这是真的。 但是,如果您正在寻找多级继承,则应该使用Services

多级继承只不过是在分层类结构中共享相同的代码。 为此,请使用Services ,并将这些服务与依赖项注入器一起放入指令中。 太容易了 这应该易于实现,易于理解并且测试运行顺利。

指令是非常强大的工具,因为您可以动态地将局部函数与控制器结合在一起。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM