Filter Data in nested json - javascript

My angular controller is following -
how to filter nested data like first row of json-
<script>
var myApp = angular.module('myApp', ['angular.filter']);
function VersionFilterCtrl($scope) {
$scope.limit=6;
$scope.orders = [
{ id:1, customer:[{ name: 'John1', id: 10 },{ name: 'John2', id: 100 }] },
{ id:2, customer: { name: 'William', id: 20 } },
{ id:3, customer: { name: 'John', id: 10 } },
{ id:4, customer: { name: 'William', id: 20 } },
{ id:5, customer: { name: 'Clive', id: 30 } }
];
}
</script>
and my html
<div ng-app="myApp">
<div ng-controller="VersionFilterCtrl">
<input type='text' name='name' ng-model='search.customer.name'>
<input type='text' name='name' ng-model='search.customer.id'>
<li ng-repeat="order in orders| filterBy: ['customer.name']: search.customer.name| filterBy: ['customer.id']: search.customer.id">
{{order.id}}{{order.customer.name}}
</li>
</div>
</div>
JSFIDDLE EXAMPLE

You approached this correctly in how you set up your search models to match the structure of the data you are filtering, i.e. search.customer.name and search.customer.id.
All you need to do is to apply the search object as the filter:
<li ng-repeat="order in orders | filter: search">
{{order.id}} | id: {{order.customer.id}} name: {{order.customer.name}}
</li>
plunker
A few other issues:
There is no filterBy (unless you create your own)
Your first order record has an array of customers - was this intentional? This plunker handles that case

Related

How to use ng-repeat with ng-model and get an ID

