using angular.forEach in filter - angularjs

I have an array (1) with some id's and another array (2) with creatures, they have id (like in first array) and names. And I want to create new array (it will be looks like (1) id array, but only with id that in (2)). So I think that I need use filter.
(1)
$scope.main = ['dog', 'cat', 'bird', 'bug', 'human'];
(2)
$scope.creatures = [
{
id: 'cat',
name : 'fluffy'
},
{
id: 'cat',
name : 'mr.Kitty'
},
{
id: 'human',
name: 'Rachel'
},
{
id: 'cat',
name : 'Lucky'
},
{
id: 'cat',
name: 'Tom'
}
];
filter:
$scope.results = $scope.main.filter(function(item) {
angular.forEach($scope.creatures, function(creature) {
return item === creature.id;
});
});
I expect that it will be
$scope.results === ['cat', 'human'];
But I have
$scope.results // [0] empty array
Where I'm wrong? Plnkr example

It is not working because you are returning in the first iteration itself inside forEach loop. You can get it working as shown below :
Updated Plunker
$scope.results = [];
$scope.main.filter(function(item) {
angular.forEach($scope.creatures, function(creature) {
if(item === creature.id){
if( $scope.results.indexOf(item) === -1){
$scope.results.push(item);
}
}
});
});
Instead of looping again inside the filter, we can get the ids out of creatures array first and then filter them in main array like below :
$scope.results = [];
$scope.ids = $scope.creatures.map(function (creature){
return creature.id;
});
$scope.ids.map(function (id){
if($scope.main.indexOf(id) !== -1){
if( $scope.results.indexOf(id) === -1){
$scope.results.push(id);
}
}
});
console.log($scope.results);

Made few changes in your plunker, it is working now. Can you check with this code.
var app = angular.module('App', []);
app.controller('Ctrl', function($scope, $timeout){
$scope.main = ['dog', 'cat', 'bird', 'bug', 'human'];
$scope.creatures = [
{
id: 'cat',
name : 'fluffy'
},
{
id: 'cat',
name : 'mr.Kitty'
},
{
id: 'human',
name: 'Rachel'
},
{
id: 'cat',
name : 'Lucky'
},
{
id: 'cat',
name: 'Tom'
}
];
var array = [];
$scope.call = function() {
angular.forEach($scope.main,function(item){
angular.forEach($scope.creatures, function(creature) {
if(item == creature.id){
// console.log('item',item,' creatureId',creature.id);
if(array.indexOf(item) < 0 ){
array.push(item);
}
console.log(array);
}
});
$scope.results = array;
});
};
$scope.call();
console.log('result ',$scope.results);
});

Related

Array is repeating same item Issue

Anyone can give me any suggestions ? I am trying to add an item in every 2 content. I couldn't see anything wrong with the code but why is the MyAds number repeating in all my ads entries ? it is supposed to start from MyAds0 and adding on.
MyAds2
Content1
Content2
MyAds2
Content3
Content4
MyAds2
Content5
Here is my code
const dummyData = [
{
name: 'Content1',
subtitle: 'Content1'
},
{
name: 'Content2',
subtitle: 'Content2'
},
{
name: 'Content3',
subtitle: 'Content3'
},
{
name: 'Content4',
subtitle: 'Content4'
},
{
name: 'Content5',
subtitle: 'Content5'
},
]
let TheData = InsertContent();
function InsertContent () {
let thisdata = [];
let adscounter = 0;
let tmpData = [ {name:'tmp', subtitle:'tmp'}];
for (let i=0; i < dummyData.length; i++){
if (Number.isInteger(i/2)) {
tmpData[0].name = 'MyAds' + adscounter;
tmpData[0].subtitle = 'My MyAds Sub' + adscounter;
thisdata = [...thisdata, tmpData[0]];
adscounter = adscounter + 1;
}
thisdata = [...thisdata, dummyData[i]];
}
return thisdata;
}
Actually the Problem is not with the logic but with the way you are using object and array with spread operator. You really don't have to use a object at first index in a array Instead you can directly use the object with spread operator to store into the array. I just modified your code to make it work as per your requirements.
const dummyData = [
{
name: 'Content1',
subtitle: 'Content1'
},
{
name: 'Content2',
subtitle: 'Content2'
},
{
name: 'Content3',
subtitle: 'Content3'
},
{
name: 'Content4',
subtitle: 'Content4'
},
{
name: 'Content5',
subtitle: 'Content5'
},
];
let TheData = InsertContent();
console.log(TheData);
function InsertContent () {
let thisdata = [];
let adscounter = 0;
let tmpData = {name:'', subtitle:''};
for (let i=0; i < dummyData.length; i++){
if (Number.isInteger(i/2)) {
tmpData = {
name: 'MyAds' + adscounter,
subtitle : 'My MyAds Sub' + adscounter
};
thisdata = [...thisdata, tmpData];
adscounter = adscounter + 1;
}
thisdata = [...thisdata, dummyData[i]];
}
return thisdata;
}

