0

I want to build a commenting system for a news portal.

I want jQuery AJAX to detect if anyone adds a comment data, it automatically updates the added comment in slideDown motion.

How can I do that? Thanks.

(Note: I'm using ASP.NET as server)

enter image description here

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>
        $(document).ready(function () {
            $.ajax({
                url: 'WebForm1.aspx',
                success: function (data) {
                    $("#Urunler").html(data);
                }
            });
        });
    </script>
    <style>
        li
        {
            width: 100px;
            height: 30px;
            background: yellow;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>


        <ul id="Urunler" runat="server">

        </ul>


    </div>
    </form>
</body>
</html>

Here is the code behind,

using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;

namespace WebApplication2
{
    public partial class WebForm1 : System.Web.UI.Page
    {

        SqlConnection cnn = new SqlConnection("Initial Catalog=Northwind;Data Source=localhost;Integrated Security=SSPI;");

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                cnn.Open();
                SqlCommand cmd = new SqlCommand("SELECT FirstName FROM Employees", cnn);
                SqlDataReader dr = cmd.ExecuteReader();
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Urunler.InnerHtml += "<li>" + dr.GetString(0) + "</li>";
                    }
                }
                cnn.Close();
            }
        }
    }
}
Hasan Alaca
  • 232
  • 2
  • 14

6 Answers6

8

If i get it right you are looking for something like facebook/gmail's real time notification.

You can achieve it by implementing several architecture :

  1. Ajax Pooling : Doing an ajax request after every N (asuume 5) seconds to the server and server will feed you the latest comments. This is the easiest and heaviest way. With a bit of traffic , it will not take a hell lot of time in flooding your server with so many unnecessary request as you will be doing request even if nothing happens.
  2. Web Socket : You can use socket.io and open a socket to relay the updates to the all the clients. This is a common approach to solve this problem. A nifty one too. You can use this answer to cope up this approach.
  3. Reverse Ajax / Comet : Last one is the toughest one . Facebook uses this architecture and as they are handling a bit of high traffic (:p) we can assume this one has the ability to scale. You can go through this video to understand the reverse ajax or comet approach. This so answer help you to get the idea of it.

Update: This article seems to give a bit of touch in different techniques to achieve your goal. It might help.

Community
  • 1
  • 1
MD. Sahib Bin Mahboob
  • 20,246
  • 2
  • 23
  • 45
5

I'll give it a shot!

This should get the LI's from the server every five seconds, and compare them against any existing comments, and if they are different, insert the new comments into the DOM and slide them down :

var comments = {
    get: function () {
        return $.ajax({ 
            url   : 'WebForm1.aspx',
            cache : false
        });
    },
    check: function (coll1, coll2, UL_ID) {
        var diff = [];
        $.each(coll2, function (_, li2) {
            var same = false;
            $.each(coll1, function (_, li1) {
                if ($(li1).text() == $(li2).text()) same = true;
            });
            if (!same) diff.push(li2);
        });
        this.output(diff, UL_ID);
    },
    poll: function (UL_ID) {
        var self = this;
        self.get().done(function (data) {
            self.check($(UL_ID).find('li'), $('<ul />').append(data).find('li'), UL_ID);
        });
    },
    output: function (elems, UL_ID) {
        $.each(elems, function (i, elem) {
            $(elem).hide().delay(i * 300).slideDown(350).appendTo($(UL_ID));
        });
    },
    init: function (UL, interval) {
        var self = this;
        setInterval(function () {
            self.poll(UL);
        }, interval);
        this.poll(UL);
    }
}

$(document).ready(function () {
    comments.init('#Urunler', 5000);
// ^^ starts plugin   ^^ ID     ^^ polling speed (5 seconds)
});

I highly recommend giving each comment an UUID in the database, and then use that to compare against to find new comments.
The code above now compares the content of the comment only, so if the exact same comment is posted twice, there could be issues.

It seems like the only thing your database is outputting is the comment itself, there is no unique identifier, so that would require a change in the database structure were you'd add a row for UUID, which would be somewhat outside the scope of the question in my opinion.

Here's a quick demonstration where the database has been substituted with localStorage

DEMONSTRATION

adeneo
  • 312,895
  • 29
  • 395
  • 388
  • @HasanAlaca - wow, thanks! Couldn't understand why I didn't get any upvotes, I took me quite some time to figure that one out, but all the upvotes where going to the answer suggesting really general solutions for data retrieval so I was thinking I misread something when I posted something I thought would actually work! – adeneo Nov 18 '13 at 17:43
  • Also, take notice on the comment about unique identifiers for each comment, that would make it easier to compare comments and be more resiliant than just checking the contents of the comment, and the same function as above should basically work with a few minor changes for that as well. – adeneo Nov 18 '13 at 17:45
