【问题标题】:AngularJs directives isolate scopeAngularJs 指令隔离范围
【发布时间】:2016-10-17 11:58:58
【问题描述】:

我有一个使用自定义指令的简单应用程序,但我在尝试使用隔离范围时完全迷失了方向,请看看并告诉我要写什么来填补空白。

这个应用的想法是什么!

a) 应用程序控制器使用 $http 从服务生成 menu_list 项目,然后使用 found 函数搜索并返回 foundItems 数组(这一切都完成了!)。
b) 该指令有一个有序列表循环抛出找到的项目并显示它们,并在每个项目旁边加上一个按钮,以便在需要时将其删除(这仍然需要)。

我错过了什么:

我在directive.html 中有三个地方我评论说

在我的 index.html 中我也评论过 以及在我的 app.js 中评论

请看看这 5 个地方,告诉我该怎么做!

index.html:

<!doctype html>
<html lang="en" ng-app="NarrowItDownApp">

<head>
    <title>Narrow Down Your Menu Choice</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles/bootstrap.min.css">
    <link rel="stylesheet" href="styles/styles.css">
</head>

<body>
    <div class="container" ng-controller="NarrowItDownController">
        <h1>Narrow Down Your Chinese Menu Choice</h1>

        <div class="form-group">
            <input type="text" placeholder="search term" class="form-control" ng-model="searchTerm">
        </div>
        <div class="form-group narrow-button">
            <button class="btn btn-primary" ng-click="found(searchTerm)">Narrow It Down For Me!</button>
        </div>
        <found-items items="found(searchTerm)"></found-items>
        <!-- Not sure -->
    </div>

    <script src="scripts/angular.min.js"></script>
    <script src="scripts/app.js"></script>
</body>

</html>

directive.html:

<div>
    <ol>
        <li ng-repeat="item in items"><!--  <==  What to say here  <==   <== -->
            {{ item.name }}, {{ item.shortName }}, {{item.description}}
            <button ng-click="remove">Remove item</button> <!--  <==  What to say here  <==   <== -->
        </li>
    </ol>
    <div class="error" ng-if="foundItem.length">nothing found
    </div> <!--  <==  What to say here  <==   <== -->
</div>

app.js:

var app = angular.module('NarrowItDownApp', []);

app.controller('NarrowItDownController', ['$scope', 'MenuSearchService', function($scope, MenuSearchService) {
    var $scope = $scope;
    $scope.searchTerm = 'soup';
    $scope.found = function() {
        return MenuSearchService.getMatchedMenuItems($scope.searchTerm);
    }
    console.log(MenuSearchService.getMatchedMenuItems($scope.searchTerm));

    $scope.remove = function(index){
        service.removeItem(index);
    }
}]);

app.service('MenuSearchService', ['$http', function($http) {
    var service = this;
    service.getMatchedMenuItems = function(searchTerm) {
        searchTerm = searchTerm.toLowerCase();
        return $http({
                method: 'GET',
                url: 'https://davids-restaurant.herokuapp.com/menu_items.json'
            })
            .then(function(response) {
                var result = response.data.menu_items;
                console.log('Result: ' + result.length);
                var foundItems = [];
                result.forEach(function(obj) {
                    if (searchTerm != '') {
                        if ((obj.name.indexOf(searchTerm) != -1) || (obj.description.indexOf(searchTerm) != -1)) {
                            foundItems.push(obj);
                        }
                    }
                })
                console.log('Found Items: ' + foundItems.length)
                return foundItems;

            }, function(error) {
                console.log('Error from $http' + error);
            });
    }
         service.removeItem = function(index){
        service.getMatchedMenuItems(index).splice(index, 1);
    }
}]);

app.directive('foundItems', function() {
    var ddo = {
        templateUrl: 'directive.html',
        scope: {
            items: '<found' // Not sure
        }
    }
    return ddo;
});

注意:稍后对 remove 方法进行编码并更新问题,但现在它不是必需的。 先感谢您! 更新:在服务和控制器上编写了 remove 方法。

