Filter with JSON in angular 6 - javascript

cities.json
[
{ "id": "1", "name": "Mumbai", "state": "Maharashtra" },
{ "id": "2", "name": "Delhi", "state": "Delhi" },
{ "id": "3", "name": "Bengaluru", "state": "Karnataka" },
{ "id": "4", "name": "Ahmedabad", "state": "Gujarat" },
{ "id": "5", "name": "Hyderabad", "state": "Telangana" },
{ "id": "6", "name": "Chennai", "state": "Tamil Nadu" }
]
mycomponent.html
<div class="search-container">
<h2>Find Location</h2>
<input #searchBoxL id="search-box-loc" (input)="searchForLocation(searchBoxL.value)" [(ngModel)]="selectedResultfilocation"
placeholder="city, province or region" />
<button (click)="searchJobMethod()"><i class="fa fa-search"></i></button>
<ul class="search-result">
<li *ngFor="let loc of searchFindLoopForLocation">
<a (click)="searchBoxL.value = loc;selectedResultfilocation = loc;">{{ loc }}</a>
</li>
</ul>
</div>
mycomponent.ts
selectedResultfilocation: string;
SearchResultResponseForlocation;
searchFindLoopForLocation;
searchForLocation(term: string): void {
this.searchResultMethodForLocation(term);
}
searchResultMethodForLocation(fl: string){
this.http.get('/assets/js/cities.json' + term).pipe(
).subscribe(
data => {
this.SearchResultResponseForlocation = data.json();
console.log(this.SearchResultResponseForlocation[0].name);
this.searchFindLoopForLocation =
this.SearchResultResponseForlocation;
},
error => {
console.log("Error in recieving data");
},
() => {
console.log(this.SearchResultResponse);
}
);
}
My Question is how to filter the name from the given JSON structure in Angular 6. when I will enter location name I can able to get all the recommendations of name. Please help me how to do this, I am totally new in angular 6.

If I'm getting your question right, you don't need something angular specific; You can always filter a JSON in javaScript as follows -
var data = [
{ "id": "1", "name": "Mumbai", "state": "Maharashtra" },
{ "id": "2", "name": "Delhi", "state": "Delhi" },
{ "id": "3", "name": "Bengaluru", "state": "Karnataka" },
{ "id": "4", "name": "Ahmedabad", "state": "Gujarat" },
{ "id": "5", "name": "Hyderabad", "state": "Telangana" },
{ "id": "6", "name": "Chennai", "state": "Tamil Nadu" }
];
var newData = filterData('Mumbai');
function filterData(locationName) {
return data.filter(object => {
return object['name'] == locationName;
});
}
console.log(newData);
If you need help related to implementation, refer the following -
<input #searchBoxL id="search-box-loc" [(ngModel)]="selectedResultfilocation" (ngModelChange)="searchJobMethod()"
placeholder="city, province or region" />
searchJobMethod() {
searchFindLoopForLocation = data.filter(object => {
return object['name'] == selectedResultfilocation;
});
}

Can you try this and let me know... a simple stackblitz would have helped here greatly
/* define SearchResultResponseForlocation as an array... i have used any but you should define a class for your object as per cities.json*/
SearchResultResponseForlocation:any[];
searchResultMethodForLocation(fl: string){
this.http.get('/assets/js/cities.json' + term).pipe(
).subscribe(
data => {
this.SearchResultResponseForlocation = JSON.parse(data);
console.log(this.SearchResultResponseForlocation[0].name);
this.searchFindLoopForLocation =
this.SearchResultResponseForlocation;
},
error => {
console.log("Error in recieving data");
},
() => {
console.log(this.SearchResultResponse);
}
);
}

An example to filter by name
HTML -
<input type="text" [ngModel]="filterBy" (ngModelChange)="filter($event)" />
In a component class -
filterBy: string = "";
filter(value) {
this.filterBy = value;
this.searchFindLoopForLocation = this.searchFindLoopForLocation.filter(obj => obj.name == value);
}

Ts File :
filterSearching() {
this.userList = this.userList.filter(obj => (obj['id'] == this.locationName)||
(obj['email'] == this.locationName) ||(obj['phone_no'] == this.locationName) ||
(obj['first_name'] == this.locationName) || (obj['last_name'] == this.locationName));
}
In the modelChange() function call the original list again . So then When a new value is searched the original data table is showed before clicked Search.
Html :
<div class="col-sm-6 row">
<input type="text" [(ngModel)]="locationName"
(ngModelChange)="modelChange()" />
<button (click)="filterSearching()" >Search</button>
</div>

Related

Check if all the key/value paris of a nested object are present in an array of objects

