不应该有一个 AngularJS ngWith 指令吗? [英] Shouldn't there be an AngularJS ngWith directive?

查看:25
本文介绍了不应该有一个 AngularJS ngWith 指令吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

也许我疯了,或者太习惯于 KnockoutJS,但我一直在文档中寻找 ngWith 指令来定义范围在元素上,在控制器中,或用于包含的 (ngInclude) 部分.

例如:

我想编写一个控制器来增强 MyItem ,例如:

MyModule.controller('MyItemCtrl', function($scope) {$scope.doSomethingToItem = function() {$scope.name = "bar";};});

或 MyItem 的视图/模板,例如:

{{姓名}}<button ng-click="doSomethingWithItem()">做某事</button>

但在这两种情况下,我都想象我的 $scope 原型继承自我的模型 MyItem.

但是作用域不是从模型继承的!!

这让我感到困惑.

相反,我的模型是范围上的属性.

如果是中继器:

<div ng-controller="MyItemCtrl">{{项目名称}}<button ng-click="doSomethingWithItem()">做某事</button>

这意味着我必须在任何地方使用 item.thisitem.that 而不是 thisthat>.我必须记住哪些函数是模型的本机函数,哪些函数是由控制器直接应用于作用域的.

如果我想要部分显示名称​​(愚蠢的例子,我知道,但你懂的):

{{name}}

我必须写它

{{item.name}}

然后确保模型是始终项.通常通过将它包装在一个指令中来简单地定义一个具有 item 属性的范围.

我经常觉得我想做的很简单:

<div ng-include="'my/partial.html'" ng-with="item"></div>

{{姓名}}<button ng-click="doSomethingWithItem()">做某事</button>

是否有一些我没有找到的神奇指令?还是我完全错了,只是在找麻烦?

谢谢.

非常感谢 Brandon Tilley 解释了使用示波器作为模型的危险.但是我仍然经常发现需要一些快速的声明性范围操作,并希望有一个 ng-with 指令.

例如,您有一个项目列表,单击该列表时会显示所选项目的展开视图.你可以这样写:

    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
<div ng-controller="ItemController">{{selection.maxView}}

现在您必须使用 selection.property 而不是我想要的:item.property 来获取所选项目的属性.我还必须在 ItemController 中使用 selection!使其与此视图完全结合.

我知道,在这个简单的例子中,我可以有一个包装控制器来使它工作,但它说明了这一点.

我写了一个非常基本的 with 指令:

myApp.directive('with', ['$parse', '$log', function(parse, log) {返回 {范围:真实,链接:函数(范围,EL,属性){var 表达式 = attr.with;var parts = expression.split(' as ');如果(部分.长度!= 2){log.error("`with` 指令需要`String as String`形式的表达式");返回;}scope.$watch(parts[0], function(value) {范围[部分[1]] = 值;}, 真的);}}}]);

这只是创建一个新的作用域,将一个表达式解析为另一个值,允许:

    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
<div with="selection as item" ng-controller="ItemController">{{item.maxView}}

这对我来说似乎非常有用.

我在这里遗漏了什么吗?不知何故只是给自己找麻烦?

解决方案

这是一个很好的问题.我可以看到来自另一个前端框架的这可能会令人困惑,但是在 Angular 中,范围引用了模型,并且您描述的语法是正常的.我个人喜欢将范围描述为更像 视图模型.

AngularJS 的作者 Miško Hevery 在 这个视频,从大约 30 分钟开始,持续大约 3 分钟:

<块引用>

人们常常认为范围就是模型,但事实并非如此.范围具有对模型的引用.[...] 所以在视图中,你可以说 model dot 任何你想访问的属性.

虽然可以编写一个 ngWith 指令来满足您的需求,但由于 Angular 对范围使用原型继承,您可能会遇到与 Miško 相同的问题在上述视频 at 31:10 中描述(您认为您正在更新父范围,但您实际上不是).有关 AngularJS 中原型继承的更多详细信息,请查看优秀文章 AngularJS wiki 上的范围原型继承的细微差别.

