Load more comments with PHP and AngularJS - javascript

I have a table of comments and a table of replies to comments and currently use AngularJS. I have a page for a user and load all the associated comments and replies on his/her profile. Since I'm just testing this on my local server for now, the sample size is very small (less than 10 rows returned). However, in order to create a scalable site, I'm wondering what I can do in terms of buttons or functions like "Load more comments" and "Load more replies".
Do I need to load all the comments of a user ALWAYS? What if the user has 3000 or even 10000 comments on his/her profile and there are more than 10000 users? Won't this take a long time for the profile page to even load? It seems like a waste to load all the comments and replies when less than 1/5 of them will even be seen in the first place. Is there anyway I can query the database to load the first 100 rows, than load the next 100 rows or something similar? What is the formal practice (and optimized for performance for this?)
As well, my general idea for "loading more comments" in Angular if I do always have to load all the comments is something like this:
$scope.allcomments = [some array of comments];
$scope.display = $scope.allcomments.slice(0, 5);
$scope.num = 5;
$scope.loadmore = function() {
var x = $scope.num
$scope.num += 5;
$scope.display.push($scope.allcomments.slice(x, $scope.num));
}
But is there no better way to do it?

I assume you're going to use ngRepeat to show the results, if so:
In view, i.e.:
<div ng-repeat="comment in allcomments | limitTo:num">{{comment}}</div>
In Controller:
$scope.loadmore = function() {
$scope.num += 5;
}

Related

Trying to display an array part after part

I'm currently displaying the content of an array in a view, let say $scope.array.
I load the content of an array with a request to my serv.
Sadly $scope.array contains a lot of elements an displaying every elements at once in the view takes a while.
In order to enhance user experience, I'd like to display the array part by part. At first I thought that $scope was able to handle it if I just proceed to add data chunk by chunk to $scope.array, but nope.
I figured out that the current $digest loop would only be over when my array was full. I tried with Async lib to add chunks asynchronously to $scope hoping for a way to dodge the $digest issue, but it doesn't work.
Now I kinda ran out of ideas to display datas properly, so if you had any experience with this kind of issues I'd be glad to hear about it !
Thanks a lot.
If pagination, periodic requests etc is ruled out then...
You can have all of your data in one array not bound to ui.
You then periodically add the data into a second array that is bound to the ui. Similar to how you mentioned you are already doing it but simply add the chunks in a $timeout or an $interval. This lets the $digests and page renders complete.
Simple Example:
<table>
<tr ng-repeat="item in shownItems track by $index">
<td>{{item}}</td>
</tr>
</table>
and in controller
app.controller('MainCtrl', ['$scope', '$timeout', function($scope, $timeout) {
//array that is bound to ui
$scope.shownItems = [];
//backing data
var fullItemsList = [];
//Create some fake data, you wouldn't do this in your program,
// this is where you would fetch from server
for(var ii = 0; ii < 50000; ii++){
fullItemsList.push("AYYYLMAO " + ii);
}
//How many items to add at a time
var chunkSize = 500;
//keep track of how many we have already added
var currentChunkIndex = 0;
//transfers a chunk of items to ui-bound array
function addMoreItems(){
var start = currentChunkIndex * chunkSize;
var end = (currentChunkIndex + 1) * chunkSize;
for(var ii = start; ii < end; ii++){
if(!fullItemsList[ii]){
break;
}
$scope.shownItems.push(fullItemsList[ii]);
}
currentChunkIndex++;
}
//Transfer chunk of items in a timeout, trigger another timeout to
//add more if there are stil items to transfer
function periodicAdd(){
$timeout(function(){
addMoreItems();
if(currentChunkIndex*chunkSize >= $scope.shownItems.length){
periodicAdd();
}
},0);
}
//Add the first chunk straight away, otherwise it will wait for the
//first timeout.
addMoreItems();
//Start the timeout periodic add.
periodicAdd();
}]);
Example plunkr
Keep in mind that this example is very rough. For instance the initial "load" of 50k rows will run on ui thread whereas your data load will presumably come async from your server. This also means you need to kick off the periodic adding only when your request completes. So yeah just a rough example.
Note that I use a 0 millisecond timeout.This will still push the callback to the end of the current processing queue, it wont execute straight away despite being 0 milliseconds. You might want to increase it a little bit to give your app a bit of breathing room. Remember to properly dispose of timeouts.
Use server side pagination. Even using one-time bindings is not always the solution, especially if there is complex template logic (show/hide parts depending on the data properties) and if the editing is required.
If you want to filter your array by some criteria (for example, month and year), implement this on the backend and pass your criteria to the server: GET /my_data?year=2017&month=7&page=1.