2

You need to pass your already loaded data to server, the server can check and return those that are not loaded yet. Here I also recommend using setTimeout instead of setInterval. Because setInterval will always fire the next call after an interval, inside the function you also use ajax which is also underministic => this could become messy when your server is under heavy load with slow response time. In this function, we should set the next interval only when the current ajax has completed.

<script>
        $(document).ready(function () {
            refreshComments(); //trigger the first call
        });

        function refreshComments(){
            var loadedIds = $("#Urunler li").map(function(){
                              return $(this).attr("employeeId");
                          }).get()
                          .join(",")); //get current loaded ids

            $.ajax({
                url: 'WebForm1.aspx?loaded='+loadedIds,
                success: function (data) {
                    if (data){ //append only when there is a newly added comment.
                       var element = $(data);
                       element.hide();
                       $("#Urunler").append(element);//use append instead of html because html will replace the old ones.
                       element.slideDown();
                       setTimeout(refreshComments,5000);
                    }
                }
            });

        }
</script>

Server side code needs to be updated to return the ids and check for the ids

using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;

namespace WebApplication2
{
    public partial class WebForm1 : System.Web.UI.Page
    {

        SqlConnection cnn = new SqlConnection("Initial Catalog=Northwind;Data Source=localhost;Integrated Security=SSPI;");

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                //Check for already loaded Ids, I assume that each record in your database has an Id
                string loadedIds = Request.QueryString["loaded"];
                string sql = "SELECT EmployeeId,FirstName FROM Employees";
                if (!string.IsNullOrEmpty(loadedIds)){
                    sql = "SELECT EmployeeId ,FirstName FROM Employees WHERE EmployeeId NOT IN (" 
                           + loadedIds +")";  
                }// You could query it using a safer method than string concatenation, here I just demonstrate the idea

                cnn.Open();

                SqlCommand cmd = new SqlCommand(sql, cnn);
                SqlDataReader dr = cmd.ExecuteReader();
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        //This should be a Literal Control, embed Id in the response.
                        Urunler.Text += string.Format("<li employeeId='{0}'>{1}</li>",dr.GetString(0),dr.GetString(1));
                    }
                }
                cnn.Close();
            }
        }
    }
}
Khanh TO
  • 48,509
  • 13
  • 99
  • 115
0

You can try this

        var lastSearchedDate =  new Date();
    var isBusy = false;

    function scrollEvent(e) {
        var body = document.body,
             html = document.documentElement;

        var docHeight = Math.max(body.scrollHeight, body.offsetHeight,
                               html.clientHeight, html.scrollHeight, html.offsetHeight);
        var currentScroll = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
        if (((docHeight * 75) / 100) < currentScroll) {
            if (!isBusy) {
                fetchData()
            }
        }
    }

    function fetchData(){
        isBusy = true;
        $.ajax({
            cache: !1,
            type: "POST",
            data: $.toJSON(dataToPost_with_lastSearchedDate),
            contentType: "application/json; charset=utf-8",
            url: requestUrlToFetch_JSON_Data,
            success: function (response_JSON_data) {
                // Parse this JSON data and Append HTML to any div you want on Your Page 
                doStuff(response_JSON_data);
                lastSearchedDate =  new Date();
                isBusy = false;
            },
            error: function (xhr, ajaxOptions, thrownError) {
                alert(ajaxOptions);
                alert(thrownError);
                alert(xhr.status);
            }
        });
    }

    function OnFirstLoad() {
        fetchData();
        if (document.attachEvent) {
            document.attachEvent('onscroll', scrollEvent);
        } else if (document.addEventListener) {
            document.addEventListener('scroll', scrollEvent, false);
        }
    }

    window.onload = OnFirstLoad;

Note, that we are using javascript date which will need to be parsed at server web/page method for which we have made request (using DateTime.ParseExact).

Hitesh Gaur
  • 362
  • 1
  • 11
0

try something like this,I have never implemented might be useful for you

The idea for either is that you run a server file (written in PHP), that waits for connections. Once it's connected to one or more clients, data can be pushed both ways. There are a few PHP WebSocket projects out there. Check out this:

http://code.google.com/p/phpwebsocket

node.js => http://nodejs.org/

http://net.tutsplus.com/tutorials/javascript-ajax/learning-serverside-javascript-with-node-js/

BinaryJS =>http://binaryjs.com/

http://ajaxpatterns.org/HTTP_Streaming

rajesh kakawat
  • 10,826
  • 1
  • 21
  • 40
0

Check here http://www.w3schools.com/html/html5_serversentevents.asp for server sent events with html5, it's what twitter and Facebook use.

Marios Fakiolas
  • 1,525
  • 1
  • 12
  • 19