Angularjs code refactoring - angularjs

I have my angularjs project, in this I have this code block, which is fired depending upon the dropdown selection. In this code the if and else part is mostly similar, I want to refactor the code so that the code is not repeated.
if (1 === $scope.form.type) {
response = $scope.resource.searchItemSalesInfo(params.get, params.post,function(response, headers) {
angular.forEach(response, function(row, id) {
response[id].prod_info = row.alias + ' (' + row.final_product_id + ') ';
});
$scope.totalCount = headers('x-total-count');
});
} else {
response = $scope.resource.searchOrderSalesInfo(params.get, params.post,function(response, headers) {
angular.forEach(response, function(row, id) {
response[id].prod_info = row.alias + ' (' + row.final_product_id + ') ';
});
$scope.totalCount = headers('x-total-count');
});
}
I tried to take the common functionality out in the below manner, but then the code does not works, and it breaks the functionality.
$scope.callresource = function(resourcename){
response = $scope.resource.resourcename(params.get, params.post,function(response, headers) {
angular.forEach(response, function(row, id) {
response[id].prod_info = row.alias + ' (' + row.final_product_id + ') ';
});
$scope.totalCount = headers('x-total-count');
});
}
if (1 === $scope.form.type) {
$scope.callresource(searchItemSalesInfo);
} else {
$scope.callresource(searchOrderSalesInfo);
}

Alternatively to my other reply, you could pass a reference to the function that you want to be executed in $scope.callresource ... in other words a callback function
I believe this is the more scalable approach.
$scope.callresource = function(resourceCallbackFunction){
response = resourceCallbackFunction(params.get, params.post,function(response, headers) {
angular.forEach(response, function(row, id) {
response[id].prod_info = row.alias + ' (' + row.final_product_id + ') ';
});
$scope.totalCount = headers('x-total-count');
});
}
if (1 === $scope.form.type) {
$scope.callresource($scope.resource.searchItemSalesInfo);
} else {
$scope.callresource($scope.resource.searchOrderSalesInfo);
}

You can't call the function using this syntax $scope.resource.resourcename because this syntax is telling JS to execute a function called resourcename.
Instead, try using the bracket notation:
$scope.resource[resourcename](..)
Also, when invoking the $scope.callresource function, pass the arguments as strings, because searchItemSalesInfo and searchOrderSalesInfo currently JS is trying to find them as variables.
$scope.callresource('searchItemSalesInfo');
Your code would look like this:
$scope.callresource = function(resourcename){
response = $scope.resource[resourcename](params.get, params.post,function(response, headers) {
angular.forEach(response, function(row, id) {
response[id].prod_info = row.alias + ' (' + row.final_product_id + ') ';
});
$scope.totalCount = headers('x-total-count');
});
}
if (1 === $scope.form.type) {
$scope.callresource('searchItemSalesInfo');
} else {
$scope.callresource('searchOrderSalesInfo');
}

Related

Repetitive data when loading a select