Converting array of objects into nested form

I have an array of objects in this form
nnz=[{
"verb":"has",
"nouns": "employees"
},
{
"verb":"has",
"nouns": "managers"
},
{
"verb":"have",
"nouns": "departments"
}
]
but i want to convert it into this form
[ {
"verb":"has",
"nouns": ["employees", "managers"]
},
{
"verb":"have",
nouns:["departments"]
}
]
and this work has to be done from client side. I am working in node.js. I want to allow user to select multiple nouns against each verb and when user selects nouns against verb it should be saved into an array in the above given form. I am unable to figure it out how can i implement this logic.
Update: we have to check verb too.now it became more tricky.
You can do somethong like this, using some Array built-in functions:
const array = [
{
"verb":"has",
"nouns": "employees"
},
{
"verb":"has",
"nouns": "managers"
},
{
"verb":"has",
"nouns": "departments"
}
]
const aggregated = array.reduce( (arr, el) =>{
let found = arr.find(ll => ll.verb == el.verb);
if(found) found.nouns.push(el.nouns);
else arr.push({verb : el.verb, nouns : [el.nouns] })
return arr;
}, []);
console.log(aggregated);
First create a temporary object that uses the verb value as keys then iterate your existing data pushing nouns to corresponding array in that temporary object.
Then map the temporary object to a new array.
nnz = [{
"verb": "has",
"nouns": "employees"
}, {
"verb": "has",
"nouns": "managers"
}, {
"verb": "has",
"nouns": "departments"
}]
var tmp = {};
nnz.forEach(function(item) {
tmp[item.verb] = tmp[item.verb] || {
verb: item.verb,
nouns: []
};
tmp[item.verb].nouns.push(item.nouns);
});
var results = Object.keys(tmp).map(function(key) {
return tmp[key];
});
console.log(results);
Try these two approaches as per your requirement. I hope it will work as per the expectation .
First Approach :
When you know the property names :
var nnz = [{
"verb":"has",
"nouns": "employees"
},
{
"verb":"has",
"nouns": "managers"
},
{
"verb":"has",
"nouns": "departments"
}
];
var newObj = {};
var nouns = [];
for (var i in nnz) {
nouns.push(nnz[i].nouns);
newObj.verb = nnz[i].verb;
newObj.nouns = nouns;
}
nnz = newObj;
console.log(nnz);
Second Approach :
When you don't know the property names :
var nnz = [{
"verb":"has",
"nouns": "employees"
},
{
"verb":"has",
"nouns": "managers"
},
{
"verb":"has",
"nouns": "departments"
}
];
var newObj = {};
var nounsArr = [];
for (var i in nnz) {
nounsArr.push(nnz[i][Object.keys(nnz[i])[1]])
nnz[i][Object.keys(nnz[i])[1]] = nounsArr;
var Objlen = Object.keys(nnz[i]).length;
for (var j=0;j<Objlen;j++) {
var objKeys = Object.keys(nnz[i])[j];
newObj[objKeys] = nnz[i][objKeys];
}
}
nnz = newObj;
console.log(nnz);

AngularJS filter to ng-repeat, exclude elements, if they in second array

I need filter for ng-repeat, that explode elements in "general" array, if element exist in "suggest" array (by id field).
$scope.general= [{id: 21323, name: 'alex'}, {id: 8787, name: 'maria'}, {id: 8787, name: 'artem'}];
$scope.suggest = [{id: 21323, name: 'alex'}, {id: 8787, name: 'maria'}];
<div ng-repeat="elem in general">{{elem.name}}</div>
You should create your own custom filter and you'll probably want to use Array.prototype.filter.
You said you wanted to exclude by the property id. The following filler optionally allows specifying a property. If the property is not specified, then the objects are excluded by strict equality (the same method used by the ===, or triple-equals, operator) of the objects.
angular.module('myFilters', [])
.filter('exclude', function() {
return function(input, exclude, prop) {
if (!angular.isArray(input))
return input;
if (!angular.isArray(exclude))
exclude = [];
if (prop) {
exclude = exclude.map(function byProp(item) {
return item[prop];
});
}
return input.filter(function byExclude(item) {
return exclude.indexOf(prop ? item[prop] : item) === -1;
});
};
});
To use this filter in your html:
<div ng-repeat="elem in general | exclude:suggest:'id'">{{elem.name}}</div>
Here is an example jsfiddle:
https://jsfiddle.net/6ov1sjfb/
Note that in your question artem's id matches maria's thus both artem and maria were filtered. I changed artem's id in the plunker to be unique to show that the filter works.
Try this :
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.general = [{
id: 21323,
name: 'alex'
}, {
id: 8787,
name: 'maria'
}, {
id: 8787,
name: 'artem'
}];
$scope.suggest = [{
id: 21323,
name: 'alex'
}, {
id: 8787,
name: 'maria'
}];
$scope.filteredArray = function () {
return $scope.general.filter(function (letter) {
for (i = 0; i < $scope.suggest.length; i++) {
return $scope.suggest[i].id !== letter.id
}
});
};
}
and
<div ng-repeat="elem in filteredArray(letters)">{{elem.name}}</div>
check out the fiddle : http://jsfiddle.net/o2er6msv/
Note: please chk ur id, they are duplicated

