不应该有AngularJS ngWith指令吗?

nic*_*las 21 angularjs angularjs-scope

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

例如:

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

MyModule.controller('MyItemCtrl', function($scope) {
    $scope.doSomethingToItem = function() {
        $scope.name = "bar";
    };
});
Run Code Online (Sandbox Code Playgroud)

或MyItem的视图/模板,如:

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

但在这两种情况下,我都在想象我的范围是从我的模型继承原型,MyItem.

但范围不继承模型!!

哪个让我感到困惑.

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

在转发器的情况下:

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

这意味着我必须使用item.thisitem.that代替只是thisthat.我必须记住哪些函数是模型的原生函数,哪些函数由控制器直接应用于作用域.

如果我想部分显示名称(愚蠢的例子,我知道,但你明白了):

<h3>{{name}}</h3>
Run Code Online (Sandbox Code Playgroud)

我必须写它

<h3>{{item.name}}</h3>
Run Code Online (Sandbox Code Playgroud)

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

我经常想要做的事情就是:

<div ng-include="'my/partial.html'" ng-with="item"></div>
Run Code Online (Sandbox Code Playgroud)

要么

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

那里有一些我没有找到的神奇指令吗?或者我完全错了,只是找麻烦?

谢谢.

编辑:

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

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

<ul>
    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
</ul>
<div ng-controller="ItemController">
    {{selection.maxView}}
</div>
Run Code Online (Sandbox Code Playgroud)

现在你必须使用所选项目的属性,selection.property而不是我想要的:item.property.我也不得不使用selectionItemController!使它完全与这个观点相结合.

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

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

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);
        }
    }

}]);
Run Code Online (Sandbox Code Playgroud)

只是创建一个新的范围,将一个表达式解析为另一个值,允许:

<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>
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎无限有用.

我在这里错过了什么吗?不管怎么说,只为自己制造麻烦?

Har*_*rry 21

我发现我可以在ng-repeat的源头周围放一个数组,它在功能上变成了ng-with.:)

<div ng-repeat="name in [vm.dto.Person.Name]" >
  <input type="text" ng-model="name.First" />
  <input type="text" ng-model="name.Last" />
</div> 
Run Code Online (Sandbox Code Playgroud)

似乎有些纯净可能不喜欢这样......也似乎没有一个好的选择.


Mic*_*ley 10

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

AngularJS的作者MiškoHevery在这段视频中做了很好的解释,从约30分钟开始,持续约3分钟:

人们经常认为范围是模型,而事实并非如此.范围引用了该模型.[...]因此,在视图中,您说出model dot您想要访问的任何属性.

虽然有可能编写一个ngWith指令来实现您正在寻找的类型,但由于Angular使用原型继承作为范围,您可能会遇到Miško在上述视频描述的相同问题(31:10)你认为你正在更新父范围的值,但实际上你没有).有关AngularJS中原型继承的更多详细信息,请参阅AngularJS wiki上的优秀文章范围原型继承的Nuances.

  • 我在这里看到ng-with指令用于其他事情,例如存储昂贵的模型方法的输出调用EG:<div ng-with ="items.find_best_item()as best"> {{best.name}} {{best.value}} {{best.price}} </ div> ...(创建一个隐含的一次性范围,而不必创建一个完整的控制器)你有没有看到任何缺点?这让我想知道为什么ngWith不是角度的基本指令 (3认同)

ker*_*nel 5

另一种方法是通过以下方式设置新变量ng-init

<div ng-init="name = vm.dto.Person.Name" >
  <input type="text" ng-model="name.First" />
  <input type="text" ng-model="name.Last" />
</div>
Run Code Online (Sandbox Code Playgroud)