I have some data in the following format:
const data = [
{
"region": "London",
"code": "0",
"airport": "Heathrow",
"messages": [
{
"date": 1617063225,
"region": "London",
"message": "This is a test message"
}
]
},
... // 300 more objects in the same format
]
I would like to test whether the above array contains an object with all the key/values as this partial object:
const obj = {
"region": "London",
"airport": "Heathrow",
"messages": [
{
"region": "London",
"message": "This is a test message"
}
]
}
Note obj does not have all the properties from the objects in data and the same applies to the messages array - there are some properties missing (like date). To test whether data contains all the properties of obj, I tried the following:
const exists = data.some(0 => {
return Object.keys(obj).some(k => {
return Object.keys(o).indexOf(k)>-1 && obj[k]===o[k];
});
});
The above only checks one level deep i.e. the messages array is not compared deeply.
Since I want this for Jest, I have also tried the following:
expect(data).toEqual(
expect.arrayContaining([
expect.objectContaining(obj)
])
);
The second approach above does not take into account the missing properties in the objects inside messages array.
Could someone please help me achieve the above?
You can do this:
for(*loop through array*) {
if(!obj[i].region === undefined) {
//This object would be miising data
//Do this for every key
}
}
Here is a solution if you have multiple objects in the nested array, for both data and obj to be compared with.
const data = [{
"region": "London",
"code": "0",
"airport": "Heathrow",
"messages": [{
"date": 1617063225,
"region": "Londonn",
"message": "This is a test messageee"
},{
"date": 1617063225,
"region": "London",
"message": "This is a test message"
},{
"date": 1617063225,
"region": "London",
"message": "This is a test message"
}]
},
{
"region": "London",
"code": "1",
"airport": "Heathrow",
"messages": [{
"date": 1617063226,
"region": "London",
"message": "This is a test message"
},{
"date": 1617063225,
"region": "London",
"message": "This is a test message"
},{
"date": 1617063225,
"region": "London",
"message": "This is a test message"
}]
}
]
const obj = {
"region": "London",
"airport": "Heathrow",
"messages": [{
"region": "London",
"message": "This is a test message"
},{
"region": "Londonn",
"message": "This is a test messageee"
},{
"region": "London",
"message": "This is a test message"
}]
}
function compareObj(x, y) {
let objectsAreSame = true;
for(let prop in x) {
if(x[prop] !== y[prop]) {
objectsAreSame = false;
break;
}
}
return objectsAreSame;
}
const compare = (data, obj)=> {
return data.some(o => {
return Object.keys(obj).every(k => {
if (Array.isArray(obj[k])) {
let cond
for(let i=0; i<obj[k].length; i++){
o[k].some(el => {
return cond = compareObj(obj[k][i], el)
})
if(cond === false) return cond
}
return cond;
} else {
return obj[k] === o[k]
}
});
});
}
console.log(compare(data, obj))
You can do something like this. But this only works if the nested array has only one object in it. You can adjust it though to loop through it if needed.
const data = [{
"region": "London",
"code": "0",
"airport": "Heathrow",
"messages": [{
"date": 1617063225,
"region": "London",
"message": "This is a test message"
}]
},
{
"region": "Londonn",
"code": "1",
"airport": "Heathrow",
"messages": [{
"date": 1617063226,
"region": "London",
"message": "This is a test messageee"
}]
}
]
const obj = {
"region": "London",
"airport": "Heathrow",
"messages": [{
"region": "London",
"message": "This is a test message"
}]
}
const compare = (data, obj)=> {
return data.some(o => {
return Object.keys(obj).every(k => {
if (Array.isArray(obj[k])) {
return compare(o[k], obj[k][0])
} else {
return obj[k] === o[k]
}
});
});
}
console.log(compare(data, obj))

Javascript filter for multidimensional json object

