AngularJS: фильтрация и уникальность с многоуровневым JSON

0

У меня есть набор данных, который отображается в таблице. Каждый объект имеет дочерний объект Locations, который также имеет дочерний объект Region и Sites, который является массивом.

У меня проблемы с двумя проблемами:

Во-первых, на мой взгляд, чтобы отображать данные Сайтов (значение "Состояние"), я получаю дубликаты. Я пытаюсь использовать "уникальный" фильтр, чтобы показывать только уникальные значения состояния, но он не работает.

Во-вторых, я хочу использовать списки выбора с этими элементами данных региона, государства/страны/провинции и города, чтобы действовать как механизм фильтрации. Это тоже не работает.

См. Plunkr для рабочего примера: http://plnkr.co/edit/p0ImqB?p=preview

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

app.controller('MainCtrl', function($scope, $anchorScroll, $location, $http) {

	$scope.cart = [];

	$scope.addToCart = function(index) {
		$scope.cart.push(index);

		$scope.cartCount = $scope.cart.length;
	}



	$scope.activeRow = function(index) {
		$scope.selectedRow = index;

		$location.hash();
		$anchorScroll('anchor-' + index);

	}


	$scope.gotoAnchor = function(x) {
		var newHash = 'anchor' + x;


	}
    
        // GET data
        $scope.dataObject = data.List;
        $scope.locationObject = data.Locations;


});
body{background:#eee;}
div.cart{display:block;height:70px;background:silver;margin-left:20px;width:200px;padding:5px 10px;margin-bottom:20px;margin-top:20px;}
.cart h1{color:#fff;line-height:20px;}
.item-list-wrapper{height:400px;width:90%;border:1px solid #ddd;overflow-y:scroll;margin-left:20px;}
.item-list-wrapper table td{padding:10px;vertical-align:middle;margin-bottom:10px;font-size:12px;}
.item-list{height:auto;width:100%;margin-bottom:10px;box-shadow:0 2px 2px rgba(0,0,0,0.2);border:1px solid #fff;background:#efefe4;}
.col-num{width:100px;}
.col-compound{width:80px;}
.filters{width:300px;clear:both;margin-left:20px;}
.filters select{display:inline-block;}
.region{font-weight:bolder;}
.state{font-weight:normal;}
    <!DOCTYPE html>
    <html ng-app="plunker">

      <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <link data-require="bootstrap@*" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
        <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
        
        <link rel="stylesheet" href="angular-ui.min.css" />
        
        <script>
        document.write('<base href="' + document.location + '" />');
      </script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="[email protected]" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js" data-semver="1.4.7"></script>
        <script data-require="[email protected]" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular-messages.js"></script>
        <script data-require="ui-bootstrap@*" data-semver="0.13.3" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.1/ui-bootstrap.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.7/angular-filter.min.js"></script>
        <script src="angular-ui.min.js"></script>
        <script src="app.js"></script>
        <script src="http://zbl.me/test/103015.js"></script>

      </head>

      <body ng-controller="MainCtrl">
        <div ng-view=""></div>
        
		<div class="filters">
        <h2>Filter results</h2>
        
    				<select name="selectRegion" class="form-control" ng-model="selectRegion" ng-change="europeSelected()" ng-options="location as location.Region for location in locationObject | orderBy: location.Region:reverse">
    					<option value="">Select Region</option>
    				</select>
    				
    				<select name="selectState" class="form-control" ng-disabled="!selectRegion" ng-model="selectState" ng-options="state as state.StateName for state in selectRegion.States">
    					<option value="">Select State/Province/Country</option>
    				</select>
    				
    				<select name="selectCity" class="form-control" ng-disabled="!selectState" ng-model="selectCity" ng-options="city as city.CityName for city in selectState.Cities">
    					<option value="">Select City</option>
    				</select>
      </div>
      
      <div class="cart">
        <h1>Cart: {{cartCount}}</h1></div>
     <div class="item-list-wrapper">
    	 <table class="table table-condensed table-hover">
    	 	<tr ng-repeat="data in dataObject | filterBy: ['location.Region']: selectRegion | filterBy: ['state.StateName']: selectState | filterBy: ['city.CityName']: selectCity" ng-click="activeRow($index)">
    			<td class="column">{{data.Phase}}</td>
    			<td class="column col-num">{{data.Number}}</td>
    			<td class="column col-compound">{{data.Item}}</td>
    			<td>
      	      	  <span ng-repeat="location in data.Locations track by $index" class="region">{{ location.Region}}: 
      				<span ng-repeat="sites in location.Sites track by $index" class="state">
      					<span ng-repeat="item in sites.State track by $index | unique: 'item' ">{{item}}</span>
      					</span>
    				</span>
    			</td>
    			<td><a href="" ng-click="addToCart()">Add</a></td>
    		</tr>
    	 </table>
     </div>
      </body>

    </html>
Теги:
angularjs-filter

1 ответ

1
Лучший ответ

Проблема в HTML, вы повторялись в sites.State но там нет никакого массива, это только строка.

Изменение item-list-wrapper на этот в HTML-документе позволит решить проблему:

 <div class="item-list-wrapper">
     <table class="table table-condensed table-hover">
        <tr ng-repeat="data in dataObject | filterBy: ['location.Region']: selectRegion | filterBy: ['state.StateName']: selectState | filterBy: ['city.CityName']: selectCity" ng-click="activeRow($index)">
            <td class="column">{{data.Phase}}</td>
            <td class="column col-num">{{data.Number}}</td>
            <td class="column col-compound">{{data.Compound}}</td>
            <td>
        <span ng-repeat="location in data.Locations track by $index" class="region">{{ location.Region}}: 
                <span ng-repeat="site in location.Sites | unique: 'State'" class="state">{{site.State}}
                    </span>
                </span>
            </td>
            <td><a href="" ng-click="addToCart()">Add</a></td>
        </tr>
     </table>
 </div>

Вот плункер: http://plnkr.co/edit/VmLjZmgLtDuds5CM7lKM?p=preview

Что касается второй проблемы с фильтрами, я бы решил ее с помощью следующих настраиваемых фильтров:

app.filter('itemFilter', function() {
 return function(input,region,state) {
    if (!region)
      return input;
    return input.filter(function (x) {
      return x.Locations.some(function (y) {
        if (!state)
          return y.Region == region.Region;
        else
          return y.Sites.some(function (z) {
            return z.State == state.StateName;
          });
      });
    });
  };
});

app.filter('regionFilter', function() {
  return function(input,region,state) {
    if (!region)
      return input;
    return input.filter(function(y) {
      if (!state)
        return y.Region == region.Region;
      else
        return y.Sites.some(function (z) {
          return z.State == state.StateName;
        });
    });
  };
});

Вы можете использовать их в коде, как показано ниже:

 <div class="item-list-wrapper">
     <table class="table table-condensed table-hover">
        <tr ng-repeat="data in dataObject | itemFilter:selectRegion:selectState" ng-click="activeRow($index)">
            <td class="column">{{data.Phase}}</td>
            <td class="column col-num">{{data.Number}}</td>
            <td class="column col-compound">{{data.Compound}}</td>
            <td>
        <span ng-repeat="location in data.Locations | regionFilter:selectRegion:selectState" class="region">{{ location.Region}}: 
                <span ng-repeat="site in location.Sites | unique: 'State' | filter: { State: selectState.StateName }" class="state">{{site.State}}
                    </span>
                </span>
            </td>
            <td><a href="" ng-click="addToCart()">Add</a></td>
        </tr>
     </table>
 </div>

Здесь плукер: http://plnkr.co/edit/liWYtMIC1rDktmBYQtjo?p=preview

  • 0
    Это работает с дупсами, но как насчет фильтрации?
  • 0
    Привет SerpicoLugNut, я не заметил, что была еще одна проблема, эти фильтрации являются довольно сложными, потому что вы не хотите показывать элемент, который содержит регион, но не содержит состояние, поэтому я использовал пользовательские фильтры, чтобы убедиться, что вывод в соответствии с обоими фильтрами. Я не использовал City, потому что он не использовался в выходных данных, но вы можете легко добавить его, передав в фильтр selectedCity и добавив еще один уровень к существующим фильтрам и новый пользовательский фильтр в цикл State в HTML.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню