Basic loop and if statement issue in AngularJS - angularjs

So I have an angular function that aims to grab some basic details from an array of objects, by looking up using an id, passed into the function.
Anyway, the function works - the first time. That is, it successfully returns the customer name of the first object where the contract id's match. However, if there is more than one contract/object that matches, it only returns the first name.
I understand this must be a basic problem with regards to looping, but can't seem to get it to work!
Thanks so much in advance.
Here is the function:
$scope.getCompanyDetailsByContractId = function(contractId) {
for (var i = $scope.customers.length - 1; i >= 0; i--) {
if ($scope.customers[i].contracts[i].id == contractId ) {
return $scope.customers[i].name;
};
};;
}
And here is the data structures:
$scope.customers = [{
id: 1,
name: "John Inc",
currentContractLength: 12,
currentContractValue: 18000,
startDate: "09/01/2014",
endDate: "09/01/2015",
nextRenewalDate: "09/01/2015",
mrr: 1500,
contracts: [{
id: 234,
status: "won",
contractNumber: 1,
value: 18000,
startDate: "09/01/2014",
endDate: "09/01/2015",
nextRenewalDate: "09/01/2014"
},
{
id: 235,
status: "pending",
contractNumber: 2,
value: 18000,
startDate: "09/01/2015",
endDate: "09/01/2016",
nextRenewalDate: "09/01/2016"
}]
}, {
id: 2,
name: "Peters Company Ltd",
currentContractLength: 3,
currentContractValue: 15000,
startDate: "09/01/2014",
endDate: "09/01/2015",
nextRenewalDate: "09/01/2015",
mrr: 1500,
contracts: [{
id: 543654,
status: "won",
contractNumber: 1,
value: 4200,
startDate: "09/01/2014",
endDate: "09/01/2015",
nextRenewalDate: "09/01/2014"
},
{
id: 54354,
status: "pending",
contractNumber: 2,
value: 18000,
startDate: "09/01/2015",
endDate: "09/01/2016",
nextRenewalDate: "09/01/2016"
}]
}];

It seems you should do 2 loops to look in all possibles contracts.
With the following call you are looking only for the contract with index i
$scope.customers[i].contracts[i].id == contractId
Maybe you should do something like
for (var i = $scope.customers.length - 1; i >= 0; i--) {
for (var j = 0; j < $scope.customers[i].contracts.length; j++) {
if ($scope.customers[i].contracts[j].id == contractId ) {
return $scope.customers[i].name;
};
}
};

Related

Merge two arrays avoiding O(n^2) complexity