Can't use javascript filter in multi-dimensional object.
var object = [{
"id": "1",
"name": "General",
"cards": [{
"id": "1",
"name": "shawn"
}, {
"id": "2",
"name": "neo"
}]
}, {
"id": "2",
"name": "CEO",
"cards": [{
"id": "1",
"name": "Raman"
}, {
"id": "2",
"name": "Sheena"
}]
}]
function searchFor(item) {
return item.cards.filter(
(card) => {
return card.name.indexOf("Raman") !== -1;
}
);
}
var filtered = object.filter(searchFor);
console.log(filtered);
This is how I am trying, inside the searchFor card.name I am getting the correct card name but filtering is returning all the cards.Its not filtering.
Could any help me with this.
An empty array isn't considered falsey in Javascript. So instead of returning the result of filtering the cards array, test its length.
var object = [{
"id": "1",
"name": "General",
"cards": [{
"id": "1",
"name": "shawn"
}, {
"id": "2",
"name": "neo"
}]
}, {
"id": "2",
"name": "CEO",
"cards": [{
"id": "1",
"name": "Raman"
}, {
"id": "2",
"name": "Sheena"
}]
}]
function searchFor(item) {
return item.cards.filter(
(card) => {
return card.name.indexOf("Raman") !== -1;
}
).length != 0;
}
var filtered = object.filter(searchFor);
console.log(filtered);
You were returning the filtered array, which would produce a TRUE result whenever cards existed. So you can just turn that into a boolean, by saying when the item.cards.filter(...).length > 0.
var object = [{
"id": "1",
"name": "General",
"cards": [{
"id": "1",
"name": "shawn"
}, {
"id": "2",
"name": "neo"
}]
}, {
"id": "2",
"name": "CEO",
"cards": [{
"id": "1",
"name": "Raman"
}, {
"id": "2",
"name": "Sheena"
}]
}]
var searchFor = (card) => card.name.indexOf("Raman") > -1;
var filteredCards = object.reduce((cards, item) => cards.concat(item.cards.filter(searchFor)), []);
var filteredObj = object.map(i => {
i.cards = i.cards.filter(searchFor);
return i;
}).filter(i => i.cards.length)
console.log(filteredCards, filteredObj)
Updated
I updated the code snippet to produce either the cards which were found. I also provide a method for returning all objects which contain the needed cards, and filter out the other cards.
// HTML Part
<div class="filter-list">
<button class="filter" data-filter-key="all">all</button>
<button class="filter" data-filter-key="open">open</button>
<button class="filter" data-filter-key="done">done</button>
</div>
// CSS Part
.filter:hover,
.filter:focus,
[data-active-filter="all"] .filter[data-filter-key="all"],
[data-active-filter="done"] .filter[data-filter-key="done"],
[data-active-filter="open"] .filter[data-filter-key="open"] {
text-decoration: underline;
}
[data-active-filter="open"] [data-completed="true"],
[data-active-filter="done"] [data-completed="false"] {
display: none;
}
// Script Part
(function () {
const mainNode = document.querySelector("main");
const filters = document.querySelector(".filter-list");
for (const filter of filters.children) {
filter.addEventListener("click", () => {
mainNode.setAttribute(
"data-active-filter",
filter.getAttribute("data-filter-key")
);
});
}
mainNode.setAttribute("data-active-filter", "all");
})();

Javascript - How to create a cascading drop-down list of country & cities with one country selected as default in AngularJS?