Executing a Function from a separate page

I'm not entire sure that this is possible, but here's what I'm looking at doing.
I have a list of buttons, that when pressed, modify a database that they are attached to, (for example, clicking button 1 would add 10 points to the score of player 1)
What I am looking to do in tandem, is to call a javascript function that lives on a separate page, a sort of a visual confirmation that the points were added to player 1's account.
Why am I organizing it like this?
I am running a Twitch channel where I am building a series of web views to display stats and information. I wish to control WHAT the audience sees from one page, and have the results display on a different page.
Here's what I have so far:
HTML (admin page):
<button class="addPoints" data-id="player1" data-name="Player 1">Player 1</button>
JS (admin page):
$(".addPoints").on('click', function(){
var $id = $(this).data('id');
var $name = $(this).data('name');
//AJAX MAGIC TO INSERT POINTS INTO DATABASE SO I CAN KEEP SCORE//
tallyPopup($id, $name);
});
HTML (display page):
<div class="displayScreen"></div>
JS (display page):
function tallyPopup(member, name){
$('.displayScreen').append(<div class='tallyPopup' id='"+member+"'><div class='portrait' id='"+member+"'></div><span class='name'>"+name+"</span><span class='score'>+10</span></div>);
$('.tallyPopup').animate({
opacity: 1
}, 3000, function(){
$(this).remove();
});
}
I know what I have does not connect the two pages, because I haven't the first clue on how to do that, if it's even possible. OR, is there a way for the Display HTML to check if the database has been updated and THEN run the tallyPopup function?
Thanks in advance.
You cannot call a function on another client (including your own clients) running your website.
To continuously check for points on the display page, use var intv = setInterval(function () {}, nMilliseconds) to repeatedly run a function until you call clearInterval(intv), which you might not do since you may want this to run forever, but perhaps only once every minute (nMilliseconds = 60000).
setInterval(function () { $.get('/point-count').then(tallyPopup) }, 60000)
tallyPopup would receive the data argument from the AJAX response.
Of course on the admin side you must fill in that line to update the amount of points via AJAX, either by PUT, POST, or PATCH. I would consider using PATCH just as a matter of semantics.
Also consider storing the return value of $(this) (var $this = $(this)) instead calling it multiple times, use promises, use CSS animations instead of $.animate (these perform much better). Consider making the element opaque and then visible (perhaps off screen when invisible), instead of using $.remove (also a performance improvement).

I wana display just 10 rows per page.But i don't know how?

I used this code its working fine and displaying all the employees in single page.. It doesn't looks good. So I want 10 employees per page and when I click on next next 10 has to display .This is exactly I want. Please help me
angular.module('picassoApp')
.controller('AdminCtrl', function($scope, $http, $location) {
$scope.employees =
$http.get("api/employee")
.success(function(response) {
$scope.employees = response;
})
.error(function(data, status, headers, config) {
console.log("Error" + status);
});
});
Here is some solutions that you need to think and apply as per your application's requirement.
You are making AJAX call here. If you really need to call AJAX on every page change on "Next" button click, then your server side code need to change accordingly and need to send the Page number on each call. But seems it is not your solution because you want this for screen look and feel.
Pagination on client side is just suitable for you. Capture the response and put it on a variable, say employees. Then use angular filter limitTo as follows on ng-repeat.
{{ employees | limitTo : rowLimit : rowStart}}
then change the rowStart on Next Button event with +10 or -10
and also do not forget to define the following on Controller initialization.
$scope.rowLimit = 10;
$scope.rowStart = 0;
https://docs.angularjs.org/api/ng/filter/limitTo
There are two approaches to this.
First, if you control the API, you can change it to return paged results. Then, instead of calling just $http.get("api/employee") you'd have to call something like $http.get("api/employee?page=0").
If you have no control over the API, however, you may use client side paging using the angular's limitTo filter (https://docs.angularjs.org/api/ng/filter/limitTo).
Your controller would stay mostly the same, you'd have to modify the view by adding the filter to your ng-repeat (e.g. ng-repeat="employee in employees | filter:10:startIndex, assuming you have the startIndex scope variable determining which item to start with).

AngularJS - How to create a backend?

