Improve AngularJs ng-class Performance with lots of data - javascript

Im looking to improve the speed of ng-class or find and alternative way to do it, because it takes too long to load when it have to manage a lot of data.
Here is my code:
<div class="col-xs-12 col-sm-6 col-md-3 col-lg-2 block animate"
ng-repeat="build in buildsRunning.builds.build | limitTo:totalDisplayed track by build._id "
ng-hide="build.hide"
ng-class="{'running': build._running ,'block-green': build._status ==='SUCCESS','block-red': build._status==='FAILURE'}">
<div class="title-container animate" >
<p>{{::build._buildTypeId}}</p>
<p class="running-on">Running on: <span class="agent">{{::build.agent._name}}</span></p>
<p class="running-on">Version: <span class="agent">{{::build._number}}</span></p>
<p class="running-on" ng-if="::build.user._name">Run by: {{::build.user._name}}</p>
</div>
<div class="update-container animate col-xs-12">
<div class="progress progress-running">
<div class="progress-bar "
role="progressbar" aria-valuenow="{{build._percentageComplete}}" aria-valuemin="0"
aria-valuemax="100" style="width:{{build._percentageComplete}}%"
ng-class="{'progress-bar-success': build._percentageComplete > 5 ,'progress-bar-warning': build._percentageComplete <= 6}">
<span ng-if="build._percentageComplete > 5" class="sr-only"> {{build._percentageComplete}}% Completed
<p class="elapsed-time" ng-if="build._percentageComplete >= 50"> in : {{build.timeInfo}} Minutes</p>
</span>
</div>
</div>
</div>
</div>
Any ideas?
Sorry for my English, if you do not understand me or need more information, please let me know

As #pankajparkar pointed out, this will be caused by your rendering of, as you said,
a lot of data.
However, best practice is to call a controller function which returns the classes:
<div class="col-xs-12 col-sm-6 col-md-3 col-lg-2 block animate"
ng-repeat="build in buildsRunning.builds.build | limitTo:totalDisplayed track by build._id "
ng-hide="build.hide"
ng-class="getClasses(build)">
and in your controller:
$scope.getClasses = function(build) {
// return whatever you like based on build object
}

Related

How to get specific Div's/Card Details when user clicked that using javascript

I am creating various cards using fetch API, this cards are holding details like (Author, Title, Cover Image, etc.).
There is a lot of cards renders there once API call my struggle is how to get specific card data/details like ( author, title etc.) of clicked card. when user clicked any of the card from these set.
HTML
<div class="row" id="ShowReports">
<div class="col-lg-3 col-md-4 col-sm-6 mt-3" onclick="show(this)" id="card">
<div class="card p-1">
<img src="https://d3i5mgdwi2ze58.cloudfront.net/znuxxu2npw851eeboqayu3e35udn" alt="image"
class="bookimg" width="150" height="200">
<h6 class="mb-3 booktitle">${title1}</h6>
<p class="mb-0 bookpara" name="author">Author : ${author1}</p>
<p class="mb-3 bookpara" name="pages">Pages : ${pages1}</p>
Download1
</div>
</div>
<div class="col-lg-3 col-md-4 col-sm-6 mt-3" onclick="show(this)" id="card">
<div class="card p-1">
<img src="https://d3i5mgdwi2ze58.cloudfront.net/znuxxu2npw851eeboqayu3e35udn" alt="image"
class="bookimg" width="150" height="200">
<h6 class="mb-3 booktitle">${title2}</h6>
<p class="mb-0 bookpara" name="author">Author : ${author2}</p>
<p class="mb-3 bookpara" name="pages">Pages : ${pages2}</p>
Download2
</div>
</div>
</div>
javaScript
function show() {
var details = this.innerHTML
console.log(details)
}
Don't know what is the right approach or method to this...
UPDATED
We need to assign unique id to data elements. For example: id="${id}-author". Note that id is from your card id
<div class="col-lg-3 col-md-4 col-sm-6 mt-3" onclick="show(${id})" id="card">
<div class="card p-1">
<img src="https://d3i5mgdwi2ze58.cloudfront.net/znuxxu2npw851eeboqayu3e35udn" alt="image"
class="bookimg" width="150" height="200">
<h6 class="mb-3 booktitle" id="${id}-booktitle">${title1}</h6>
<p class="mb-0 bookpara" name="author" id="${id}-author">Author : ${author1}</p>
<p class="mb-3 bookpara" name="pages" id="${id}-pages">Pages : ${pages1}</p>
Download1
</div>
</div>
After that, we can implement show function like below
function show(id) {
const author = document.getElementById(id + "-author").innerHTML;
const booktitle = document.getElementById(id + "-booktitle").innerHTML;
const pages = document.getElementById(id + "-pages").innerHTML;
console.log({ author, booktitle, pages })
}
If you don't want to modify HTML, you also can try this way
onclick="show({ author: ${author}, booktitle: ${booktitle}, pages: ${pages} })"
And you need to have params corresponding to your data name
function show({ author, booktitle, pages }) {
console.log({ author, booktitle, pages })
}
OLD ANSWER
onclick="show(this)"
this in this context is referred to the global one, but from my understanding of your question, you're trying to get scoped context, so the change could be
onclick="show(event)"
To access the innerHTML from that click, you can try this way
function show(event) { //the param needs to be passed properly
var currentElement = event.target || event.srcElement;
var details = currentElement.innerHTML
console.log(details)
}
P/s: If you want to keep the global context on this, you also need to pass the param on show function.
# Nick Vu thanks for your comment your approach is quite logical and great well what i have did is, I have assigned a unique id to every card div while calling API and then target its childnode's innerHTMLS.
HTML
<div class="col-lg-3 col-md-4 col-sm-6 mt-3" id="card">
<div class="card p-1" id="second" onclick="show(id)">
<img src="https://d3i5mgdwi2ze58.cloudfront.net/znuxxu2npw851eeboqayu3e35udn" alt="image"
class="bookimg" width="150" height="200">
<h6 class="mb-3 booktitle">${title2}</h6>
<p class="mb-0 bookpara" name="author">Author : ${author2}</p>
<p class="mb-3 bookpara" name="pages">Pages : ${pages2}</p>
Download2
</div>
</div>
</div>
javascript
function show(e) {
console.log(e)
var details = document.getElementById(e)
console.log(details)
console.log(details.childNodes[1].src)
console.log(details.childNodes[3].innerHTML)
console.log(details.childNodes[5].innerHTML)
console.log(details.childNodes[7].innerHTML)
}
this is working around what i want as output.. thanks. Or may be at last i can do forEach loop of childnodes to make it more short.