I have a form with ng-model="award.myProperty". There are some inputs and texareas. In my service I have an array for textareas:
allQuestions = [
id: 'XXX', question: 'some text',
id: 'YYY', question: 'some text',
id: 'ZZZ', question: 'some text',
];
My goal is to get data from textareas in such structure
questions: [{
'XXX': 'data from textarea1',
'YYY': 'data from texarea2',
'ZZZ': 'data from textarea3',
}];
I've tried to use ng-repeat with ng-model, but ng-model doesn't return ID's. If I use $index with ng-repeat then I get an array:
[{ 0: 'data from textarea1',
1: 'data from textarea2',
2: 'data from textarea3',}]
Structure is good, but that's not my ID's from service.
SERVICE
const allQuestions = [
{ id: 'XXX', question: 'question1' },
{ id: 'YYY', question: 'question2' },
{ id: 'ZZZ', question: 'question3' },
];
getQuestion() {
return allQuestions;
},
CONTROLLER
$scope.allQuestions = awards_service.getQuestion();
$scope.award = {
description: '',
questions: [],
};
VIEW
<form name="awardForm">
<input ng-model="award.description"></input>
<div ng-repeat="question in allQuestions">
<textarea ng-model="award.questions"></textarea>
</div>
</form>
Maybe there is a better solution than ng-repeat.
In your controller change $scopre.award.questions to:
$scope.allQuestions = awards_service.getQuestion();
$scope.award = {
description: '',
questions: [{}]
};
Then in the view:
<form name="awardForm">
<input ng-model="award.description"></input>
<div ng-repeat="question in allQuestions">
<textarea ng-model="award.questions[0][question.id]"></textarea>
</div>
</form>
Demo:
angular.module("myApp", [])
.controller('myCtrl', ['awards_service', '$scope', function(awards_service, $scope) {
$scope.allQuestions = awards_service.getQuestion();
$scope.award = {
description: '',
questions: [{}],
};
$scope.submit = function() {
console.log($scope.award);
// submit your form then reset the award object
// ...
$scope.award = {
description: '',
questions: [{}],
};
}
}])
.factory('awards_service', function() {
const allQuestions = [
{ id: 'XXX', question: 'question1' },
{ id: 'YYY', question: 'question2' },
{ id: 'ZZZ', question: 'question3' },
];
return {
getQuestion() {
return allQuestions;
}
}
});
.as-console-wrapper { height: 70px !important; overflow: auto; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<form name="awardForm" ng-submit="submit()">
<label>Description</label><br>
<input ng-model="award.description"></input><br>
<label>Questions</label><br>
<div ng-repeat="question in allQuestions">
<textarea ng-model="award.questions[0][question.id]" placeholder="Enter a question"> </textarea>
</div>
<input type="submit" value="submit" />
</form>
</div>
</div>

Multi level json filter in angular js

I am new in angular js i want to put filter in ng-repeat i have json like this
var data = [
{name:test1,b1:{lastValue:0},b2:{lastValue:6},b3:{lastValue:6},b4:{lastValue:0}}
{name:test2,b1:{lastValue:6},b2:{lastValue:0},b3:{lastValue:6},b4:{lastValue:0}}
{name:test3,b1:{lastValue:6},b2:{lastValue:0},b3:{lastValue:6},b4:{lastValue:0}}
]
I want to put filter on lastValue i tested like this
ng-repeat = "d in data | filter:{*.lastValue:filterStatus}"
filterStatus // contain value of filter which user selected but its not working
I don't know how to do this i tried google but nothing found please help me
<input ng-model="filterStatus" type="text">
your filterStatus should hold model value
ng-repeat = "d in data | filter:filterStatus"
var app = angular.module("Profile", []);
app.controller("ProfileCtrl", function($scope) {
$scope.filter_val = {}
$scope.data = [{
name: 'test1',
b1: {
lastValue: 0
},
index: 'b1'
}, {
name: 'test2',
b2: {
lastValue: 6
},
index: 'b2'
}, {
name: 'test3',
b3: {
lastValue: 6
},
index: 'b3'
}, {
name: 'test4',
b4: {
lastValue: 0
},
index: 'b4'
}, {
name: 'test5',
b5: {
lastValue: 89
},
index: 'b5'
}, {
name: 'test6',
b6: {
lastValue: 68
},
index: 'b6'
}]
$scope.own_filter = function(val) {
if (!$scope.filter_val.value)
return true;
else {
return (String(val[val['index']]['lastValue'] || '').indexOf($scope.filter_val.value) != -1)
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="Profile" ng-controller="ProfileCtrl">
<input type="text" ng-model="filter_val.value" placeholder="Enter Last Value">
<div class="row" ng-repeat="event in data |filter:own_filter track by $index ">
<h4>{{'Name : ' + event.name}}------{{'Last Value : '+event[event['index']]['lastValue']}}</h4>
</div>
</body>
Use {$:filterStatus} construction:
angular.module('app', []).controller('ctrl',function($scope){
$scope.data = [
{name:'test1',b1:{lastValue:1},b2:{lastValue:6},b3:{lastValue:6},b4:{lastValue:0}},
{name:'test2',b1:{lastValue:2},b2:{lastValue:0},b3:{lastValue:6},b4:{lastValue:0}},
{name:'test3',b1:{lastValue:3},b2:{lastValue:0},b3:{lastValue:6},b4:{lastValue:0}}
]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<div ng-app='app' ng-controller='ctrl'>
<input type='number' ng-model='filterStatus' ng-init='filterStatus=1'>
<ul>
<li ng-repeat='item in data | filter: {$:filterStatus}'>{{item.name}}</li>
</ul>
</div>

How to filter ng-repeat list on empty string values?

How can I filter an ng-repeat to show all items where a certain columnfield is an empty string? When I try this it always seem to give the full list. I only want to see the person with id 1.
Fiddlejs example
Controller:
var people = [{
name: '',
age: 32,
id: 1
}, {
name: 'Jonny',
age: 34,
id: 2
}, {
name: 'Blake',
age: 28,
id: 3
}, {
name: 'David',
age: 35,
id: 4
}];
$scope.filteredPeople = $filter('filter')(people, {
name: ''
});
$scope.people = people.slice(0);
View:
<li ng-repeat="p in filteredPeople">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
You can use Angular's 'filter' in 'ng-repeat':
// In template:
<li ng-repeat="p in filteredPeople | filter : filterPeople">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
// In controller:
$scope.filterPeople = function(item) {
return !item.name;
};
To list users that have name:
<li ng-repeat="p in filteredPeople" ng-if="p.name !== ''">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
To list only users that do not have name:
<li ng-repeat="p in filteredPeople" ng-if="p.name === ''">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
Just pass third parameter to filter saying true which will perform strict check
$scope.filteredPeople = $filter('filter')(people, {
name: ''
}, true);
Forked JSFiddle

Dependent Select Angular JS

I have hierarchical data set. There is one fixed root unit.
What I want to do is to make this tree browsable with dependent selects.
I have created a simple plunkr example with a fixed dataset.
http://plnkr.co/edit/Bz5A1cbDLmcjoHbs5PID?p=preview
The data format in the example mimics the format I would get from a server request in "real" life.
This working fine in this simple first step. What is missing is, that when a user changes a selection somewhere in the middle, the select boxes and the ng-model binding below the new selection need to be destroyed.
So when I select Europe->France->Quimper and change "Europe" to "Asia" - then there should be "Asia" as the first select box and a second one the Asia countries.
Is there an "Angular" way to deal to deal with this? Any other hint is appreciated also ;)
<!DOCTYPE html>
<html ng-app="app">
<head>
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.3.17/angular.js" data-semver="1.3.17" data-require="angular.js#1.3.17"></script>
</head>
<body>
<div ng-controller="Ctrl">
<select ng-repeat="select in selects track by $index" ng-model="$parent.boxes[$index]">
<option ng-repeat="child in select.children" ng-click="expandSelects(child)">{{child.name}}</option>
</select>
<ul>
<li ng-repeat="item in boxes">{{ item }}</li>
</ul>
</div>
<script>
var app = angular.module('app', []);
app.controller('Ctrl', ['$scope', function($scope) {
var data = {
'europe': {
name: 'europe',
children: [{
name: 'france',
parent: 'europe'
}, {
name: 'italy',
parent: 'europe'
}],
},
'asia': {
name: 'asia',
children: [{
name: 'japan',
parent: 'asia'
}, {
name: 'china',
parent: 'asia'
}],
},
'france': {
name: 'france',
children: [{
name: 'paris',
parent: 'france'
}, {
name: 'quimper',
parent: 'france'
}]
}
};
var root = {
name: 'world',
children: [{
name: 'europe',
parent: 'world'
}, {
name: 'asia',
parent: 'world'
}, ]
};
$scope.selects = [root];
$scope.expandSelects = function(item) {
var select = data[item.name];
if (select) {
$scope.selects.push(select);
}
}
$scope.$watch('boxes', function(item, old) {
}, true);
}]);
</script>
</body>
</html>
This is a classic example of cascading dropdowns, with the added challenge of an unknown number of levels in the cascade. I combined the data set into one object for simplicity, added labels for the dropdowns, and simplified the select element.
This solution allows for any number of levels, so if you needed data below the city level, you could add it without changing any code, as illustrated by the "Street" example I added to Paris.
select {
display: block;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.3.17/angular.js" data-semver="1.3.17" data-require="angular.js#1.3.17"></script>
</head>
<body>
<div ng-controller="Ctrl">
<div ng-repeat="select in selects track by $index" ng-if="select.children">
<label>{{ select.optionType }}</label>
<select ng-model="selects[$index + 1]" ng-options="child.name for child in select.children" ng-change="clearChildren($index)"></select>
<hr />
</div>
</div>
<script>
var app = angular.module('app', []);
app.controller('Ctrl', ['$scope', function($scope) {
var data = {
optionType: 'Continent',
name: 'World',
children: [
{
optionType: 'Country',
name: 'Europe',
children: [
{
optionType: 'City',
name: 'France',
children: [
{
optionType: 'Street',
name: 'Paris',
children: [
{
name: 'First'
},
{
name: 'Second'
}
]
},
{
name: 'Quimper'
}
]
},
{
name: 'Italy'
}
]
},
{
optionType: 'Country',
name: 'Asia',
children: [
{
name: 'Japan'
},
{
name: 'China'
}
]
}
]
};
$scope.selects = [data]
$scope.clearChildren = function (index) {
$scope.selects.length = index + 2;
};
}]);
</script>
</body>
</html>
To go to the children in your hierachy is not as hard as it may seem. If you set up your select with angular and let it do most of the selection for you (for example using ng-options instead of ng-repeating the tag itself), and tell it what options there are, then the list of children you are trying to render just becomes a standard ng-repeat of the children that were picked from the select above.
I modified your plunker to show you how you could accomplish that a slightly different way.
http://plnkr.co/edit/zByFaVKWqAqlR9ulxEBt?p=preview
Main points I changed were
$scope.expandSelects = function() {
var select = data[$scope.selected.name];
if (select) {
console.log('changed');
console.log(select);
$scope.chosen = select;
}
}
Here i just grab the chosen item which the will use. Then the ends up looking like.
<ul>
<li ng-repeat="item in chosen.children">{{ item.name }}</li>
</ul>
The only other set up that was really needed was setting up the with ng-options and giving it a model to bind to.
<select ng-options="child.name for child in selects.children"
ng-model="selected" ng-change="expandSelects()">
</select>
Use can use a filter on the second select to filter de options based on the previous selection.
For example, you can have a first selection to choose the continent:
<select ng-options="c for c in continents" ng-model="selectedContinent" ></select>
and a second selection for the coutries:
<select ng-options="c.name for c in countries | filter : {parent:selectedContinent}" ng-model="selectedCountry" ></select>
Made a fiddle with a simplified data structured just to show how the filter works: http://jsfiddle.net/marcosspn/oarL4n78/

Angular: How to filter by deep object property in array?

I have an objects formatted like this:
id: 1,
name: MyObj
properties: {
owners: [
{
name:owner1,
location: loc1
},
{
name:owner2,
location: loc1
}
]
}
Number of owners is different for each object. When I try to filter it using ng-repeat with filter:searchBox and search box inputs
<input name="search-filter" class="form-control" type="search" ng-model="searchBox.properties.title" />
<input name="search-filter" class="form-control" type="search" ng-model="searchBox.properties.owners" />
filtering by title works perfectly, however owners filtering doesn't work at all but I supposed it will filter based on both location and name. What am I doing wrong?
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.objs =
{
id: 1,
name: 'MyObj',
properties: {
owners: [
{
name: 'owner1',
location: 'loc1'
},
{
name: 'owner2',
location: 'loc2'
}
]
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<input name="search-filter" class="form-control" type="search" placeholder="Search by location" ng-model="searchBox.properties.location" />
<input name="search-filter" class="form-control" type="search" placeholder="Search by name" ng-model="searchBox.properties.owners" />
<div ng-repeat="owner in objs.properties.owners | filter:{'location': searchBox.properties.location} |filter:{'name': searchBox.properties.owners}">
{{owner}}
</div>
</div>
You can filter manually
var list = [
{
id: 1,
name: 'MyObj',
properties: {
owners: [
{
name: 'owner1',
location: 'loc1'
},
{
name: 'owner2',
location: 'loc1'
}
]
}
}
];
function filter(filter) {
return list.filter(function(item) {
return item.properties.owners.find(function(owner) {
return Object.keys(filter).every(function(key) {
return filter[key] === owner[key];
});
});
});
}
console.log(filter({ name: 'owner1', location: 'loc1' }));
I used es6 shim for that.

Categories