Angular2 removing duplicates from an JSON array - arrays

I have a problem with filter in my JSON array when I move my app to Angular2 . In Angular 1.x that was easier. I used 'unique' in filter and this remove all duplicates.
apps:
{"app":"database_1",
"host":"my_host1",
"ip":"00.000.00.000"
},
{"app":"database_1",
"host":"my_host1",
"ip":"00.000.00.000"
},
{"app":"database_2",
"host":"my_host2",
"ip":"00.000.00.000"
},
{"app":"database_2",
"host":"my_host2",
"ip":"00.000.00.000"
}
Part of html code:
<div *ngFor='#appsUnique of apps '>
<div class="row dashboard-row">
<div class="col-md-2">
<h4>{{appsUnique.app }}</h4>
</div>
</div>
</div>
And result is:
database_1
database_1
database_2
database_2
I want to get result:
database_1
database_2
How can I remove duplicates from an array?

Mybe it can help you
myList = ["One","two","One","tree"];
myNewList = Array.from(new Set(myList ));

I have a solution for this problem :)
Array.from(new Set([{"app":"database_1",
"host":"my_host1",
"ip":"00.000.00.000"
},
{"app":"database_1",
"host":"my_host1",
"ip":"00.000.00.000"
},
{"app":"database_2",
"host":"my_host2",
"ip":"00.000.00.000"
},
{"app":"database_2",
"host":"my_host2",
"ip":"00.000.00.000"
}].map((itemInArray) => itemInArray.app)))
More about Array.from & Set
Thanks all for help :)

You could use following method:
names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
ngOnInit() {
let filteredNames=this.remove_duplicates(this.names);
console.log(filteredNames);
console.log(this.names);
}
remove_duplicates(arr) {
let obj = {};
for (let i = 0; i < arr.length; i++) {
obj[arr[i]] = true;
}
arr = [];
for (let key in obj) {
arr.push(key);
}
return arr;
}
Hope this helps.

You could use Observable approach as well, It is very simple.
let filteredData = [];
let arrayData = [{
"app": "database_1",
"host": "my_host1",
"ip": "00.000.00.000"
},
{
"app": "database_1",
"host": "my_host1",
"ip": "00.000.00.000"
},
{
"app": "database_2",
"host": "my_host2",
"ip": "00.000.00.000"
},
{
"app": "database_2",
"host": "my_host2",
"ip": "00.000.00.000"
}];
Observable.merge(arrayData)
.distinct((x) => x.app)
.subscribe(y => {
filteredData.push(y)
console.log(filteredData)
});

instead of looping over the normal json array, you can create another array in your corresponding typescript class, and alter this as you see fit. In your html, you can then have the following
html
<div *ngFor='let appsUnique of filteredApps'>
<div class="row dashboard-row">
<div class="col-md-2">
<h4>{{appsUnique.app }}</h4>
</div>
</div>
</div>
Next, you need this filteredApps array in your corresponding typescript class.
typescript
let filteredApps = [];
and in a function you can then create that filteredApps, for example in the onInit method.
onInit()
{
filteredApps = // filter logic
}

You will need trackBy.
Try with:
*ngFor="#appsUnique of posts;trackBy:appsUnique?.app"
Hope it helps.

Related

svelte - using a nested json array with an Each function

