shireef khatab shireef khatab - 1 month ago 28
AngularJS Question

AngularJs directives isolate scope

I have a simple app using custom directive but i`m totally lost trying to use isolate scope, please have a look and tell me what to write in order to fill the gaps.

What is the idea of the app!



a) the app controller generates a menu_list items from a service using $http then do search and return the foundItems array using the found function (this is all done!).

b) the directive has an ordered list looping throw the found items and displaying them plus a button next to each item to remove it if needed (this is still needed).

What am i missing:



i have three places in my directive.html where i comment saying <-- <== What to say here <== <== -->

also in my index.html i have commented <-- Not sure -->
as well as in my app.js commented <-- Not sure -->

please have a look at these 5 places and tell me what to do!

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


Note: ill code the remove method later and update the question , but for now it is not essentail.
Thank you in advance!
Update: coded the remove method on service and controller.

Answer

It seems you were going back and forth between a directive and a component. Components have the one-way binding that you referenced <. Your directive should look like this:

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

Then in your controller, I suggest you separate your search function and your results:

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

The markup is as follows - notice the ng-repeat. You assign it to a variable and use that variable inside the element. Then the ng-if is your condition for when the div should show which is when you have 0 results.

<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