Group by on a complex object in AngularJS

I've an array that contains assignments of employees on tasks, it looks like something like this:
$scope.assignments = [
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Kill everyone", project:"Destruction"
},
date: {
day:"01/01", year:"1985"
}
},
{
employee: {
id:"2", firstname:"Luke", lastname:"Skywalker"
},
task: {
name:"Find daddy", project:"Star Wars"
},
date: {
day:"65/45", year:"1000000"
}
},
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Save the world", project:"Destruction"
},
date: {
day:"02/01", year:"1985"
}
}
];
I would like to group by employee, for having something like this:
$scope.assignmentsByEmployee = [
{ //First item
id:"1",
firstname:"John",
lastname:"Rambo",
missions: [
{
name:"Kill everyone",
date:"01/01",
year:"1985"
},
{
name:"Save the world",
date:"02/01",
year:"1985"
}
]
},
{ //Second item
id="2",
firstname:"Luke",
lastname:"Skywalker",
missions: [
name:"Find daddy",
date:"65/45",
year:"1000000"
]
}
];
Is their a simple way to do this ? I tried something with a double forEach, but it leads me nowhere.
Hope I'm understandable :)
Thanks !
You should just be able to loop through the assignments array and create a 'keyed array' (which just means using an object in JavaScript) on employee ID. Then you just fill up the missions array as required.
Something like
// initialise a holding object
var assignmentsByEmployee = {};
// loop through all assignemnts
for(var i = 0; i < $scope.assignments.length; i++) {
// grab current assignment
var currentAssignment = $scope.assignments[i];
// grab current id
var currentId = currentAssignment.employee.id;
// check if we have seen this employee before
if(assignmentsByEmployee[currentId] === undefined) {
// we haven't, so add a new object to the array
assignmentsByEmployee[currentId] = {
id: currentId,
firstname: currentAssignment.employee.firstname,
lastname: currentAssignment.employee.lastname,
missions: []
};
}
// we know the employee exists at this point, so simply add the mission details
assignmentsByEmployee[currentId].missions.push({
name: currentAssignment.task.name,
date: currentAssignment.date.day,
year: currentAssignment.date.year
});
}
These leaves assignmentsByEmployee as an object, but you can simply foreach through it and convert it back to an array if required. E.g:
$scope.assignmentsByEmployee = [];
for(var employeeId in assignmentsByEmployee) {
$scope.assignmentsByEmployee.push(assignmentsByEmployee[employeeId]);
}

can not extract info from $scope in angularjs

I have a code as follow:
function getdata($scope){
$scope.todos = [
{name:"john",data:"1 2 3"},
{name:"Marry",data:"6 7 8"},
{name:"Edward",data:"2 4 5"}
];
var seri=new Array();
for(var item in $scope.todos)
{
seri.push(
{
name: item.name,
data: [1, 0, 4]
});
}
console.log(seri);
}
Now when I check the console for the name it returns undefined. what is the problem?
Try
function getdata($scope) {
$scope.todos = [
{ name: "john", data: "1 2 3" },
{ name: "Marry", data: "6 7 8" },
{ name: "Edward", data: "2 4 5" }
];
var seri = new Array();
angular.forEach($scope.todos, function (item, key) {
seri.push({
name: item.name,
data: [1, 0, 4]
});
});
console.log(seri);
//you can get data from this by using return
}
When you loop through an array in javascript the item is an integer with the position of the value in the array. You'll need to use this position to get the true item, like this:
for (var i in $scope.todos) {
var item = $scope.todos[i];
...
}
If the function is inside a controller and being called as such you should declare it as
$scope.getData = function() {
}
And then it should work fine. If the function is NOT to be part of the scope and you are passing the scope in then try receiving the parameter as "scope" and not "$scope" which has a special meaning in Angular.
this is not how you iterate array in javascript (see materik answer).
you can alternatively use angular.forEach to iterate the todos array like this:
angular.forEach($scope.todos, function(item)
{
seri.push(
{
name: item.name,
data: [1, 0, 4]
});
});

Resources