Given two arrays, farmers and collections, I want to be able to merge the farmer information to each collection when farmer_id in the collection is equal to id in farmers. if there is no id of the farmer that matches farmer_id in the collection then that collection should have a an empty farmer object
const farmers = [{
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
},
{
id: 11,
name: 'James Bond',
email: 'james#gmail.com'
}
]
const collections = [{
id: 9,
name: 'Book',
farmer_id: 10,
date: 'June'
},
{
id: 10,
name: 'Game',
farmer_id: 11,
date: 'July'
},
{
id: 13,
name: 'Car',
farmer_id: 10,
date: 'August'
},
{
id: 11,
name: 'Wristwatches',
farmer_id: 20,
date: 'August'
}
]
The result should be in this format below
const result = [{
id: 9,
name: 'Book',
farmer_id: 10,
date: 'June',
farmer: {
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
}
},
{
id: 10,
name: 'Game',
farmer_id: 11,
date: 'July',
farmer: {
id: 11,
name: 'James Bond',
email: 'james#gmail.com'
}
},
{
id: 13,
name: 'Car',
farmer_id: 10,
date: 'August',
farmer: {
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
}
},
{
id: 11,
name: 'Wristwatches',
farmer_id: 20,
date: 'August',
farmer: {}
}
]
This is what i have been able to come up with but am stuck right now
function mapper(farmers, collectors) {
for (let k = 0; k < farmers.length; k++) {
const idToFarmerInfo = {};
idToFarmerInfo[farmers[k].id] = farmers[k];
for (let j = 0; j < collectors.length; j++) {
let mapper = idToFarmerInfo[collectors[j].farmer_id];
farmers[mapper] = collectors[j]
}
}
return farmers
}
i followed this link as am trying to avoid O of N squared but O of N complexity
For a better performance you could create a hash of farmers where the complexity is O(N) because we're iterating the farmers list only once.
const farmers = [{ id: 10, name: 'John Doe', email: 'jdoe#gmail.com' }, { id: 11, name: 'James Bond', email: 'james#gmail.com' } ]; const collections = [{ id: 9, name: 'Book', farmer_id: 10, date: 'June' }, { id: 10, name: 'Game', farmer_id: 11, date: 'July' }, { id: 13, name: 'Car', farmer_id: 10, date: 'August' }, { id: 11, name: 'Wristwatches', farmer_id: 20, date: 'August' } ]
var farmers_hash = farmers.reduce((hash, item) => {
hash[item.id] = item;
return hash;
}, {});
console.log(farmers_hash);
The following step is to build the desired output by assigning one farmer using hash keys.
This can be achieved using map method in combination with Object.assign.
const farmers = [{ id: 10, name: 'John Doe', email: 'jdoe#gmail.com' }, { id: 11, name: 'James Bond', email: 'james#gmail.com' } ]; const collections = [{ id: 9, name: 'Book', farmer_id: 10, date: 'June' }, { id: 10, name: 'Game', farmer_id: 11, date: 'July' }, { id: 13, name: 'Car', farmer_id: 10, date: 'August' }, { id: 11, name: 'Wristwatches', farmer_id: 20, date: 'August' } ]
var farmers_hash = farmers.reduce((hash, item) => {
hash[item.id] = item;
return hash;
}, {});
var result = collections.map((item) => {
item.farmer = Object.assign({}, farmers_hash[item.farmer_id])
return item;
});
console.log(result);
As you can see the final complexity is O(N) + O(M) where N is the length of farmers array and M is the length of collections array.
Demo on stackblitz
You can use a more declarative approach and use Array.map and Array.find
const result = collections.map(collection => {
return {
...collection,
farmer: farmers.find(farmer => collection.farmer_id == farmer.id) || {}
};
});
console.log(result);
You can create a Map collection to have O(N) of access to desired farmer by id. Then mapping becomes faster in terms of performance:
const unique = new Map(farmers.map(f=> [f.id, f]));
const result = collections.map(s => ({
...s, farmer_id: unique.get(s.farmer_id) || s.farmer_id
}))
Now mapping of collections has complexity O(N). However, do not forget to sum complexity of making unique farmers. The overall complexity is O(N) + O(M).
An example:
const farmers = [{
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
},
{
id: 11,
name: 'James Bond',
email: 'james#gmail.com'
}
];
const collections = [{
id: 9,
name: 'Book',
farmer_id: 10,
date: 'June'
},
{
id: 10,
name: 'Game',
farmer_id: 11,
date: 'July'
},
{
id: 13,
name: 'Car',
farmer_id: 10,
date: 'August'
},
{
id: 11,
name: 'Wristwatches',
farmer_id: 20,
date: 'August'
}
];
const unique = new Map(farmers.map(f=> [f.id, f]));
const result = collections.map(s => ({
...s, farmer_id: unique.get(s.farmer_id) || s.farmer_id
}))
console.log(result);

How to get total of numbers in an array from SharePoint list items

