I am developing application in which I have feeds or some timeline. here is my ng-repeat code:
<div ng-repeat="x in feeds" class="fd-feed-card">
<div class="fd-feed-usr-img">
<img ng-src="{{x.user.media[0].small}}" class="fd-img fd-img-br border-style">
</div>
<div class="ft-16 fd-feed-usr-name">
<span><b>{{x.user.name}}</b></span><span class="ft-12 fd-feed-created-time plx prm">{{x.feed.createdTimeStamp | readableTime}}</span>
</div>
<div ng-style="imgStyle">
<img ng-src="{{x.feed.media[0].medium}}" class="fd-img objectcover image-blur">
</div>
<div ng-if="x.feed.total_comments > 0 || x.feed.total_likes >0">
<p class="mll"><span on-tap="openCommentModal(x.feed._id, $index, x.feed)" class="prm" ng-if="x.feed.total_comments > 0">{{x.feed.total_comments}} Comment</span><span ng-if="x.feed.total_likes>0" on-tap="openUserModal(x.feed._id)">{{x.feed.total_likes}} Likes</span>
</p>
</div>
<div class="fd-feed-distance">
<span class="plx prm ft-16">{{x.distance}} <span class="ft-10">mil</span></span>
</div>
</div>
here every feed contains username, userimage and 400*400px image of feed and distance. after this im using ionic infinite scroll like this:
<ion-infinite-scroll on-infinite="getDashboardFeed()" distance="1%" ng-if="!noMoreFeedContent"></ion-infinite-scroll>
in my javascript code, i am calling API with pagination having 5 feeds at a time. here it is my javascript code:
$scope.getDashboardFeed = function(start) {
var _start = start || false;
var params = {}
params.offset = offset;
params.limit = limit;
Posts.getAllFeeds(params).success(function(res) {
if (_start) {
$scope.feeds = [];
}
if (res.data.length < limit) {
$scope.noMoreFeedContent = true;
} else {
$scope.noMoreFeedContent = false;
}
for (var i = 0; i < res.data.length; i++) {
var markerPos = new google.maps.LatLng(res.data[i].feed.location[0], res.data[i].feed.location[1]);
var currentLatLng = new google.maps.LatLng(res.data[i].location.location[0], res.data[i].location.location[1])
var distance = google.maps.geometry.spherical.computeDistanceBetween(markerPos, currentLatLng) * 0.000621371;
res.data[i].distance = distance.toFixed(2);
for (var j = 0; j < res.data[i].feed.likes.length; j++) {
if (uid == res.data[i].feed.likes[j].user) {
res.data[i].isLiked = true;
break;
} else {
res.data[i].isLiked = false;
}
}
$scope.feeds.push(res.data[i]);
}
offset = offset + limit;
if (_start) {
$scope.$broadcast('scroll.refreshComplete');
} else {
$scope.$broadcast('scroll.infiniteScrollComplete');
}
})
.error(function(err) {
})
};
im also calculating distance of every feed based on current location. and checking if i liked the post or not.
Now the problem is when feed is loaded to 25,30 , the scroll becomes laggy in my android . Im also using native scrolling given in this link ,
i have read also more blogs like this
but i didnt get much help. I have to load 1000s of feeds here where every feed contains 400*400px picture.
i also tried collection-repeat. it didnot work either.
Is there any other approach I can try to fix my scroll perfomance?
Anybody can help me with that?
I had same issue, especially when using images in ng-repeat.
Check out my answer here
Related
I've written code using Javascript to format the following section of a webpage based on the values:
<div class="col-md-auto mx-auto">
<h3>Average price</h3>
<p id="avgPrice"></p>
<br>
<div>Average change</div>
<div class="change" id = "avgChange"></div>
</div>
<div class="col-md-auto mx-auto">
<h3>Max price</h3>
<p id="maxPrice"></p>
<br>
<div>Max change</div>
<div class="change" id="maxChange"></div>
</div>
(The values for the text within each of the id's are getting pulled from a database, and appear correctly on the webpage when I start the server)
Here is my Javascript to format the HTML based on positive/negative values:
function changeFormatter() {
var elements = document.getElementsByClassName("change");
for (var i = 0; i < elements.length; i++) {
var change = elements[i]; //this is where the problem is
console.log(change);
if (change > 0) {
elements[i].innerHTML = "▴ " + change + "%";
elements[i].classList.add("text-success");
}
if (change < 0) {
elements[i].innerHTML = "▾ " + change + "%";
elements[i].classList.add("text-danger");
}
}
}
This code is being called by the following eventlistener:
window.addEventListener('load', (event) => {
console.log('page is fully loaded');
getData(); //gets values from database and adds them to HMTL
changeFormatter();
});
The issue is the line where I'm defining the var change. The output of the console.log on the line below it shows the text I want is there, see image below:
But no matter what I try I cannot get the text contained within this div. I've tried elements[i].value, .textContent, .innerHTML, .innerText, parseFloat(elements[i].innerHTML)... but they all return 'undefined' when I try and log them. I would really appreciate any suggestions!
Output of console.log(elements[i], elements[i].innerHTML)
.innerHTML should be correct as seen here: https://jsfiddle.net/awLynp28/3/. All I did was copy your script, have it run on page load (since it looks like you have something like that in there, I am assuming your function is getting called after the data is fully called in), and change
var change = parseFloat(elements[i].innerHTML);
document.addEventListener('DOMContentLoaded', function() {
var elements = document.getElementsByClassName("change");
for (var i = 0; i < elements.length; i++) {
var change = parseFloat(elements[i].innerHTML); //this is where I put innerHTML
console.log(change);
if (change > 0) {
elements[i].innerHTML = "▴ " + change + "%";
elements[i].classList.add("text-success");
}
if (change < 0) {
elements[i].innerHTML = "▾ " + change + "%";
elements[i].classList.add("text-danger");
}
}
}, false);
I'm using ngInfiniteScroll in a few different places to show contacts, and missed calls. It loops over every item and adds a ng-click to show user profile. The scrolling works fine in all locations until you actually click on a user/call. Afterwards the scroll never triggers again in either contacts nor phone calls. I've looked at their docs and seen infinite-scroll-listen-for-event which I figured is what I needed for infinite scroll to reset after the click event, but it doesn't appear to be working. I can't tell if I have the $emit in the wrong location, or what?
HTML
<md-list infinite-scroll="recent.moreContacts()" infinite-scroll-disabled="recent.busy" infinite-scroll-listen-for-event="resetInfiniteScrollList" infinite-scroll-distance="1" infinite-scroll-immediate-check="false" infinite-scroll-parent="true">
<md-list-item ng-repeat="client in recent.clients | orderBy:'firstName'" ng-click="recent.viewCustomer(client.id)" class="repeater-list-item recent-session" layout="row" layout-align="start start" aria-label="View {{client.fullName}}'s profile">
<div ng-if="client.avatar" class="md-avatar" style="background-image: url('{{client.avatar}}');"></div>
<div ng-if="!client.avatar" class="md-avatar" ></div>
<div class="md-list-item-text">
<h3>{{client.firstName}} {{client.lastName}} <span ng-if="!client.firstName">Unknown <small class="text-tertiary text-gray">(Customer: {{client.id}})</small></span></h3>
</div>
</md-list-item>
</md-list>
loading contacts
vm.moreContacts = function () {
$timeout(function () {
$rootScope.closeSidenavs();
$rootScope.btnActive = 'contacts';
$mdSidenav('contacts').open();
$sessionStorage.currentTab = 'contacts';
if (vm.busy || vm.foundAllContacts || vm.contactsSearchActive) {
} else {
vm.busy = true;
api.get('/account/' + $rootScope.user.account.id + '/clients?page=' + vm.contactsNextPage, function (success, data) {
if (success) {
for (var i = 0; i < data.clients.length; i++) {
vm.clients.push(data.clients[i]);
}
self.totalFound = data.totalFound;
self.lastPageLoaded = data.page;
if (data.clients.length === 25) {
vm.contactsNextPage = vm.contactsNextPage += 1;
console.log(vm.contactsNextPage);
}
if (vm.clients.length === self.totalFound) {
vm.foundAllContacts = true;
}
} else {
vm.isClientsError = true;
}
vm.busy = false;
});
}
}, 10);
};
ng-click function
vm.viewCustomer = function (clientId) {
if (clientId > 0) {
if ($mdMedia('xs') || $mdMedia('sm')) {
$rootScope.btnActive = '';
$rootScope.closeSidenavs();
}
$location.path(
"/customer/" + clientId + "/feed"
);
$rootScope.$emit('resetInfiniteScrollList');
//vm.contactsSearchActive = false;
}
};
I'm working on a project at the moment using angular JS.
I've used a directive to switch from advanced search so that the results can be viewed on its own page. basically when submit is clicked, the advanced search is hidden and only results table can be seen. so now, once on results table, I want to be able to go back to that advanced search to the point before I hit that submit button, the data is still there, I have just reversed the directive in a way. any suggestions would be greatly appreciated, this is all fairly new to me.
thanks! (please note, my search controller uses TypeScript)
this is being called just under the submit button on the search_partial.html
<div class="submit">
<button class="btn btn-primary" type="button" name="Submit" ng-click="vm.validateForm()" ng-disabled="!(!!vm.hospitalNumberInput || !!vm.nhsNumberInput || !!vm.fullNameInput || !!vm.sexInput || vm.yearOfBirthInput || !!vm.streetInput || !!vm.cityInput
|| !!vm.postCodeInput || !!vm.chosenCountry)">Search</button>
Clear all
</div>
</form>
<section>
<div id="searchDirective" search-results patients="vm.results" class="ng-hide"></div>
</section>
and I have a directives file called search.results.directive.js
(function () {
angular
.module('app.search.results')
.directive('searchResults', function() {
return {
restrict: 'AE',
templateUrl: 'app/search/Partials/result_partial.html',
scope: {
patients: '='
}
};
});
})();
so what I'm trying to do now that I can see the results-partial.html on the screen in front of me, I want to be able to click a back button on there to take me back to the search-partial.html at the point before the user clicked that submit button so that the data in the boxes can be altered if needs be or more search data added. (at the moment I have a back href going to the home url, it works for now, but that's what im hoping to replace).
results-partial.html:
<main class="container">
<!-- RESULT -->
<section class="result-display">
<form>
<div class="searchresults content table-responsive">
<h2>Search Criteria: </h2>
<h2> Search Results: {{patients.length}} patients found</h2>
<table class="table resultstable table-striped">
<thead>
<tr class="theading">
<th>Hospital number</th>
<th>NHS Number</th>
<th>Full Name</th>
<th>DOB</th>
<th>Sex</th>
</tr>
</thead>
<!--repeated simply for style insight-->
<tbody>
<tr ng-repeat="patient in patients">
<td>{{patient.resource.hospitalNumber}}</td>
<td>{{patient.resource.nhsNumber}}</td>
<td>{{patient.resource.nameString}}</td>
<td>{{patient.resource.birthDate}}</td>
<td>{{patient.resource.gender.toUpperCase()}}</td>
</tr>
</tbody>
</table>
</div>
<a href style="float: right; font-size:120%;" onclick="location.href='http://localhost:3000/';"><i class="close"></i><u>Back to Search</u></a>
</form>
</section>
</main>
If I understand the question right, you want to preserve the values in the input.
You can use a factory or value to store the data.
myApp.factory('DataHolder', function (){
return data;
});
// Or, with value
myApp.value('DataHolder', data);
And in your controller you can access that data anywhere.
myApp.controller('Ctrl', function ($scope, DataHolder){
$scope.data = DataHolder;
});
So when you come back to the back state, if you have data stored you can get it back to show it.
fixed it. managed to get it working my changing the flag to false with "returnToSearch()" function at the bottom.
createDisplayParams(): void {
// add in search params to display params
var paramTypes: string[] = [];
for (var i: number = 0; i < this.searchParams.length; ++i) {
var objectIndex: number = paramTypes.indexOf(this.searchParams[i].ParamName);
if (objectIndex === -1) {
// if param name dosen't exist, add it to the paramTypes
paramTypes.push(this.searchParams[i].ParamName);
}
}
for (var j: number = 0; j < paramTypes.length; ++j) {
var valueParams: core.ISearchParam[] = [];
valueParams =_.filter(this.searchParams, searchParam => { //lodash
return searchParam.ParamName == paramTypes[j];
});
var valueStrings: string[] = [];
valueParams.forEach(v => valueStrings.push(v.ParamValue));
this.displayParams.push({ paramType: paramTypes[j], paramValue: valueStrings.join(", ") });
}
}
obtainPatientInformation(): void {
this.createSearchParams();
if (this.searchParams.length > 0) {
var rawResults: angular.IPromise<core.IPatient> = this.searchDataService.performAdvancedSearch(this.searchParams);
var searchControllerInstance: SearchController = this;
this.createDisplayParams();
rawResults.then(
function success(response: any): void {
if (response.data.entry && response.data.entry.length > 0) {
searchControllerInstance.noResults = false;
searchControllerInstance.results = response.data.entry;
for (var index: number = 0; index < searchControllerInstance.results.length; index++) {
var patient: core.IEntry = searchControllerInstance.results[index];
patient.resource.nameString = '';
if (patient.resource.name) {
var familyNameArray: string[] = patient.resource.name[0].family;
for (var familyIndex: number = 0; familyIndex < familyNameArray.length; familyIndex++) {
var familyName: string = familyNameArray[familyIndex];
patient.resource.nameString = patient.resource.nameString + ' ' + familyName.toUpperCase() + ',';
}
var givenNameArray: string[] = patient.resource.name[0].given;
for (var givenIndex: number = 0; givenIndex < givenNameArray.length; givenIndex++) {
var givenName: string = givenNameArray[givenIndex];
patient.resource.nameString = patient.resource.nameString + ' ' + givenName;
}
}
var identifiers: core.IIdentifier[] = patient.resource.identifier;
for (var indentifierIndex: number = 0; indentifierIndex < identifiers.length; indentifierIndex++) {
var identifier: core.IIdentifier = identifiers[indentifierIndex];
if (identifier.system) {
if (identifier.system === 'nhsNumber') {
patient.resource.nhsNumber = identifier.value;
}
if (identifier.system === 'hospitalNumber') {
patient.resource.hospitalNumber = identifier.value;
}
}
}
}
} else {
searchControllerInstance.noResults = true;
searchControllerInstance.results = null;
}
});
}
this.searchClicked = true;
this.checkSearch();
}
checkSearch(): void {
var resultSectionElements: angular.IAugmentedJQuery = angular.element('[id*="resultSection"]');
var advanceSearchSectionElements: angular.IAugmentedJQuery = angular.element('[id*="advanceSearchSection"]');
if (this.searchClicked) {
resultSectionElements.removeClass('ng-hide');
advanceSearchSectionElements.removeClass('ng-show');
advanceSearchSectionElements.addClass('ng-hide');
} else {
resultSectionElements.addClass('ng-hide');
advanceSearchSectionElements.removeClass('ng-hide');
advanceSearchSectionElements.addClass('ng-show');
}
}
returnToSearch(): void {
this.searchClicked = false;
this.searchParams.splice(0,this.searchParams.length);
this.displayParams.splice(0,this.displayParams.length);
this.checkSearch();
}
I have an ngRepeat with a limitTo in my HTML. This will show the first x number of users - essentially paginating the table. I now need to be able to show the next batch of x users. I've added a couple of anchors to go to previous or next page (with functions attached to the click)
I'm now not sure how to manipulate the ngRepeat through these functions to actually show the correct batch of users.
HTML
<div ng-repeat="user in users | limitTo:paginate.size">
{{user.name}}
{{user.email}}
</div>
<ul class="pagination">
<li>left</li>
<li>right</li>
</ul>
JS
$scope.users = //full users object here
$scope.paginate = {};
$scope.paginate.size = 10;
$scope.prevPage = function(){
//load the previous 10 users
}
$scope.nextPage = function(){
//load the next 10 users
}
You should add another filter (or simply a custom filter) such as
<div ng-repeat="user in users | filter:getList(user, index)">
{{user.name}}
{{user.email}}
</div>
and then in the scope
$scope.users = //full users object here
$scope.paginate = {};
$scope.paginate.size = 10;
$scope.paginate.start = 0;
$scope.prevPage = function(){
//load the previous 10 users
if ($scope.paginate.start) {
$scope.paginate.start -= $scope.paginate.size;
}
}
$scope.nextPage = function(){
//load the next 10 users
$scope.paginate.start += $scope.paginate.size;
}
$scope.getList = function (user, index) {
return (index >= $scope.paginate.start && index < $scope.paginate.start + $scope.paginate.size);
};
I have a page running angularJS. Sometimes, when I open the document, the data that needs to appear only sometimes shows up. When I keep trying to refresh the page, it's pretty much random: sometimes the content appears, sometimes it doesn't.
The section of the code that runs this looks like this:
<div class="row">
<div class="col-md-12" ng-repeat="(observer,hosts2) in bugDuration">
{{observer}}
<div class="row">
<div class="col-md-3" ng-repeat="(host, bugs2) in hosts2"> {{host}}
<div ng-repeat="(bug, duration) in bugs2">
{{bug}} for {{duration}} seconds.
</div>
</div>
</div>
</div>
</div>
As you can see, it is using ng-repeat, and my best guess is that when this code is running, the ng-repeat objects, such as bugDuration are empty, so none of it runs.
My script that initializes all of these variables is located after, in my document. Is there something I should do in the controller or whatever so the variables can be refreshed and the content can be shown everytime?
Edit
Here is the code where bugDuration is initialized:
bugDuration = {};
bugTracker = {};
$.getJSON('../java_output/bugs.json', function (data) {
for ( var observer in data ) {
bugDuration[observer] = {};
for (var host in data[observer]) {
bugDuration[observer][host] = {};
for (var bug in data[observer][host]) {
bugDuration[observer][host][bug] = data[observer][host][bug].duration;
}
}
}
console.log (bugDuration);
});
$.getJSON('../java_output/bug_summary.json', function (data) {
var numObservers = data.numObservers;
delete data['numObservers'];
JSONbugsList = data;
var bugTracker = {};
for (var observer = 1; observer <= numObservers; observer++) {
observers.push(observer);
observerKeys = Object.keys(data);
// observerKeys.splice(observerKeys.indexOf('numObservers'));
for (var host in data["observer" + observer]) {
if (hosts.indexOf(host) == -1) {
hosts.push(host);
}
hostKeys = Object.keys(data["observer" + observer]);
for (var bug in data["observer" + observer][host]) {
if (bugs.indexOf(bug) == -1) {
bugs.push(bug);
}
for (var i in data["observer" + observer][host][bug]) {
bugTracker[bug] = true;
var dateVar = data["observer" + observer][host][bug][i];
var intoList = {"observer":observer, "host":host, "bug":bug, "start":(new Date(1000*dateVar.start)), "end":(dateVar.end==null?' the end.':(new Date(1000*dateVar.end)))}
}
}
}
}
// Removed unimportant stuff here//
$scope.$apply();
$scope.hostsS = hosts;
$scope.bugsS = bugs;
$scope.observersS = observers;
$scope.JSONbugsList = JSONbugsList;
$scope.hostKeys = hostKeys;
$scope.observerKeys = observerKeys;
$scope.start = 'start';
$scope.end = 'end';
$scope.bugDuration = bugDuration;
$scope.$apply();
The biggest problem among others is that $scope.$apply() needs to happen after the data gets set on the $scope. Since $.getJSON is asynchronous, by the time the callback gets triggered, the $scope.$apply() lines at the bottom will have already been fired.
$.getJSON('../java_output/bug_summary.json', function (data) {
/*do stuff outside of angular context when the ASYNC callback fires*/
$scope.stuff = data;
/*then call $scope.$apply()*/
$scope.$apply();
});