I am using cordova-sqlite-porter to export an SQLite table to JSON and then use the JSON exported using svelte.
My code to export the json is:
let myDB = '';
let vetdrugs = [];
myDB = window.sqlitePlugin.openDatabase({ name: "vetcalculators.db", iosDatabaseLocation: "Documents" });
var successFn = function(json, count){
vetdrugs = JSON.stringify(json);
};
cordova.plugins.sqlitePorter.exportDbToJson(myDB, {
successFn: successFn,
dataOnly:true,
tables:['vetADrugs']
});
The resulting JSON is:
{
"data":{
"inserts":{
"vetADrugs":[
{
"drugradio":"single",
"druglabel":"ml",
"conc3":null,
"Id":2,
"dose":10,
"conc1":null,
"maximum":null,
"desc":"",
"title":"Test0",
"notes":"",
"minimum":null,
"conc":100,
"drugconc":"mg/ml",
"conc2":null
},
{
"drugradio":"single",
"druglabel":"ml",
"conc3":null,
"Id":3,
"dose":10,
"conc1":null,
"maximum":4,
"desc":"",
"title":"Test1",
"notes":"",
"minimum":2,
"conc":100,
"drugconc":"mg/ml",
"conc2":null
},
{
"drugradio":"single",
"druglabel":"ml",
"conc3":null,
"Id":4,
"dose":10,
"conc1":null,
"maximum":4,
"desc":"",
"title":"Test2",
"notes":"",
"minimum":2,
"conc":100,
"drugconc":"mg/ml",
"conc2":null
},
{
"drugradio":"single",
"druglabel":"ml",
"conc3":null,
"Id":5,
"dose":10,
"conc1":null,
"maximum":4,
"desc":"",
"title":"Test3",
"notes":"",
"minimum":2,
"conc":100,
"drugconc":"mg/ml",
"conc2":null
}
]
}
}
}
Unfortunately, the JSON is exported as:
{
"data":{
"inserts":{
"vetADrugs":[]...
And I am not able to export it as just:
{
"vetADrugs":[]...
Normally, in svelte I would use an each function like this:
{#each vetADrugs as drugs}
{drugs.title}
{/each}
But I am not sure how to incorporate the "data" and "inserts" part of the JSON into each function. Any help would be appreciated!
ADDENDUM:
I did try the following with no luck:
{#each vetdrugs.data.inserts.vetADrugs as drug}
<p>
{drug.title}
</p>
{/each}
You can use dot notation in the each block.
{#each data.inserts.vetADrugs as drug}
<p>
{drug.title}
</p>
{/each}

Convert json Array to Object on Vue Js 2

I'm trying to convert my data json from an array to an object to be able to consume the data but something went wrong...
Here is the data json sample:
[
{
"id": 1,
"title": "my title",
"imgHero": "../../path/hero.jpg"
}
]
And here is the Vue component:
<template>
<div class="hero">
<img :src="blog.imgHero" alt="hero image" class="heroImg">
<h3 class="heroTitle">{{ blog.title }}</h3>
</div>
</template>
<script>
import tripsJson from '#/data/trips.json'
export default {
name: 'App',
data () {
return {
array: tripsJson,
blog: {}
}
},
created () {
var obj = this.array.reduce(function (acc, cur, i) {
acc[i] = cur
return acc
}, {})
this.blog = obj
console.log(this.blog)
}
}
</script>
Any help or suggestion is more than welcome. Thx

Use scope variable in ng-repeat

I want to use a $scope variable within the ng-repeat attribut, like so :
<div class="userOpinion" ng-if="usersOpinions.length != 0" ng-repeat="userOpinion in {{usersOpinion}}">
But it doesnt seem to work, {{usersOpinion}} remains non-interpreted... How could I manage to make it work?
The Idea is to dynamically change {{usersOpinion}} when clicking on button.
Thanks
Instead of ng-repeat="userOpinion in {{usersOpinion}}" ,change it to ng-repeat="userOpinion in usersOpinions.
You should use like
<div class="userOpinion" ng-if="usersOpinions.length != 0" ng-repeat="userOpinion in usersOpinions">{{userOpinion}}</div>
It should be enough to remove the curly brackets. The ng-repeat is interpreted as code.
<div class="userOpinion" ng-if="usersOpinions.length != 0" ng-repeat="userOpinion in usersOpinion">
The curly brackets tells angular that it should transform the variable into a string before outputting it.
If you want to change it dynamically you need to add ng-click to div tag, something like this
<div class="userOpinion" ng-if="usersOpinions.length != 0" ng-repeat="userOpinion in usersOpinion" ng-click="changeOpinion($index)">
{{userOpinion}}
</div>
and add function to scope
$scope.changeOpinion = function (index) {
$scope.usersOpinion[index] += '1';
}
no you can do whaterver you want with value of that opinion, here is the whole code with both simple array of opinions and objects http://jsfiddle.net/Lvc0u55v/9513/
if I'm understand your question, you can try this
var autoDrops = angular.module('autoDrops', []);
autoDrops.controller('DropsController', function($scope) {
$scope.usersOpinion = [];
$scope.datas = [{
"name": "item01"
}, {
"name": "item02"
}, {
"name": "item03"
}, {
"name": "item04"
}, {
"name": "item05"
}, {
"name": "item06"
}];
$scope.datas1 = [{
"name": "item11"
}, {
"name": "item12"
}, {
"name": "item13"
}, {
"name": "item14"
}, {
"name": "item15"
}, {
"name": "item16"
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="autoDrops" ng-controller="DropsController">
<button ng-click="usersOpinion = datas">
data
</button>
<button ng-click="usersOpinion = datas1">
datas1
</button>
<div>
<div ng-repeat="elem in usersOpinion">
{{elem}}
</div>
</div>
</div>

How to apply dynamic filters in AngularJS

I'm starting to learn AngularJS now and I have some issues with filters.
I need to apply two types of filters and I can't figure out how.
I have a device list JSON that looks like this:
[{
"ID": 1,
"Name": "Device 1",
"Price": 1998.92,
"Colors": [{
"ColorCode": "Red",
"ColorName": "#FF0000"
},
{
"ColorCode": "Green",
"ColorName": "#2EFE2E"
}],
"Type": {
"TypeID": 1,
"TypeName": "Mobile device"
},
"Company": {
"CompanyID": 1,
"CompanyName": "Alcatel"
}
}]
I display the list like this:
<div ng-repeat="device in devices | filter:companyFilters | filter:colorFilters">
<span>{{device.Company.CompanyID}}</span> // 1
<span>{{device.Company.CompanyName}}</span> // Google
<span>{{device.Name}}</span> // Nexus 6P
</div>
I have some filters that I applied but there are two filters that I can't understand how to apply.
Filter 1:
A checkbox list of companies that filters the items by the selected
companies.
Filter 2:
A color filter that when clicking on a color will filter the devices
that has that color
For the company filter I have this checkbox list:
<div ng-repeat="company in deviceCompanies">
<input type="checkbox" data-ng-model="companyFilters" id="{{company.CompanyID}}" data-ng-true-value='{{company.CompanyID}}' data-ng-false-value='' />
<label for="{{company.CompanyID}}">{{company.CompanyName}}</label>
</div>
And on the controller side I have this:
$scope.companyFilters = [];
For the color filter I have this:
<div>
<a ng-click="???">All</a>
<div ng-repeat="color in deviceColors" style="display:inline-block; margin-right:10px;">
<div style="width:20px;height:20px;background-color:{{color.ColorCode}}"></div>
<a ng-model="selColor" data-ng="color.ColorCode" ng-click="colorFilters">{{color.ColorName}}</a>
</div>
</div>
And on the controller:
$scope.colorFilters = function (device) {
if (!$scope.selColor)
return true;
for (var i = 0; i < device.Colors.length; i++) {
if (device.Colors[i].ColorCode == $scope.selColor)
return true;
}
return false;
};
But it doesn't work...
Can anyone please tell me how to apply these filters ?
Since you are using ng-repeat which creates its own scope, anything you do in ng-repeat will not get recognized on the controller scope. Using a tool like ng-inspector or batarang will illustrate this.
I recommend using controllerAs Syntax, in your controller add.
angular.module('myModule').controller('CustomFilterController', function() {
var vm = this;
this.devices = //your list of data
this.companyFilters = [];
this.colorFilters = //your function
}
On your view declare your controller like this:
<div ng-controller='CustomFilterController as custom'>
(Note the value after as can be whatever you want it to be)
Then reference anything on that controller as custom.ThingOnController
EX:
<div ng-repeat="device in custom.devices | filter:custom.companyFilters | filter:custom.colorFilters">
After trying some workarounds, this is what I came up with:
<div ng-repeat="company in deviceCompanies">
<!--the ng-click will call a function that updated an array of values-->
<input type="checkbox" id="{{company.CompanyID}}" ng-click="selectCompany(company.CompanyID)">
<label for="{{company.CompanyID}}">{{company.CompanyName}}</label>
</div>
And the controller part is so simple:
$scope.selectedCompanies = [];
//when the array is upted the filter function will also launch
$scope.selectCompany = function (companyId) {
var i = $.inArray(companyId, $scope.selectedCompanies);
if (i > -1) {
$scope.selectedCompanies.splice(i, 1);
} else {
$scope.selectedCompanies.push(companyId);
}
}
$scope.companyFilter = function (device) {
if ($scope.selectedCompanies.length > 0) {
if ($.inArray(device.Company.CompanyID, $scope.selectedCompanies) < 0)
return;
}
return device;
}
Same goes to the colors filter:
<div>
<a ng-click="selectColor()">All</a>
<div ng-repeat="color in deviceColors" style="display:inline-block; margin-right:10px;">
<div style="width:20px;height:20px;background-color:{{color.ColorCode}}"></div>
<a ng-click="selectColor(color.ColorCode)">{{color.ColorName}}</a>
</div>
</div>
And controller part:
$scope.selectedColor;
$scope.selectColor = function (colorCode) {
$scope.selectedColor = colorCode;
}
$scope.colorFilters = function (device) {
if (!$scope.selectedColor)
return true;
for (var i = 0; i < device.Colors.length; i++) {
if (device.Colors[i].ColorCode == $scope.selectedColor)
return true;
}
return false;
};
And finally, applying the filters:
<div ng-repeat="device in devices | filter:companyFilter | filter:colorFilters">
...
</div>
You can have a look here to see how it works
I think the color filter can be more elegant, but, for now, this does the trick.
If I'll come up with a better solution I'll post it here.

How to select objects that have a certain atribute in a json file in an Angular JS project?

I have a link to an API which lists movies, each movie has title,id etc...
API: http://private-5d90c-kevinhiller.apiary-mock.com/angular_challenge/horror_movies
It also has an offers array inside which contains a 'provider_id' property.
I need to show how many movies are available at which provider.
But I dont know how, the best I came up with was:
{{movie.offers[0].provider_id}}
But that only shows the first provider on each movie.
What I want is to extract how many movies each provider has.
My Html:
<div ng-controller="ProviderController as provider">
<div ng-repeat="movie in provider.movies">
{{movie.offers[0].provider_id}}
</div>
</div>
My Main.js:
app.controller('ProviderController', function($http) {
var provider = this;
provider.movies = [];
$http({
url: 'some/path/horror_movies',
method: "GET",
}).success(function(data) {
provider.movies = data;
});
});
Also this is the structire of the json file:
[{
"id": 140524,
"title": "Dracula Untold",
"offers": [{
"provider_id": 2,
"retail_price": 14.99,
//...
}, {
"provider_id": 2,
"retail_price": 14.99,
}, {
"provider_id": 7,
"retail_price": 14.99,
}, ]
},
{
"id": 138993,
"title": "The Purge: Anarchy",
"offers": [
// ...
]
},
]
Any ideas ? Thanks.
You will need to change the structure of your database to have providers at the top level. A function achieving something like this should iterate over every movies offers, something like this:
function getProviders (movies) {
var providers = [],
movie = {},
offer = {};
for (var i = 0, max = movies.length; i < max; i += 1) {
movie = movies[i];
for (var j = 0; j < movies[i].offers.length; j += 1) {
offer = movie.offers[j];
if (typeof providers[offer.provider_id] === 'undefined') {
providers[offer.provider_id] = { movies: [] };
}
providers[offer.provider_id].movies.push(movie);
}
}
return providers;
}
I started a fiddle here: http://jsfiddle.net/d29tu8fg/1/
Before adding a movie to a provider, you might also want to check, if that movie already exists. You only need to do that though, if – like in your data – a movie can have two different offers from the same provider.
Add the providers to the $scope and in your view show the length:
<div ng-repeat="provider in providers track by $index">
{{provider.movies.length}}
</div>

Resources