Maybe I'm crazy, or too used to KnockoutJS, but I keep looking for an ngWith directive in the docs to define the scope on an element, in a controller, or for an included (ngInclude) partial.

For example:

I'd like to write a controller that augments MyItem like:

MyModule.controller('MyItemCtrl', function($scope) {
    $scope.doSomethingToItem = function() {
        $scope.name = "bar";
    };
});

Or a view/template for MyItem like:

<div ng-controller="MyItemCtrl">
    {{name}}
    <button ng-click="doSomethingWithItem()">Do Something</button>
</div>

But in both of these cases I'm imagining my $scope to be prototypically inherit from my model, MyItem.

But the scope doesn't inherit from the model!!

Which baffles me.

Instead, my model is a property on the scope.

In the case of a repeater:

<div ng-repeat="item in list">
    <div ng-controller="MyItemCtrl">
        {{item.name}}
        <button ng-click="doSomethingWithItem()">Do Something</button>
    </div>
</div>

which means everywhere I have to use item.this or item.that instead of just this and that. I have to remember which functions are native to the model, and which were applied directly to the scope by a controller.

If I want to have a partial to display names (stupid example, I know, but you get the idea):

<h3>{{name}}</h3>

I have to write it

<h3>{{item.name}}</h3>

and then ensure the model is always item. Usually by wrapping it in a directive simply to defines a scope with an item property.

What I often feel like I want to do is simply:

<div ng-include="'my/partial.html'" ng-with="item"></div>

or

<div ng-repeat="list" ng-controller="MyItemCtrl">            
    {{name}}
    <button ng-click="doSomethingWithItem()">Do Something</button>
</div>

Is there some magical directive out there that I haven't found? Or am I completely wrong and just looking for trouble?

Thanks.

EDIT:

Many thanks to Brandon Tilley for explaining the dangers of using scopes as models. But I still often find the need for some quick declarative scope manipulation and wish for an ng-with directive.

Take, for example, you have a list of items which, when clicked, shows an expanded view of the selected item. You might write it something like:

<ul>
    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
</ul>
<div ng-controller="ItemController">
    {{selection.maxView}}
</div>

now you have to get properties of the selected item using selection.property rather than what I'd want: item.property. I'd also have to use selection in ItemController! Making it wholly coupled with this view.

I know, in this simple example I could have a wrapping controller to make it work, but it illustrates the point.

I've written a very basic with directive:

myApp.directive('with', ['$parse', '$log', function(parse, log) {

    return {
        scope: true,
        link: function(scope, el, attr) {
            var expression = attr.with;
            var parts = expression.split(' as ');

            if(parts.length != 2) {
                log.error("`with` directive expects expression in the form `String as String`");
                return;
            }

            scope.$watch(parts[0], function(value) {
                scope[parts[1]] = value;
            }, true);
        }
    }

}]);

that simply creates a new scope parsing one expression onto another value, allowing:

<ul>
    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
</ul>
<div with="selection as item" ng-controller="ItemController">
    {{item.maxView}}
</div>

This seems infinitely useful to me.

Am I missing something here? Just making trouble for myself down the line somehow?

解决方案

This is a great question. I can see how this may be confusing coming from another front-end framework, but in Angular, the scope has a reference to the model, and the syntax you're describing is normal. I personally like to describe the scope as more like a view model.

Miško Hevery, the author of AngularJS, does a good job of explaining this concept in this video, starting at about the 30 minute mark and lasting about 3 minutes:

People oftentimes think that the scope is the model, and that's not the case. Scope has references to the model. [...] So in the view, you say model dot whatever property you want to access.

While it may be possible to write an ngWith directive that does kind-of what you're looking for, since Angular uses prototypal inheritance for scopes, you will likely run into the same issues that Miško describes in the aforementioned video at 31:10 (where you think you're updating a value on the parent scope but you're actually not). For more details on prototypal inheritance in AngularJS, check out the excellent article The Nuances of Scope Prototypal Inheritance on the AngularJS wiki.

这篇关于不应该有一个 AngularJS ngWith 指令吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