Angular performance issues, ng-repeat, unwanted callbacks - javascript

I'm facing some serious performance issues in my angular app, surely due to my bad ng-repeat implementation but I don't know how to do better. I've tried some other combinations but none give me the result I want, nor better performance. There have been some infinite loops, undefined variables due to asynch and $digest aborting.
This is how it should be looking (so that's the working result, but not optimized for now) : http://scr.hu/0ei9/8bpw9
Days with blue cells = user is present, red cell = absent. Beneath are the "shifts" per day (each shift can be done on various days).
When I console.log some of the functions, they are called way too many times than needed, for example isPresent (for checking if the user submited the day as available) is called 5x180 (180 being probably 5 users x 30 days of month) and getDayOfWeek (used in template for the shifts row) 28+840+812...there are 10 shifts. Whereas I would normally need to call isPresent only 1x180 for all cells and getDayOfWeek 1x30 days of month for one shifts row. That said, I don't really get why its called sooo many times and how to optimize it.
In addition, when I click on a blue cell, the setShift() function is called. I copied the function here but don't analyze it, I only wanted to show that it nowhere calls any of the previous functions, however I console.log an impressive 28x "days of the week" + 180 "is present" and + 812 "day of the week". No Idea where it comes from... to be frank, everything i click calls this same amout - if I change the month, year, click on an independent button...
I omitted some classes and css for better code reading.
Thanks for your help.
Edit
after commenting and decommenting some of the code I see that the most of those unwanted logs when I call the setShift() function come from the last sub-call : showPopover() where I open a $modal. When commented, there is like 1/3 of what I'm used to see. Before the modal appears there is the rest of this stuff. Furthermore I think that the temlpateUrl might be the cause because when commented it does not log all those houndreds of 'is present' and 'day of week'. And when I click anywhere on the modal, it recalls all those functions. Any ideas?
JS angular functions
$scope.isPresent = function(day, month, year, userId) {
console.log('is present')
var date = new Date(year, month - 1, day + 1)
var day = moment(date).format("D-M-YYYY");
for (var i = 0; i < $scope.presences.length; i++) {
var presentDay = moment($scope.presences[i].start).format("D-M-YYYY")
if (presentDay == day && userId == $scope.presences[i].coursierId) {
return true
}
}
}
$scope.getDayOfWeek = function(day, month, year) {
console.log('day of the week')
var date = new Date(parseInt(year), month - 1, day + 1)
var dayId = date.getDay();
return dayId;
}
/*
used for a limited ng-repeat
*/
$scope.getTimes = function(n) {
return new Array(n);
};
/*
Shows a list of sorted out shifts with corresponding
hours, cities and capabilities of coursier.
*/
$scope.setShift = function(day, month, year, userId, event) {
var date = new Date(year, month - 1, day)
var day = moment(date).format("D-M-YYYY");
var dayOfWeek = moment(date).day()
//SORT SHIFTs BY DAY OF WEEK clicked
var day_shifts = $scope.sortShiftByDayOfWeek(dayOfWeek)
//console.log(day_shifts)
//check if the day clicked is an dispo present day
for (var i = 0; i < $scope.presences.length; i++) {
var dispoDay = moment($scope.presences[i].start).format("D-M-YYYY")
//if yes, check the presence user id and the cell of user clicked
if (dispoDay == day) {
//then get all the shifts that fit into this coursier's time range
if ($scope.presences[i].coursierId == userId) {
var dispo = $scope.presences[i];
var dispoHours = $scope.getDispoHoursAndDay(dispo);
var time_shifts = $scope.compareDiposHoursAndShift(dispoHours, day_shifts);
//then sort the shifts by the dispo's and shift's cities
var time_city_shifts = $scope.compareDispoCityAndShift(time_shifts, dispo);
var time_city_able_shifts = $scope.compareUserAndShift(time_city_shifts, userId);
$scope.showPopover(time_city_able_shifts, event);
}
};
};
}
###Calendar table
<table class="table table-bordered">
<!--days of month-->
<tr class="mainHeader">
<th>coursier/jour</th>
##calendar.days = 30 days of month, for example
<th class="monthDay" ng-repeat=" numDay in [] | range: calendar.days">{{$index+1}} {{calendar.daysNames[$index]}}
</th>
</tr>
<!-- user name and days -->
<tr ng-repeat="user in coursiers">
<!-- <td class="coursierName">nom coursier</td> -->
<td>
{{user.name}}
</td>
<td ng-click="setShift($index+1, monthNum,year, user._id, $event)" ng-repeat="numDay in getTimes(calendar.days) track by $index" ng-class=" isPresent($index, monthNum,year, user._id) == true ?
'present' : isAbsent($index, monthNum,year, user._id) == true ?
'absent' : '' ">
</td>
</tr>
<tr>
<td>Shifts par jour</td>
<td class="shiftsParJourCell" ng-repeat="day in getTimes(calendar.days) track by $index">
<span ng-repeat="shift in shifts">
<span ng-repeat="jour in shift.jours">
{{jour.id ==
getDayOfWeek($parent.$parent.$index, monthNum, year) ? shift.nom : ''}}
</span>
</span>
</td>
</tr>
</table>

After a while, in my case the problem was that I wasn't using directives.
The scopes were having unwanted interactions (still don't know why) but after separing my html in angular directives there are no issues so far.

Related

Change the date labels as Day with numbers in full calendar

I am working with FullCalendar V4 along with Ionic -4 and Angular-8 . In week view it shows me 7 days. I want every day to be displayed as Day with number. For example instead of Monday it should be displaying Day 1.
Also
I am planning to display only three weeks so there should be Day
label starting with Day 1, Day 2 , Day 3 and all the way to display
Day 21
Is there a inbuilt method to do this. Or any other approach to do so. Thanks in advance :)
Current Implementation
columnHeaderText(info){
if(info){
return 'Day ' + this.count++
}
}
<ion-content>
<full-calendar #calendar
[header]="header"
[defaultView]="defaultView"
[plugins]="calendarPlugins"
[editable]="editable"
[events]="events"
[eventStartEditable]="eventStartEditable"
[eventDurationEditable]="eventDurationEditable"
[dragRevertDuration]="dragRevertDuration"
[droppable]="droppable"
(columnHeaderText)=" columnHeaderText($event)"
(eventRender)="eventRender($event)"
></full-calendar>
Maybe you can try something like this? and reset 'count' everytime you change to a new 3 week period
var count = 1;
var calendar = new Calendar(calendarEl, {
//your settings...
columnHeaderText: (date) => {
return 'Day ' + count++},
}
}
EDIT
calendarOptions: any;
dayCount: number = 1;
ngOnInit() {
this.calendarOptions = {
columnHeaderText: () => {
return 'Day ' + this.dayCount++
}
}
and change in your html to:
[columnHeaderText]="calendarOptions.columnHeaderText"
}

JavaScript Validation for Balance Amount

I have MySQL Table that consist of initial_amount, used_amount & balance as follows.
fin_code initial_amount used_amount balance
1 500,000.00 275,000.00 225,000.00
2 212,000.00 125,000.00 87,000.00
3 455,000.00 455,000.00 -
02) If I enter to issue 300,000.00 as used_amount through the Bootstrap view under fin_code 1, there need to control over issues vs balance. That is 225,000.00.
03) I used the following JavaScript code to perform this task
$(document).on('keyup', '#used_amount', function () {
var bal = parseFloat($('#balance').val());
var amount = parseFloat($('#used_amount').val());
if (bal < amount) {
$('#save').prop('disabled', true);
$('#used_amount_div').addClass('danger');
alert("Can not proceed your request ..!!. Issue amount is higher than the available balance..");
} else {
$('#save').prop('disabled', false);
}
04) But it is properly working for the minus values / balances only. I can not understand what I am going wrong. Can any one help me on this task ?

Angular ng-show multiple conditions (no more than 3 work)

I have a div which I need to show when any of 5 conditions are true.
The problem is that ng-show seems to take into consideration only the first 3 conditions. I don't know if it's only my problem, cause I couldn't find any related problem.
In the following example I kept moving conditions around, but each time only the first 3 conditions are taken into consideration. Whatever condition falls into the 4th position, does not show the div.
Please let me know if you know a work around in case it's not possible to have more than 3 conditions.
It's a pretty big div, so I post only a part:
<div class="row " ng-show="selectedAllP[0] || selectedAllF[0] || selectedAllP || selectedAllD || level">
<div class="row selectedCase">
<div><h3 id="choices">Your choices:</h3></div>
<div class="col-md-4" id="publisher">
<h4>Publishers</h4>
<div class="level" ng-hide="selectedAllP[0] || selectedAllP">Select publisher</div>
<table class="table table-bordered table-striped">
<tbody id="pub">
<tr ng-hide="selectedAllP.Name === ' - Any Publisher -'" ng-repeat="roll in selectedAllP" ng-click="deSelectP(roll)">
<td class="deselect">{{roll.Name}}</td>
</tr>
<tr ng-show="selectedAllP.Name === ' - Any Publisher -'" ng-click="deSelectP(selectedAllP)">
<td class="deselect">{{selectedAllP.Name}}</td>
</tr>
</tbody>
</table>
<p ng-show="noticeAnyPublisher && selectedAllP.Name === ' - Any Publisher -'" class="notice">{{noticeAnyPublisher}}</p>
</div>
And the logic for a part of the div above:
$scope.selectedAllP = [];
$scope.setSelectedP = function (publisher) {
$scope.selectedP = publisher.Name;
// Check if the selected publisher is already in the array
// if it isn't, than push it in the array (else do nothing)
if (publisher.Name == " - Any Publisher -"){
$scope.selectedAllP = publisher;
console.log($scope.selectedAllP);
} else if ($scope.selectedAllP.Name == " - Any Publisher -") {
$scope.noticeAnyPublisher = 'Deselect "Any Publisher" first';
console.log("blblblb");
} else if ($scope.selectedAllP.indexOf(publisher) == -1) {
$scope.selectedAllP.push(publisher);
}
console.log($scope.selectedP, $scope.selectedAllP);
};
$scope.deSelectP = function (dePublisher) {
// Check if the selected publisher is already in the array
// if it is, than remove it from the array (else do nothing)
if (dePublisher.Name == " - Any Publisher -") {
$scope.selectedAllP = [];
$scope.selectedP = 0;
$scope.noticeAnyPublisher = '';
} else {
var idx = $scope.selectedAllP.indexOf(dePublisher);
if (idx != -1) {
$scope.selectedAllP.splice(idx, 1);
$scope.selectedP = $scope.selectedAllP[0].Name;
}
}
};
I want when I choose the 4th condition (in this case || selectedAllD) to show the div above, but as u can see, even if the distributor is selected (and selectedAllD exists in console), the div doesn't show. Check next image to see the div showing when I select the 3rd condition (selectedAllF[0]).
div showing when I select the 3rd condition (selectedAllF[0]). It is showing for the fisrt 2 conditions too. Problem is that its behavior is the same, whatever the order of the conditions (it only considers the first 3 conditions).
You could call a method in your ng-show.
<div class="row " ng-show="showRow()">
and declare that function into your .js file.
$scope.showRow = function () {
return $scope.selectedAllP[0] || $scope.selectedAllF[0] || $scope.selectedAllP || $scope.selectedAllD || $scope.level;
}
No matter how many condition you will pass to ng-show or any ohter directive which accepts expressions. See this docs Angular Expressions. So instead, check all of the parts of you condition statement. In such representation it will be evaluated to true every time when there is AT LEAST 1 statement which returns true. Also it is worth to note that this expression will be evaluated from left to right and UNTIL first true statement will be found.

Javascript data needs to display HTML output as columns once the following year is evaluated

I have data from last 3 years that I need to display as YEARS for each column.
In C# /asp.net I am looping through and getting all the data and then in javascript I end up looping through the data and then just appending rows to a table.
The problem with this is that since the data goes from 2015 records to then onto 2014 and then 2013 that I will end up with 1 column and many rows
However I want to break it about and show it as
2015 2014 2013
a a a
b b b
Thus how can I do that with the data? I though about Pivoting the data, and I though about div tags , but nothing seems that clear to me
Mockup
Update
I see in another project that this was done in angular (not relevant to my issue) but the way in which it was done was to assume that there was ALWAYS data in each month folder for each year, however, this is not the case to which I have only 4 months to display for 2015
Example of the existing code:
<table class="table-light">
<tr>
<th ng-repeat="year in years"><h2>{{ year }}</h2></th>
</tr>
<tr ng-repeat="month in months">
<td ng-repeat="year in years" class="text-center">
<!-- directory path predicted based on history -->
<a target="_blank" class="link"
href="http://Logs\{{ year }} LOGS\{{ month.number }} - {{ year }}\&file=pdf">{{ month.title }}</a>
</td>
</tr>
</table>
Update 2
My data from chrome console looks like this
Then what I have showing on the web page ends up showing the 2015 months with data, but then It shows that I have files in the month January thus it is getting displayed
3 months from 2015 then 1 month of 2016 , so thus my c# code is correctly knowing to only return the month folders which have files, but I want to arrange them into 3 columns ( I want to display 3 years 2016, 2015, 2014)
I only want to show 1 distinct month if a month contains 1 to many files thus the logic in the javascript below
var strResult = "";
var month = "";
var final = "";
strResult = "<table class='table-light' id='myTableId'><thead><tr><th style='text-align:left;'><h2>2015</h2></th></tr></thead><tbody>";
var unique = {};
var distinct = [];
for (var i in files) {
if (typeof (unique[files[i].shortMonth]) === "undefined") {
distinct.push(files[i].shortMonth);
// do the work here
month = files[i].month;
if (month === "" || month === null) {
month = "";
}
strResult += "<tr><td><a target='blank' class='link ng-binding' href='files.html?id=sub&year=" + files[i].year + "&month=" + files[i].shortMonth + "' onclick=\"getFiles('" + files[i].year + "','" + files[i].shortMonth + "');\">" + month + "</a></td></tr>";
final += month + ",";
}
unique[files[i].shortMonth] = 0;
}
So hopefully that makes more sense as I know how to loop through javascript, but I want to end up displaying the html with the "look" of the screenshot under the word Mockup
However, with the caveat that that the reality is the data as it stands will really only show
2016 2015 2014
January August July
September August
October December

calculation to show image on website every 3rd week

I have a grails project where need to show on call team icon on home page. there are three images for three team. teams rotate every 3 week so for example team 1 logo will show first (1)and last week(4) of month and so one..
I have tried putting in db table for all 52 weeks and team no and putting it in session-
code in service-
sql.query("SELECT * FROM tbl_ImageForTeamUser where weekno=?",[wkno])
{ rs ->
while (rs.next()) {
def userinf = new UserInfo()
userinf.weekno= rs.getInt("weekno")
userinf.teamname= rs.getString("teamname")
userinf.teamno= rs.getInt("teamno")
items.add(userinf)
}
}
Saved in session-
session.weekno= items[0].teamno()
UI looks like-
<tr>
<g:if test="${session.weekno == "1" }">
<td class="team1" align="right" nowrap></br></br></td>
</g:if>
<g:if test="${session.weekno == "2"}">
<td class="team2" align="right" nowrap></br></br></td>
</g:if>
<g:if test="${session.weekno == "3" }">
<td class="team3" align="right" nowrap></br></br></td>
</g:if>
but somehow this is not looking a good solution. please suggest a better ,coding suggestion .dont want to use DB and handle it on UI side.
The cal.get(Calendar.WEEK_OF_MONTH) will give you 1 2 3 4 5 or the the week of the month it is.
You can use this to print the correct order without having to store it in a database table. because you only have 3 unique ordering of the pictures if I understand your question correctly.
Calendar cal = Calendar.getInstance()
def weekOfMonth = cal.get(Calendar.WEEK_OF_MONTH)
def teamImageCountShown = weekOfMonth % 3
if(teamImageCountShown==1){
//Display 1 2 3
}
if(teamImageCountShown==2){
//Display 2 3 1
}
if(teamImageCountShown==0){
//Display 3 1 2
}

Categories