【问题讨论】:

  • 说实话有几点;服务需要返回一个项目数组,该数组需要通过 items 属性传递给指令,然后指令模板需要遍历数组并根据每个项目采取行动。用 jsFiddle 演示会更容易......
  • 您有一个隔离范围,因此要拥有点击事件等功能,您需要为这些事件绑定或在自定义指令的控制器中处理它们。
  • @Neil Hibbert 我相信我已经从 then 方法返回了一个数组

标签: angularjs angularjs-directive isolate-scope


【解决方案1】:

您似乎在指令和组件之间来回切换。组件具有您引用的单向绑定&lt;。您的指令应如下所示:

app.directive('foundItems', function() {
    var ddo = {
      restrict: 'E', //Since this is a directive and not a component, you need to define which type (E = Element since you're using <found-items>)
      templateUrl: 'directive.html',
      scope: {
          items: '=' // This is two-way binding which you'll need for the array
      },
      controller: function ($scope) {
        $scope.remove = function (item) {
          // This can be where you make a call to your service to remove the item on the server
          var index = $scope.items.indexOf(item);
          if(index >= 0) {
            $scope.items.splice(index, 1);
          }
        }
      }
    }
    return ddo;
});

然后在你的控制器中,我建议你将搜索功能和结果分开:

app.controller('NarrowItDownController', ['$scope', 'MenuSearchService', function($scope, MenuSearchService) {
    $scope.searchTerm = 'soup';
    // It looks like you want to use found as both the results and the search function.  Separate them.
    $scope.search = function(searchTerm) {
      console.log('Searching for ' + searchTerm);
      MenuSearchService.getMatchedMenuItems(searchTerm).then(function(foundItems) {
        // The service executes asynchronously so use the then() to create a callback and store the results.
        $scope.results = foundItems;
      });
    };

    $scope.search($scope.searchTerm);
}]);

标记如下 - 注意ng-repeat。您将其分配给一个变量并在元素内使用该变量。那么ng-if 是你的条件,当你有 0 个结果时,div 应该显示。

<div>
    <ol>
        <li ng-repeat="item in items">

            {{ item.name }}, {{ item.shortName }}, {{item.description}}
            <button ng-click="remove(item)">Remove item</button>

        </li>
    </ol>
    <div class="error" ng-if="items.length == 0">nothing found </div>

</div>

http://plnkr.co/edit/VqaYgNx56qbjAQT1Xd3m?p=preview

【讨论】:

  • 多么传奇!真的非常感谢。
  • 这里为什么是if条件? if(index >= 0) { $scope.items.splice(index, 1); }
  • 因为indexOf在数组中查找项时,如果找到会返回0或更大的索引,否则返回-1,所以可以这样写if(index !== -1)
  • 我的意思是为什么我不能只说 $scope.items.splice(index, 1);没有条件,只要不通过该项目,所以它无论如何都是!= -1?
  • 另外请告诉我为什么我们需要在控制器内部再次调用 .then ?是获取数组而不是函数吗?
【解决方案2】:

查看文档here。您需要定义指令将使用的绑定类型。如果您将对象传递给指令,它将是=。所以指令作用域定义是这样的:

scope: {
  items: '='
}

之后,您的指令范围将只定义items,而不是所有其他父范围对象。您可以像往常一样使用该变量:

ng-repeat="item in items"

对于诸如删除之类的事情,您可以在指令中实现功能,但它要做的事情超出了您当前问题的范围。可以调用 $http 吗?

【讨论】:

  • 请把我当作一个初学者,我需要那些缺失的部分来完成这个难题,并尝试理解一个活生生的例子,而不仅仅是文档
  • 作为初学者,您应该至少阅读整个文档一次。并尝试重现它们是由那里的框架作者制作的东西。例如,您在变量中定义仅在一行之后返回的指令。虽然文档总是显示return {}
猜你喜欢
  • 1970-01-01
  • 2015-12-08
  • 1970-01-01
  • 2012-12-27
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多