【问题标题】:AngularJS: Access models using dynamic names in templateAngularJS:使用模板中的动态名称访问模型
【发布时间】:2014-10-16 15:47:47
【问题描述】:

我有一个模板,里面有很多本质上是重复的代码。我想使用一个指令来包含一个部分模板,我可以为每个重复代码“块”操作它。

模板目前看起来像这样:

<div class="column book">
    <div class="header">
        <input type="text" id="book_query" ng-model="book_query.name" />
    </div>
    <div class="content">
        <div class="row" ng-repeat="book in books | filter:book_query">
            {{book.name}}
        </div>
    </div>
</div>
....
<div class="column game">
    <div class="header">
        <input type="text" id="game_query" ng-model="game_query.name" />
    </div>
    <div class="content">
        <div class="row" ng-repeat="game in games | filter:game_query">
            {{game.name}}
        </div>
    </div>
</div>
....

控制器只是获取数据并将其添加到范围,例如

$scope.books = data.books;
$scope.games = data.games;

我开始做的是使用一个接受参数的指令(例如书籍、游戏等),这样我就知道要使用哪个模型了。我遇到的问题是如何使用参数访问模板中的模型?目前,指令本身非常简单:

<div item-column item="book"></div>
<div item-column item="game"></div>

app.directive('itemColumn', function() {
    return {
        scope: {
            item: '@'
        },
        replace: true,
        templateUrl: 'item_column.html'
    };
});

在 item_column.html 中,我希望我可以只替换 item 参数,它可以很好地显示 arg 的值,但不能用于替换模型中使用 'book' 或 'game' 的位置,例如

<div class="column {{item}}">
    <div class="header">
        <input type="text" id="{{item}}_query" ng-model="{{item}}_query.name" />
    </div>
    <div class="content">
        <div class="row" ng-repeat="item in ??? | filter:{{item}}_query">
            {{item.name}}
        </div>
    </div>
</div>

有人可以告诉我这样做的最佳方法吗?我不怀疑我走错了路!

编辑:上面的原始问题现在几乎完全解决了使用 JoseM 下面的答案。一个突出的问题是每个元素上的单击功能不再从隔离范围内触发父范围。

我的控制器布局如下:

    app.controller('ItemsCtrl', ['$scope', '$http', 'CONFIG', function($scope, $http, CONFIG) {

    var items = ['books', 'games'];

    items.forEach(function(item) {
        $scope[item] = [];
        $scope['selected_'+item] = null;
    })

    $scope.getItem = function(item) {

        $http.get('?action=get_item&id='+item.id+'&type='+item.type)
            .success(function(data) {
                // update model
            })
            .error(function(data, status) {
                // do something
            });
    }
}]);

$scope.getItem 在视图中单击项目时不再可访问,在实现 JoseM 的答案后类似于以下内容:

<div class="row" ng-repeat="item in array | filter:query">
    <div class="text" ng-click="getItem(item)">
        {{item.name}}
    </div>
</div>

是否有一种简单的方法可以使父范围函数在隔离范围内可用?或者这些功能有更好的地方吗?为(我的感觉)非常基本的问题道歉 - 我仍在努力了解 Angular!

【问题讨论】:

  • 您可以将函数传递给模板并动态创建自己的模板
  • 没错,它应该可以工作。问题是,问题并不明显,因为我已经对其进行了一些简化,但是模板中有大量代码。理想情况下,我真的不希望它在 JS 文件中 - 我更愿意将它包含在单独的 html 文件中。

标签: angularjs templates angularjs-ng-click angular-ngmodel


【解决方案1】:

实现所需的一种方法是在指令中使用子作用域,然后使用对父作用域值的监视来自己“链接”父作用域变量。

在你的指令中:

app.directive('itemColumn', function() {
    return {
        scope: true,
        templateUrl: 'item_column.html',
        link: function(scope,elem,attrs) {
          var varName = scope.varName = attrs.item;
          var parScope = scope.$parent;
          parScope.$watch(varName + 's', function(newVal){
            scope.theArray = newVal;
          });
          parScope.$watch(varName + '_query', function(newVal){
            scope.theQuery = newVal;
          });
        }
    };
});

在您的模板中:

<div class="column {{varName}}">
    <div class="header">
        <input type="text" ng-attr-id="{{varName}}_query" ng-model="theQuery.name" />
    </div>
    <div class="content">
        <div class="row" ng-repeat="item in theArray | filter:theQuery">
            {{item.name}}
        </div>
    </div>
</div>

如果您想使用隔离范围,您可以这样做,但如果您使用与上述相同的属性,则必须提供至少 3 个属性。我个人认为使用隔离范围是一种更好的方法。看看下面的隔离版本是如何更简单的:

指令的独立版本

app.directive('itemColumn2', function() {
    return {
        scope: {
          label: '@',
          array: '=',
          query: '='
        },
        templateUrl: 'item_column2.html'
    };
});

模板的独立版本

<div class="column {{label}}">
    <div class="header">
        <input type="text" ng-attr-id="{{label}}_query" ng-model="query.name" />
    </div>
    <div class="content">
        <div class="row" ng-repeat="item in array | filter:query">
            {{item.name}}
        </div>
    </div>
</div>

用法

<div item-column2 label="book" array="books" query="book_query"></div>
<div item-column2 label="game" array="games" query="game_query"></div>

最后是一个示例 plunker:http://plnkr.co/edit/OyEHR4ZhzYKvs4jeDfjD?p=preview

【讨论】:

  • 隔离作用域方法非常有效,非常感谢!我现在唯一遇到的问题是,当单击 UI 中的元素时,在父作用域中调用了一些函数,这些函数不再适用于隔离作用域。有没有一种简单的方法可以将它们链接起来?我会用一些细节更新原始问题。
  • 其实都挺好的。我似乎通过将函数作为另一个参数发送来对问题进行了排序。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2014-08-20
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 1970-01-01
  • 2013-11-14
  • 2016-09-02
  • 1970-01-01
相关资源
最近更新 更多