I have an angularjs app on one html page and it pretty much works well. But instead of using constants on a angularjs script, I'd like to make it dynamic where someone can change the values from another page. Here's some sample code I'd like to be dynamic:
// compute base_cost
$scope.base_cost = function(pages, delivery) {
// change this if you want to change price per page
price_per_page = 150;
// change this if you want to change the cost of a 3 day delivery
three_business_days = 100;
base_cost = pages * price_per_page;
if (delivery === "3 Business Days"){
base_cost = pages * price_per_page + three_business_days;
}
return base_cost;
};
I'd like the price_per_page and three_business_days to have a seperate page (maybe password-protected) where these variables' constants can be changed by the client when he wants to change the price, etc.
What is the simplest way to do this?
P.S. I'm already currently searching about it, but just a bit of guidance would be greatly appreciated.
Thanks
Assuming another page means another view, see this answer. Basically, create a service.
Assuming you want to persist these values across sessions you need more than just a service: you need some kind of API / database.
There are endless choices: node.js, ASP.NET Web API, etc. Depends on your experience.
Have you considered firebase to get something up and running quickly (assuming you don't have existing infrastructure to rely on)? There's a reasonable free tier for experimentation.
https://www.firebase.com
There's also some nice AngularJS support:
https://www.firebase.com/docs/web/libraries/angular/index.html
The real time aspect may be overkill though..
What you are describing is a factory / service. It is the model in an MVC application.
In angular, a factory is a singleton, you don't instantiate new copies of it, and changes made to it in one area persist through to another area of site. Of course, that is only during the life of your session, you'd need to store the models state to some other form of storage.
Here is an example application, it has a controller (to show how to use it), and a factory.
angular.module('testModule', [])
.factory('BaseCost', function(){
// change this if you want to change price per page
price_per_page = 150;
// change this if you want to change the cost of a 3 day delivery
three_business_days = 100;
return {
price: function(amt){
price_per_page = amt;
},
days: function(cost){
three_business_dates = cost;
},
base: function(pages){
return pages * price_per_page;
}
};
})
.controller('ACtrl',function($scope, BaseCost){
$scope.setPrice = function(amt){
BaseCost.price(amt);
};
$scope.daysCost = function(cost){
BaseCost.days(cost);
}
$scope.baseCost = BaseCost.base(pages);
});

AJAX progress bar on array iteration?

I am not too familiar with AJAX but I'm sure what I am trying to do is possible.
Basically I have a form with a text area, when the form is submitted the text area is made into an array with each new line being a value. Simple stuff, now my php then performs a database query on each array value. Also simple.
Now as the operation takes a while I want to make it into an AJAX call using jquery, and for every iteration on the array I want it to display the result back on my main page as well as displaying a progress bar.
So if my text area contains a list of 20,000 names and the query is to fetch the ages of these people, the ajax call would split the textarea into an array and iterate the array. For each iteration it should perform the query and send the result to my main page. So on my main page I will see a list that grows over time.
I hope I have explained this well enough, I just need advice on where to start/what to research. Any examples would be greatly appreciated.
Thanks!
As ajax is simply a request for data you cannot create a reliable loading bar easily.
However if you are doing loads of requests as you suggest in your question, "Which by the way is not the best idea".
You could do something like the code below. Again its pretty basic but will give your user a rough idea. I stuck it in a fidddle here for you http://jsfiddle.net/6dgAF/ its a basic example but should give you a jump off point.
function Status(data)
{
this.data = data;
this.size = this.data.length;
this.current = 0;
this.bar = $("#bar");
//Get width of each step of load
this.step = (this.bar.width() / this.size) ;
for(var i =0; i < this.size; i++){
this.getData(this.data[i]);
}
}
Status.prototype.getData = function(string){
//run your ajax here on each string and on success do this
//$.get( "ajax/test.html", function( string ) {
//this.current++;
//this.updateBar();
//});
this.current++;
this.updateBar();
}
Status.prototype.updateBar = function(){
//updates the bar with the current count * step width;
$("span",this.bar).width(this.step*this.current);
}
//Init object and put in dummy data
var status = new Status(new Array("string1","string2","string3","string4","string5","string6","string7","string8","string9","string10"));
An AJAX request is nothing else than requesting data from your server, just like any HTML page. The only difference is that you use Javascript, and don't feed the data to your browser as an HTML page, but use the data some way on your page.
One possible way to do the thing you want is the following:
Set an interval with the refresh rate, which calls a function getData
In getData you perform an AJAX request, which requests a piece of data from the server, which represents the current state. You might want to make sure the server only returns incremental updates, to avoid sending large amounts of data
Use the data on your front page, by displaying it in a friendly way to the user.
The main thing to keep in mind is that the server must save it's current state (the data which it has gathered with its queries), which it must return in the event of an AJAX request.
What you want is called XHR2 - personally I am using dojo
(dojo/request/xhr here)
However it should be possible with jQuery as well, search for jQuery XHR2 progress ...

Categories

Resources