I'm creating a spfx web part using Reactjs. I have a function getting an array of items from a SharePoint list that includes a number column of "Hours". I need to get a total for all the hours that have been returned but can't figure out how to calculate that.
I feel like I'm missing something simple but I've run through all kinds of loops and for some reason I can't get it to work. I've verified that I am getting data from the Hours column.
I'll also state the obligatory "I'm new to spfx and react". :) TIA for any help!
private readItem(): void {
this.props.spHttpClient.get(`${this.props.siteUrl}/_api/web/lists/getbytitle('Time Off')/items?$select=Title,Id,Hours`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
}).then((response: SPHttpClientResponse): Promise<ITimeOffItem[]> => {
return response.json();
})
.then((item: ITimeOffItem[]): void => {
console.log(item); //the data is here including Hours
this.setState({
items: item,
hoursTotal: //????How do I get the sum of "Hours" and assign it to a number in state
});
});
}
Create a function to loop through the items and add the hours
function countHours(items) {
if (!items) {
return 0;
}
let total = 0;
for (let i = 0; i < items.length; i++) {
total += items[i].Hours;
}
return total;
}
const item = [
{ Id: 25, Title: "Comp Time", Hours: 6, ID: 25 },
{ Id: 26, Title: "Comp Time", Hours: 5, ID: 26 },
{ Id: 27, Title: "Work from Home", Hours: 3, ID: 27 },
{ Id: 28, Title: "Comp Time", Hours: 7, ID: 28 },
{ Id: 29, Title: "Work from Home", Hours: 8, ID: 29 },
{ Id: 30, Title: "Holiday", Hours: 8, ID: 30 },
{ Id: 31, Title: "Work from Home", Hours: 32, ID: 31 }
];
console.log(countHours(item));
Use it like
this.setState({
items: item,
hoursTotal: countHours(item)
});
you can also use reduce
const item = [
{ Id: 25, Title: "Comp Time", Hours: 6, ID: 25 },
{ Id: 26, Title: "Comp Time", Hours: 5, ID: 26 },
{ Id: 27, Title: "Work from Home", Hours: 3, ID: 27 },
{ Id: 28, Title: "Comp Time", Hours: 7, ID: 28 },
{ Id: 29, Title: "Work from Home", Hours: 8, ID: 29 },
{ Id: 30, Title: "Holiday", Hours: 8, ID: 30 },
{ Id: 31, Title: "Work from Home", Hours: 32, ID: 31 }
];
const sum = item.reduce(function(a, b) { return a + b.Hours; }, 0);
console.log(sum)
It's hard to answer this without knowing what the data structure looks like, but if you are trying to sum an array of numbers you could use reduce.
const hours = [7, 5, 3, 1, 7]
const totalHours = hours.reduce((accumulator, hour) => accumulator + hour)

How to filter all the fields in react?

How to filter all the fields in react?
I have written a code which only filters specified fields.
let filteredContacts=this.props.contacts.filter(
(contact)=>{
return contact.name.indexOf(this.state.search)!==-1;
}
);
the above code only returns filtered names...but i want to filter name,age,city work.
this is the data file:
export default function(){
return [{
key: 1,
name: 'Steve',
city: 'Paris',
}, {
key: 2,
name: 'Tim',
city: 'London',
}, {
key: 3,
name: 'Stella',
city: 'Bankok',
}, {
key: 4,
name: 'John',
city: 'Paris',
}];
}
i want to create a search bar which which filters all the fields suppose if i search john then the list of john should be displayed and if i search paris then all the entries which have paris should be displayed..So the code which i have written only searches for name as i have specified name..i want to search the inputed data to search all the fields.
The filter criteria can be the indexOf on Object.values() like below but it will only give a complete match
var data = [{
key: 1,
name: 'Steve',
city: 'Paris',
}, {
key: 2,
name: 'Tim',
city: 'London',
}, {
key: 3,
name: 'Stella',
city: 'Bankok',
}, {
key: 4,
name: 'John',
city: 'Paris',
}];
var value = 'Paris'
var newData = data.filter((obj) => {
return Object.values(obj).indexOf(value) > -1
})
console.log(newData)
Well, I fastly tried, do a loop on your keys. Maybe there's a more elegant way.
let filteredContacts=this.props.contacts.filter(
(contact)=>{
var found = false;
Object.keys(contact).map(function(key, index) {
if (contact[key].indexOf(this.state.search) >= 0)
found = true;
}
return found;
}
);

Angular show list in alphabetical order and also show divider

**please anyone can help me i want to print list in Angularjs like this **
enter image description here
Use Order by
$scope.friends = [
{name: 'John', phone: '555-1212', age: 10},
{name: 'Mary', phone: '555-9876', age: 19},
{name: 'Mike', phone: '555-4321', age: 21},
{name: 'Adam', phone: '555-5678', age: 35},
{name: 'Julie', phone: '555-8765', age: 29}
];
<tr ng-repeat="friend in friends | orderBy:'name'">
read more here
You have to filter each group by the letters you want. Here's a Plunker Using this list:
$scope.myList = [{
id: 11,
name: 'Okra'
}, {
id: 12,
name: 'Musa'
}, {
id: 4,
name: 'Sky'
}, {
id: 13,
name: 'India'
}, {
id: 14,
name: 'Rose'
}, {
id: 15,
name: 'Titanic'
}, {
id: 16,
name: 'Onion'
}, {
id: 6,
name: 'Germany'
}, {
id: 17,
name: 'Beer'
}, {
id: 18,
name: 'Run'
}, {
id: 2,
name: 'Garden'
}, {
id: 19,
name: 'Mountain'
}]
One function to get the alphabets between the two:
function genCharArray(charA, charZ) {
var a = [], i = charA.charCodeAt(0), j = charZ.charCodeAt(0);
for (; i <= j; ++i) {
a.push(String.fromCharCode(i));
}
return a;
};
Then your filter:
app.filter("cfilter", function () {
return function (input, x, y) {
var groups = [];
var letters = genCharArray(x, y);
for (var i = 0; i < input.length; i++) {
for (var x = 0; x < letters.length; x++) {
if (input[i].name.substring(0, 1) == letters[x])
groups.push(input[i]);
}
} return groups;
}
});
And your HTML:
<div ng-repeat="w in myList | cfilter: 'A':'H' | orderBy: 'name'">
<div>{{w.name}}</div>
</div>
create one directive pass an array of letter and range of alphabates you want to disaply.
<dummy-directive data="arrayData" range="A-G"></dummy-directive>
<dummy-directive data="arrayData" range="H-L></dummy-directive>
<dummy-directive data="arrayData" range="M-P"></dummy-directive>
<dummy-directive data="arrayData" range="Q-Z"></dummy-directive>
Now question is that how to implement directive?
we will display sorted data.

calculating a count (number of distinct key's in an object) in angular

I have the following Angular code, see below.
What I'd like to achieve is - for each user - find out the "count" for each activity type.
What I'd like to achieve is:
John Thompson = 2 Deal
Bill Gates = 3 Deal
Billy Wellington = 2 Deal, 1 Meeting
The activity id's are the same in the activities object, and the $scope.activities.
Bit stuck here, any idea on how to either a) Write a function to get the COUNT or b) Do something clever in the HTML element with a ng-repeat and group or something.
$scope.competitionDetails = {
end_date: "2014-03-01",
users: [{
id: 2,
name: "John Thompson",
activities: [{ //This is all their activities
id: 6431,
time: (57).minutes().ago(),
points: 20
}, {
id: 6431,
time: new Date(),
points: 20
}]
}, {
id: 3,
name: "Bill Gates",
activities: [{ //This is all their activities
id: 6431,
time: new Date(),
points: 20
}, {
id: 6431,
time: new Date(),
points: 20
}, {
id: 6431,
time: new Date(),
points: 20
}]
}, {
id: 1,
name: "Billy Wellington",
activities: [{ //This is all their activities
id: 6431,
time: new Date(),
points: 20
}, {
id: 6431,
time: new Date(),
points: 20
}, {
id: 6432,
time: new Date(),
points: 100
}]
}]
};
$scope.activities = [{
id: 6431,
name: "Deal",
points: 20
}, {
id: 6432,
name: "Meeting",
points: 100
}];
I have created a fiddle for you with a working example: http://jsfiddle.net/ADukg/4757/
Just using some regular js, with a tiny bit of angular:
// create a lookup
var lookup = {};
angular.forEach($scope.activities, function(activity){
lookup[activity.id] = activity;
});
// calculate the results
angular.forEach($scope.competitionDetails.users, function(user){
user.results = {};
angular.forEach(user.activities, function(activity){
var name = lookup[activity.id].name;
if(!user.results[name]){
user.results[name] = 1;
}else{
user.results[name] += 1;
}
});
});

Resources