Handlebars lookup to make an href

I am trying to make a mod on an existing app. All I want to do is create an href that contains a url, but using the handlebars lookup function. When I try it just returns a blank value.
Here is my function:
var cardLink = function generateCardLink() {
var url = `"url/container-scan-reports/${vendor}/${product}/${image}"`
return url;
}
//...
res.render('vendor', {
title: 'Vendor Images',
images: images,
tags: tags,
cardLink: cardLink
});
I am then trying to pass in href this way on the top div of template.
<div class="row row-cards-pf ">
{{#each images}}
<div href={{lookup ../cardLink #index }} class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
<div class="card-pf card-pf-view card-pf-view-select card-pf-view-single-select">
<div class="card-pf-body">
<div class="card-pf-top-element">
<span class="pficon-image card-pf-icon-circle"></span>
</div>
<h2 class="card-pf-title text-center">
{{ this }}
</h2>
<div class="card-pf-items text-center">
<div class="card-pf-item">
{{{ lookup ../tags #index}}}
</div>
</div>
<!-- <p class="card-pf-info text-center"><strong>Most recent image</strong> {{ lookup ../mostRecentImages #index}}</p> -->
</div>
<div class="card-pf-view-checkbox">
<input type="checkbox">
</div>
</div>
</div><!-- /col -->
{{/each}}
Can anyone help me?
You don't need lookup in this case. I think you want to display the url, so #index is not the right reference. Try it this way:
<div href={{../cardLink}} class="col-xs-12 col-sm-6 col-md-4 col-lg-4">

Stop Modal from closing when AngularJS gets update to model

I have a web application that polls a server for data updates (based on a queue of tests being run on the server). I have a bootstrap-modal containing a log if a test fails. When the application receives an update from the server, any open modal is closed but the page is left with the modal screen preventing interaction.
I have tried pausing updates when a modal is opened and resuming them when it is closed, but that doesn't seem to have fixed the problem. I have also tried moving the modals for logs to sit directly under in the DOM. It seems the data changing causes the page to redraw everything inside the controller.
excerpt from index.html
<div class="row" ng-controller="testStatusController as testStatus">
Header Row (static html)
<div class="row test-table-data {{script.colorClass}}" ng-repeat="script in testStatus.scripts">
<div class="col-md-2">
<p class="align-middle"><span class="d-inline d-md-none">Name: </span><span>{{script.tcName}}</span></p>
</div>
<div class="col-md-6 align-middle">
<p><span class="d-inline d-md-none">Description: </span>{{script.description}}</p>
</div>
<div class="col col-md-2 align-middle">
<p><span class="d-inline d-md-none">Run Status: </span>{{script.status}}</p>
</div>
<div class="col col-md-2">
<p>
<span class="icon text-align-middle dripicons-wrong text-danger big" ng-if="!script.pass && script.status=='Complete'" data-toggle="modal" data-target=".{{script.tcName.slice(0,-4)}}"></span>
<span class="d-inline icon dripicons-checkmark text-success big" ng-if="script.pass"></span>
<span class="spinner-border text-primary" ng-if="script.status=='Running'"></span>
<span class="d-inline icon dripicons-clock text-primary big" ng-if="script.status=='Not Run'"></span>
</p>
</div>
<div class="modal fade {{script.tcName.slice(0,-4)}} log" ng-if="!script.pass && script.status == 'Complete'">
<div class="modal-dialog modal-lg" ng-focus="testStatus.pauseUpdates(true)" ng-blur="testStatus.pauseUpdates(false)">
<div class="modal-content log-modal">
<div class="modal-header">
<div class="modal-title text-monospace">
<h4>{{script.tcName}}</h4>
<h6>{{script.description}}</h6>
</div>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
<p class="text-monospace"><span ng-repeat="log in testStatus.getLog(script.tcName).lines track by $index">{{log.line}}<br /></span></p>
</div>
</div>
</div>
</div>
</div>
<div class="row test-table-foot">
<div class="col-md-3">
<p>Passed: <span>{{testStatus.passed()}}</span></p>
</div>
<div class="col-md-3">
<p>Failed: <span>{{testStatus.failed()}}</span></p>
</div>
<div class="col-md-3">
<p>Remaining: <span>{{testStatus.remaining()}}</span></p>
</div>
<div class="col-md-3">
<p>Total: <span>{{testStatus.total()}}</span></p>
</div>
</div>
</div>
</div>
the update Function (in main.js called every 5 seconds) Comments indicate what code was removed to help keep things brief.
testList.updateResults = function () {
if (testList.running) {
$http({url:theUrl + "?cmd=json&testRun=default",
method: "GET"
}).then(function(response){
var strRes = response.data.result;
var tmp = angular.fromJson(strRes);
// update trName if bound input not focused
testList.scripts = tmp.tc;
testList.running = false;
angular.forEach(tmp.tc, function(script, index){
if(script.status != "Complete") {
testList.running = true;
script.colorClass = "text-primary";
}
else {
if(script.pass) {
script.colorClass = "text-success";
}
else {
script.colorClass = "text-danger";
if(!(script.tcName.slice(0, -4) in testList.logs)) {
testList.getLog(script.tcName);
}
}
}
});
// update start/stop button
}, function(data){
console.log(data);
});
}
};
I would expect that AngularJS would not update sections of the DOM if the data bound to them was the same, but instead everything in the controller section is redrawn. My next instinct was to separate the logs and the status into different controllers, but I suspect I will have the same problem when a new log gets appended to the list of logs.

Bootstrap different col-* with ng-repeat

I've got a movie reviews example application built in angular + bootstrap, I'm trying to build a "grid" of 3 images for medium and up screens, the problem is that when I want to have only 2 images per row for xs screens.
I'm using ng-repeat and populating the imgs inside the cols.
is there a nice way to do this? (I'm aware that the $index + N may be out of bounds, and that there is code duplication here. just want to find a good solution for rearranging the bootstrap grid for different screen sizes on dynamic data)
<div ng-repeat="movie in movies" ng-if="$index % 3 == 0" class="row slide-left">
<div class="col-md-4">
<img ng-src='http://image.tmdb.org/t/p/w185/{{movies[$index].poster_path}}' ng-click="chooseMovie(movies[$index])">
</div>
<div class="col-md-4">
<img ng-src="http://image.tmdb.org/t/p/w185/{{movies[$index + 1].poster_path}}" ng-click="chooseMovie(movies[$index + 1])">
</div>
<div class="col-md-4">
<img ng-src="http://image.tmdb.org/t/p/w185/{{movies[$index + 2].poster_path}}" ng-click="chooseMovie(movies[$index + 2])">
</div>
</div>
<div ng-repeat="movie in movies" >
<div class="col-md-4 col-xs-6">
<img ng-src='http://image.tmdb.org/t/p/w185/{{movie.poster_path}}' ng-click="chooseMovie(movie)">
</div>
</div>
This should do the trick.
I removed the row but i think even with it will works unless you use the clearfix class.
The grid will automatically go on the next line after "12" columns.
So a size of 4 for medium screen means 3 per line, 6 for xs screen ->2/line :)
You can detect bootstrap columns by using the following function:
function findBootstrapEnvironment() {
var envs = ["ExtraSmall", "Small", "Medium", "Large"];
var envValues = ["xs", "sm", "md", "lg"];
var $el = $('<div>');
$el.appendTo($('body'));
for (var i = envValues.length - 1; i >= 0; i--) {
var envVal = envValues[i];
$el.addClass('hidden-'+envVal);
if ($el.is(':hidden')) {
$el.remove();
return envs[i]
}
};
}
The setting a value to the scope based on the return
if(findBootstrapEnvironment()==="Medium"|(findBootstrapEnvironment()==="Large"|){
$scope.size="Medium"
}else{
$scope.size="Small"
}
And then with ng-if you can manage the div to be with 3 or 2 photos like this
Three photos if medium
<div ng-repeat="movie in movies" ng-if="size==medium" class="row slide-left">
<div class="col-md-4">
<img ng-src='http://image.tmdb.org/t/p/w185/{{movies[$index].poster_path}}' ng-click="chooseMovie(movies[$index])">
</div>
<div class="col-md-4">
<img ng-src="http://image.tmdb.org/t/p/w185/{{movies[$index + 1].poster_path}}" ng-click="chooseMovie(movies[$index + 1])">
</div>
<div class="col-md-4">
<img ng-src="http://image.tmdb.org/t/p/w185/{{movies[$index + 2].poster_path}}" ng-click="chooseMovie(movies[$index + 2])">
</div>
</div>
Two photos if small
<div ng-repeat="movie in movies" ng-if="size==small" class="row slide-left">
<div class="col-sm-4">
<img ng-src='http://image.tmdb.org/t/p/w185/{{movies[$index].poster_path}}' ng-click="chooseMovie(movies[$index])">
</div>
<div class="col-sm-4">
<img ng-src="http://image.tmdb.org/t/p/w185/{{movies[$index + 1].poster_path}}" ng-click="chooseMovie(movies[$index + 1])">
</div>
</div>

AngularJs ng-repeat does not update after filter object gets updated

Hi I am working on requirement where my filter object is keep getting changed and because of that i have to change ng-repeat on div.
html code :
<div class="col-md-6" ng-repeat="model in models | filter:{ModelText : '!All models', ModelId: '!FilteredModelIds'}:true">
<div class="well">
<div class="media">
<div class="media-object small"><i class="pp-car"></i></div>
<div class="media-body">
<div class="text-box">
<h3>{{model.ModelText}}</h3><span class="hr-small"></span>
</div>
<div class="dashboard-control clearfix">
<div class="simple-metric text-left sub-metric">
<div class="metric-title">Satisfaction score</div>
<div class="metric-number text-red">{{model.SatisfactionAvg}}</div>
</div>
<div class="simple-metric text-left sub-metric">
<div class="metric-title">Total interviews</div>
<div class="metric-number">{{model.TotalInterviews}}</div>
</div>
</div>
<ul class="list-standard">
<li> View interviews</li>
</ul>
</div>
</div>
</div>
</div>
here is the angular js code:
function getModelId() {
dataFactory.getModelIdByFilter($scope.region, $scope.subregion).success($scope.handleSuccess).then(function (result) {
$scope.FilteredModelIds = result.data;
});
}
Model json :
[{"ModelId":0,"ModelText":"All models","Sequence":0,"TotalInterviews":0,"SatisfactionAvg":0.000000},{"ModelId":1,"ModelText":"A3","Sequence":20,"TotalInterviews":2062,"SatisfactionAvg":9.637245},{"ModelId":2,"ModelText":"A4","Sequence":30,"TotalInterviews":3106,"SatisfactionAvg":9.743721},{"ModelId":3,"ModelText":"A5","Sequence":40,"TotalInterviews":1863,"SatisfactionAvg":9.694041},{"ModelId":4,"ModelText":"A6","Sequence":50,"TotalInterviews":280,"SatisfactionAvg":9.642857},{"ModelId":5,"ModelText":"A8","Sequence":70,"TotalInterviews":46,"SatisfactionAvg":11.217391},{"ModelId":9,"ModelText":"Q5","Sequence":110,"TotalInterviews":3176,"SatisfactionAvg":9.503778},{"ModelId":10,"ModelText":"Q7","Sequence":120,"TotalInterviews":1355,"SatisfactionAvg":9.685608},{"ModelId":11,"ModelText":"R8","Sequence":130,"TotalInterviews":31,"SatisfactionAvg":10.064516},{"ModelId":12,"ModelText":"TT","Sequence":140,"TotalInterviews":408,"SatisfactionAvg":9.764705},{"ModelId":13,"ModelText":"A1","Sequence":10,"TotalInterviews":1087,"SatisfactionAvg":10.097516},{"ModelId":14,"ModelText":"A7","Sequence":60,"TotalInterviews":263,"SatisfactionAvg":10.190114},{"ModelId":15,"ModelText":"Q3","Sequence":105,"TotalInterviews":1045,"SatisfactionAvg":9.542583}]
on page load its showing proper data with filter. but on change of filtered object in my case FilteredModelIds, its not getting updated. any help is appreciated.
please let me know if i am worng here.
Thanks.

Categories

Resources