I'm calling EventListener so that when something is typed into the username field, it will list that user's companies for me.
var ent = document.getElementById("username");
//var str = "";
ent.addEventListener('change', async () => {
localStorage.clear();
self.empUsuario = new Array();
self.rucEmp = new Array();
var newUser = document.getElementById("username");
$('#empresa').empty();
await fetch(environment.apiPoint + '/empresas?usuario=' + newUser.value, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(datos => {
datos.forEach(e => {
self.todasEmpresasUsuario.push({
ruc: e.ruc,
nombEmp: e.nombreCorto
});
});
})
await self.todasEmpresasUsuario().forEach(
function (element) {
self.empUsuario.push(element.nombEmp);
self.rucEmp.push(element.ruc);
}
);
Then I give it a conditional if the user is different from null, that it shows me with the rucEmp, and if not an empty space.
var str = "";
var item = "";
if (newUser.value != '') {
self.cont = 0;
let vacio = '';
for (item of self.empUsuario) {
vacio = "<option value=''>" + ' ' + "</option>"
str += "<option value='" + self.rucEmp[self.cont] + "'>" + item + "</option>"
self.cont++;
}
if (newUser.value == '') {
//str += "";
str += "<option value='" + self.rucEmp[self.cont] + "'>" + item + "</option>"
$('#empresa').empty().append(str);
}
$('#empresa').empty().append(vacio + str);
}
I expected the company lists to appear for each user and not accumulate, but the lists accumulate in the select.
enter image description here

How to map and send emails to specific users who don't meet a certain criteria in Javascript/GAS

I am new in Javascript and bit by bit I have used resources here on StackOverflow to build on a project that uses external API to get time entries for users from the 10k ft project management system. I have finally have different functions together as follows:
Calls for user details which includes user_id
Get the time entries and sums up for every user who's approval has a value (pending or approval) in a specific date range. Those without approval will be ignored in the summation and their total entries left at 0.
My challenge now is to have only those with 0 as total hours of time entries receive emails to update their time entries. This code doesn't seem to select only those with 0 and send emails specifically to them. I will appreciate any pointers and/or assistance. after sending the email, this should be recorded on Google sheet
var TKF_URL = 'https://api.10000ft.com/api/v1/';
var TKF_AUTH = 'auth'
var TKF_PGSZ = 2500
var from = '2020-01-20'
var to = '2020-01-26'
var options = {
method: 'get',
headers: {
Authorization: 'Bearer ' + TKF_AUTH
}
};
function getUsers() {
var userarray = [];
var lastpage = false;
var page = 1;
do {
// gets 10kft data
var users = read10k_users(page);
// writes data from current page to array
for (var i in users.data) {
var rec = {};
// pushing of mandatory data
rec.id = users.data[i].id;
rec.display_name = users.data[i].display_name;
rec.email = users.data[i].email;
userarray.push(rec);
}
// checks if this is the last page (indicated by paging next page link beeing null
if (users.paging.next != null) {
lastpage = false;
var page = page + 1;
} else {
lastpage = true;
}
}
while (lastpage == false);
return (userarray);
return (userarray);
}
function read10k_users(page) {
var endpoint = 'users?';
var url = TKF_URL + endpoint + 'per_page=' + TKF_PGSZ + '&auth=' + TKF_AUTH + '&page=' + page;
var response = UrlFetchApp.fetch(url, options);
var json = JSON.parse(response);
//Logger.log(json.data)
return (json);
}
function showTimeData() {
var users = getUsers()
var time_array = [];
for (var i = 0; i < users.length; i++) {
// Logger.log(users[i].id)
var url = 'https://api.10000ft.com/api/v1/users/' + users[i].id + '/time_entries?fields=approvals' + '&from=' + from + '&to=' + to + '&auth=' + TKF_AUTH + '&per_page=' + TKF_PGSZ;
var response = UrlFetchApp.fetch(url, options);
var info = JSON.parse(response.getContentText());
var content = info.data;
var total_hours = 0;
for (var j = 0; j < content.length; j++) {
if (content[j].approvals.data.length > 0) {
total_hours += content[j].hours;
}
}
Logger.log('User name: ' + users[i].display_name + ' ' + 'User id: ' + users[i].id + ' ' + 'total hours: ' + total_hours+ ' ' + 'Email: ' + users[i].email)
}
}
function sendMail(showTimeData){
var emailAddress = user.email;
var message = 'Dear ' + user.display_name + 'Please update your details in the system'
var subject = ' Reminder';
MailApp.sendEmail(emailAddress, subject, message);
}
I was able to get a solution for this as follows:
for (var j = 0; j < content.length; j++) {
if (content[j].approvals.data.length > 0) {
total_hours += content[j].hours;
}
}
Logger.log('User name: ' + users[i].display_name + ' ' + 'User id: ' + users[i].id + ' ' + 'total hours: ' + total_hours + ' ' + 'Email: ' + users[i].email)
if (total_hours == 0) {
sendMail(users[i])
}
}
}
function sendMail(user) {
var emailAddress = user.email;
var message = 'Dear ' + user.display_name + 'Please update your details in the system'
var subject = ' Reminder';
MailApp.sendEmail(emailAddress, subject, message);
}

code passes through $scope.options first instead of $http.get

i have an ion-slide component with 3 slides. when running the app the first time, all three slides load. however, going to another controller and coming back to the controller where the ion-slide is (using $state.go), only displays one slide and has the following error:
TypeError: Cannot read property '0' of undefined
seeing this error, i traced it passes through this line first:
sharedProperties.setProperty($scope.cardNumbers[$scope.currentIdx]
.CardNumber);
instead of this code fetching the card number:
var url = 'http://10.10.9.169/UserService3/WebService1.asmx';
$http.get(url + '/getCardsbyUsername' + '?unameID=' + currentID ).success(function(response) {
// stuff
console.log('response is jsonobj = ' + response);
var strObj = JSON.stringify(response).replace(/"(\w+)"\s*:/g, '$1:');
var myObject = eval('(' + strObj + ')');
$scope.cardNumbers = myObject;
console.log('response is jsonarr = ' + $scope.cardNumbers);
})
.error(function(response) {
// error stuff
console.log('response error is = ' + response);
});
here's the full code:
$scope.currentIdx = 0;
var currentID = sharedProperties3.getUserID();
console.log('current ID = ' + currentID);
var url = 'http://10.10.9.169/UserService3/WebService1.asmx';
$http.get(url + '/getCardsbyUsername' + '?unameID=' + currentID ).success(function(response) {
// stuff
console.log('response is jsonobj = ' + response);
var strObj = JSON.stringify(response).replace(/"(\w+)"\s*:/g, '$1:');
var myObject = eval('(' + strObj + ')');
$scope.cardNumbers = myObject;
console.log('response is jsonarr = ' + $scope.cardNumbers);
})
.error(function(response) {
// error stuff
console.log('response error is = ' + response);
});
$scope.options1 = {
initialSlide: 0,
onInit: function(slider1)
{
$scope.slider1 = slider1;
sharedProperties.setProperty($scope.cardNumbers[$scope.currentIdx].CardNumber);
},
onSlideChangeEnd: function(slider1)
{
console.log('The active index is ' + slider1.activeIndex);
$scope.currentIdx = slider1.activeIndex;
console.log('The active card is ' + $scope.cardNumbers[$scope.currentIdx].CardNumber);
sharedProperties.setProperty($scope.cardNumbers[$scope.currentIdx].CardNumber);
}
};
$scope.options2 = {
direction: 'vertical',
slidesPerView: '1',
pagination: false,
initialSlide: 1,
showNavButtons: false
};
how can i make it pass through the $http.get code block first?
i noticed i was loading angularjs more than once, so i got rid of the extra code calling angularjs in my index.html and it worked.

Angular unit testing with ngMock - $timeout.flush() throws exception

I am using ngMock for unit testing and I need to use the $timeout.flush function in one of my tests, so I have added the two following lines to my test:
$timeout.flush();
$timeout.verifyNoPendingTasks();
as indicated on http://www.bradoncode.com/blog/2015/06/11/unit-testing-code-that-uses-timeout-angularjs/.
$timeout.flush() does flush the timeout as expected, however I am now getting an exception from angular-mocks.js every time I run my test:
LOG: 'Exception: ', Error{line: 1441, sourceURL: 'http://localhost:9876/base/node_modules/angular-mocks/angular-mocks.js?05a191adf8b7e3cfae1806d65efdbdb00a1742dd', stack: '$httpBackend#http://localhost:9876/base/node_modules/angular-mocks/angular-mocks.js?05a191adf8b7e3cfae1806d65efdbdb00a1742dd:1441:90
....
global code#http://localhost:9876/context.html:336:28'}, 'Cause: ', undefined
Does anyone know where this exception could come from? I get it as many times as I use the $timeout.flush() function.
Looking at the angular-mocks.js file, it looks like it comes from the $httpBackend function. I have tried to update the ngMock version but it does not change anything. I have tried version 1.4.7 (which is my angular version) and version 1.6.2.
function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
var xhr = new MockXhr(),
expectation = expectations[0],
wasExpected = false;
xhr.$$events = eventHandlers;
xhr.upload.$$events = uploadEventHandlers;
function prettyPrint(data) {
return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
? data
: angular.toJson(data);
}
function wrapResponse(wrapped) {
if (!$browser && timeout) {
if (timeout.then) {
timeout.then(handleTimeout);
} else {
$timeout(handleTimeout, timeout);
}
}
return handleResponse;
function handleResponse() {
var response = wrapped.response(method, url, data, headers, wrapped.params(url));
xhr.$$respHeaders = response[2];
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
copy(response[3] || ''));
}
function handleTimeout() {
for (var i = 0, ii = responses.length; i < ii; i++) {
if (responses[i] === handleResponse) {
responses.splice(i, 1);
callback(-1, undefined, '');
break;
}
}
}
}
if (expectation && expectation.match(method, url)) {
if (!expectation.matchData(data)) {
throw new Error('Expected ' + expectation + ' with different data\n' +
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
}
if (!expectation.matchHeaders(headers)) {
throw new Error('Expected ' + expectation + ' with different headers\n' +
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
prettyPrint(headers));
}
expectations.shift();
if (expectation.response) {
responses.push(wrapResponse(expectation));
return;
}
wasExpected = true;
}
var i = -1, definition;
while ((definition = definitions[++i])) {
if (definition.match(method, url, data, headers || {})) {
if (definition.response) {
// if $browser specified, we do auto flush all requests
($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
} else if (definition.passThrough) {
originalHttpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers);
} else throw new Error('No response defined !');
return;
}
}
throw wasExpected ?
new Error('No response defined !') :
new Error('Unexpected request: ' + method + ' ' + url + '\n' +
(expectation ? 'Expected ' + expectation : 'No more request expected'));
}

Angular: Combine array objects and combine values

I'm retrieving data with http.get.
This provides me with an array of objects like below:
[{
"id”:12345,
"resource_state":2,
"external_id”:”abscdgrft”,
"upload_id”:1234567,
"athlete":{
"id”:123456,
"resource_state":2,
"firstname”:”testname”,
"lastname”:”testlastname”,
"profile_medium”:”image/athlete/medium.png",
"profile":"image/athlete/large.png",
"city”:”testcity”,
"state”:”teststate”,
…
},
"name”:”test name“,
"distance":87223.1,
"moving_time":11026,
"elapsed_time":11173,
"total_elevation_gain":682.3,
…
}]
I would like to combine all those object based on the athlete.firstname + athlete.lastname.
So for example all objects with athlete first name Jim and last name Donalds I want to be combined in one object, the same goes for all the other names.
When combining the objects based on the full name, values like "distance", "moving_time", "elapsed_time" and "total_elevation_gain" needs to be summed.
I tried using the code below but the problem is that I can't get it to work with multiple values like I mention above.
This is working only with one value, distance for example:
var obj = {}; // Initialize the object
angular.forEach(data, function(value, key) {
if (value.start_date > firstdayOfWeek && value.start_date < lastdayOfWeek) {
if (obj[value.athlete.firstname + ' ' + value.athlete.lastname]) { // If already exists
obj[value.athlete.firstname + ' ' + value.athlete.lastname] += value.distance; // Add value to previous value
} else {
obj[value.athlete.firstname + ' ' + value.athlete.lastname] = value.distance; // Add in object
}
} else {
//do nothing
}
});
console.log(obj); // Result
When I modify it like this it is not working anymore.
var obj = {};
angular.forEach(data, function(value, key) {
//console.log(value);
if (value.start_date > startOfLastWeek && value.start_date < endOfLastWeek) {
//console.log(value);
if (obj[value.athlete.firstname + ' ' + value.athlete.lastname]) { // If already exists
obj[value.athlete.firstname + ' ' + value.athlete.lastname] += {
"profile" : value.athlete.profile,
"distance" : value.distance,
"moving_time" : value.moving_time,
"elapsed_time" : value.elapsed_time,
"total_elevation_gain" : value.total_elevation_gain,
}; // Add value to previous value
} else {
obj[value.athlete.firstname + ' ' + value.athlete.lastname] = {
"profile" : value.athlete.profile,
"distance" : value.distance,
"moving_time" : value.moving_time,
"elapsed_time" : value.elapsed_time,
"total_elevation_gain" : value.total_elevation_gain,
}; // Add in object
}
} else {
//do nothing
}
});
console.log(obj); // Result
Thanks!
try to add item by item... You can't add all with += { ... }:
var obj = {};
angular.forEach(data, function(value, key) {
//console.log(value);
if (value.start_date > startOfLastWeek && value.start_date < endOfLastWeek) {
//console.log(value);
if (obj[value.athlete.firstname + ' ' + value.athlete.lastname]) { // If already exists
var aux = obj[value.athlete.firstname + ' ' + value.athlete.lastname];
aux.profile += value.athlete.profile;
aux.distance += value.distance;
...
} else {
obj[value.athlete.firstname + ' ' + value.athlete.lastname] = {
"profile" : value.athlete.profile,
"distance" : value.distance,
"moving_time" : value.moving_time,
"elapsed_time" : value.elapsed_time,
"total_elevation_gain" : value.total_elevation_gain,
}; // Add in object
}
} else {
//do nothing
}
});
console.log(obj); // Result
Use underscore or lodash groupBy, map and reduce
with lodash:
_.chain(myArr).map(function(o) {
return {
fullname: o.athlete.firstname + ' ' + o.athlete.lastname,
distance: o.distance,
moving_time: o.moving_time,
elapsed_time: o.elapsed_time,
total_elevation_gain: o.total_elevation_gain
}
}).groupBy(function(o) {
return o.fullaname
}).map(function(d, fullname) {
var totals = _.reduce(d, function(result, run, n) {
result.moving_time += run.moving_time | 0
result.elapsed_time += run.elapsed_time | 0
result.total_elevation_gain += run.total_elevation_gain | 0
return result
}, {
moving_time: 0,
elapsed_time: 0,
total_elevation_gain: 0
})
totals.fullname = fullname
return totals
})

Resources