I want to create a Country-city cascading drop down , when the country will be selected the cities of that specific country will be shown in the 2nd drop-down.
One country will come as default in the 1st or country drop-down , let USA be the default country.
Again one state will be the default of the 2nd drop-down - say New York for USA, London for UK, Moscow for Russia, Madrid for Spain & Delhi for India.
The following is my JSON data.
[{
"id": "1", "name":"USA",
"cities": [{
"id": "1",
"name": "New York"
}, {
"id": "2",
"name": "Los Angeles"
}]
}, {
"id": "2", "name":"UK",
"cities": [{
"id": "3",
"name": "London"
}, {
"id": "4",
"name": "Glasgow"
}]
},
{
"id": "3", "name":"Russia",
"cities": [{
"id": "5",
"name": "Moscow"
}, {
"id": "6",
"name": "St. Petersburg"
}]
},
{
"id": "4", "name":"Spain",
"cities": [{
"id": "7",
"name": "Madrid"
}, {
"id": "8",
"name": "Barcelona"
}]
},
{
"id": "5", "name":"India",
"cities": [{
"id": "9",
"name": "Delhi"
}, {
"id": "10",
"name": "Mumbai"
}]
}]
I tried doing this but failed to keep the default country & have a default city for every country.
I am using Angular v1 & vanilla JS (no JQuery). I do not want to use angular.forEach
I am unable to implement the default Country in the 1st drop-down & default City for that particular country in the 2nd drop-down
This a way how you can achieve this by using data-ng-options (ng-options):
Hope this helps.
(function() {
var app = angular.module("app", []);
app.controller("Controller", ["$scope", function($scope) {
$scope.title = "Demo";
$scope.data = [{
"id": "1",
"name": "USA",
"cities": [{
"id": "1",
"name": "New York"
}, {
"id": "2",
"name": "Los Angeles"
}]
}, {
"id": "2",
"name": "UK",
"cities": [{
"id": "3",
"name": "London"
}, {
"id": "4",
"name": "Glasgow"
}]
}, {
"id": "3",
"name": "Russia",
"cities": [{
"id": "5",
"name": "Moscow"
}, {
"id": "6",
"name": "St. Petersburg"
}]
}, {
"id": "4",
"name": "Spain",
"cities": [{
"id": "7",
"name": "Madrid"
}, {
"id": "8",
"name": "Barcelona"
}]
}, {
"id": "5",
"name": "India",
"cities": [{
"id": "9",
"name": "Delhi"
}, {
"id": "10",
"name": "Mumbai"
}]
}];
$scope.country = $scope.data[0]; // Let USA be the default country.
$scope.city = $scope.country.cities[0]; // Show the first city of USA by default.
$scope.setCities = function(country) {
$scope.city = country.cities[0];
};
}]);
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="app">
<div data-ng-controller="Controller">
<h3 data-ng-bind="title"></h3>
<label>Country:</label>
<select data-ng-model="country" data-ng-change="setCities(country)" data-ng-options="c as c.name for c in data">
</select>
<label>Cities:</label>
<select data-ng-model="city" data-ng-options="ci as ci.name for ci in country.cities">
</select>
</div>
</div>
Pure JavaScript code. Just for your reference, in case you really can't figure it out. But next time let us know what at least you have tried.
<select id="ddlCountries" onchange="onChange()"></select>
<select id="ddlCities"></select>
<script>
var ddlCountries = document.getElementById("ddlCountries");
var ddlCities = document.getElementById("ddlCities");
var data = []; // your json array
var defaultCountry = data[0];
loadAllCountries();
loadDefaultCities();
function loadAllCountries() {
for (var i = 0; i < data.length; i++) {
var currentCountry = data[i];
addCountry(currentCountry);
}
}
function loadDefaultCities() {
addCities(defaultCountry.cities, defaultCountry);
}
function addCountry(currentCountry) {
var option = document.createElement("option");
option.text = currentCountry.name;
option.value = currentCountry.id;
ddlCountries.appendChild(option);
}
function addCities(cities, currentCountry) {
for (var i = 0; i < cities.length; i++) {
var option = document.createElement("option");
option.text = cities[i].name;
option.value = cities[i].id;
ddlCities.appendChild(option);
ddlCities.selectedIndex = 0;
}
}
function onChange() {
var selectedCountry = data.find(findById);
clearDropdownlist(ddlCities);
addCities(selectedCountry.cities, selectedCountry);
}
function findById(country) {
return country.id == ddlCountries.value;
}
function clearDropdownlist(ddl) {
while (ddl.firstChild) {
ddl.removeChild(ddl.firstChild);
}
}
</script>

Remove duplicate objects, but push property to array on remaining object

I have an array of objects like so:
[
{
"id": "1",
"location": "US"
},
{
"id": "7",
"location": "US"
},
{
"id": "1",
"location": "France"
},
{
"id": "1",
"location": "China"
}
]
I would like to end up with a resulting array that looks like this:
[
{
"id": "1",
"locations": ["US", "France", "China"]
},
{
"id": "7",
"locations": ["US"]
}
]
Is there a solid way to accomplish this using underscore?
I'm contemplating looping through the array and for each id looping through the rest of the array and pushing location values to a locations array on that first object (by id), then at the end removing all duplicate objects (by id) which do not contain a locations property.
This is different from existing questions on SO that simply ask about removing duplicates. I am aiming to remove duplicates while also holding on to certain property values from these duplicates in an array on the 'surviving' object.
Solution in plain Javascript
var data = [{ "id": "9" }, { "id": "1", "location": "US" }, { "id": "7", "location": "US" }, { "id": "1", "location": "France" }, { "id": "1", "location": "China" }],
result = [];
data.forEach(function (a) {
a.location && !result.some(function (b) {
if (a.id === b.id) {
b.locations.push(a.location);
return true;
}
}) && result.push({ id: a.id, locations: [a.location] });
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
You can use reduce function to transform your array.
var data = [
{ "id": "1", "location": "US" },
{ "id": "7", "location": "US" },
{ "id": "1", "location": "France" },
{ "id": "1", "location": "China" }
];
var result = data.reduce(function (prev, item) {
var newItem = prev.find(function(i) {
return i.id === item.id;
});
if (!newItem) {
prev.push({id: item.id, locations: [item.location]});
} else {
newItem.locations.push(item.location);
}
return prev;
}, []);
And a version using underscore:
var result = _.chain(data)
.groupBy('id')
.map(function(group, id){
return {
id: id,
locations: _.pluck(group, 'location')
}
})
.value();

Jquery : transform nested json object to another json object

In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)

Categories

Resources