0

I have a repeater (for content posts) which contains an update panel, which in turn, contains another repeater as a (child for comments).

What I am trying to achieve is having a user comment/liking on a post. The values are verified using JavaScript/JQuery and sent to the server using PageMethods. I managed to get the UpdatePanel to refresh from JavaScript. The problem I am facing is that I need to somehow find the Posts RepeaterItem so that I can create an instance of the Comments Repeater in order to rebind it to the data source which would make the users comment appear after they enter it.

I tried searching online for a couple of days now but no one seems to address this issue using nested repeaters mixed with JavaScript and update panels etc. I don't mind a full page postback and I do not mind changing the structure of my page if necessary. The only thing that I would like is that the user stays on the same place on the page when this process happens and I am worried that with a complete page refresh, the user will be navigated back to the top of the page. JavaScript is the right way to do it for immediate feedback. I am however new to JavaScript in ASP and C# so it's proving to be a bit of a challenge.

Structure

Repeater (Posts)
|
---- Update Panel (for refreshing childeren from JavaScript)
    |
    ---- Repeater (Comments)

ASP Code

<asp:Repeater ID="rptActivityStream" runat="server" OnItemDataBound="rptActivityStream_ItemDataBound">
  <HeaderTemplate></HeaderTemplate>
  <ItemTemplate>
    <asp:HiddenField ID="hfActivityStreamID" value='<%#Eval("ActivityStreamID") %>' runat="server" />
      <table style="width:100%;">
        <tr>
          <td style="width:100%;">
             <div class="card">
               <div class="cardheader">
                 <table style="width:100%;">
                   <tr>
                     <td style="width:80%; text-align:left;">
                        <div style="display:inline-block">
                          <img src='<%#Eval("Avatar") %>' class="listmenuavatar" /> 
                          <%#Eval("FullName") %>
                        </div>
                        <div style="display:inline-block">
                          <%#Eval("ActivityStreamTitleHTML") %>
                        </div>
                      </td>
                      <td style="width:20%; text-align:right;">
                        <div style="display:inline-block">
                          <%#Eval("TimeAgo") %>
                        </div>
                      </td>
                    </tr>
                  </table>
                </div>
                <div class="cardbody">
                  <%#Eval("ActivityStreamContentHTML") %>
                </div>
                <div id="cardfooter" class="cardfooter">
                  <asp:UpdatePanel ID="UpdPnlComments" runat="server"  UpdateMode="Conditional" OnLoad="UpdPnlComments_Load">
                    <ContentTemplate>
                      <asp:Repeater ID="rptSocialData" runat="server">
                        <HeaderTemplate></HeaderTemplate>
                        <ItemTemplate>
                          <button id="btnLike" type="button" class="btn btn-default btn-sm">
                            <input id="hdnASID" type="hidden" runat="server" value='<%#Eval("ActivityStreamID") %>'/>
                            <span class="glyphicon glyphicon-thumbs-up"></span> Like
                          </button>
                          <button id="btnComment" type="button" class="btn btn-default btn-sm">
                            <input id="hdnASID2" type="hidden" runat="server" value='<%#Eval("ActivityStreamID") %>'/>
                            <span class="glyphicon glyphicon-comment"></span> Comment
                          </button>
                          <%#Eval("LikeCount") %>
                          <%#Eval("CommentCount") %>
                        </ItemTemplate>
                        <FooterTemplate></FooterTemplate>
                      </asp:Repeater>
                      <div class="commentsDiv" style="display:none; margin-top:10px;">
                        <div style="display:inline-block; vertical-align: top;">
                          <img src='<%#Eval("Avatar") %>' class="listmenuavatar" />
                        </div>
                        <div class="commentBoxDiv form-group has-feedback" style="display:inline-block; padding-left: 10px; padding-right: 10px; width:30%;">
                          <asp:TextBox ID="txtComment" CssClass="commentBox form-control" runat="server" TextMode="MultiLine" Font-Size="8pt"></asp:TextBox>
                        </div>
                        <div style="display:inline-block; vertical-align: top;">
                          <button id="btnSendComment" type="button" class="post-Comment btn btn-primary btn-sm" data-id='<%#Eval("ActivityStreamID") %>'>
                            <span class="glyphicon glyphicon-comment"></span> Send
                          </button>
                        </div>
                        <div style="display:block; padding-top:20px;">
                          <asp:Repeater ID="rptComments" runat="server">
                            <HeaderTemplate></HeaderTemplate>
                            <ItemTemplate>
                              <table style="width:100%; padding-left:5px; padding-right:5px;">
                                <tr>
                                  <td style="width:50%; text-align:left; vertical-align:top; padding-left:10px; padding-top: 15px;">
                                    <div style="text-align:center; display:table;">
                                      <div style="float:left;">
                                        <asp:Image ID="Image1" runat="server" CssClass="commentavatar" ImageUrl='<%#Eval("AuthorAvatar") %>'/>
                                      </div>
                                      <div style="vertical-align: middle; padding-left: 10px; display: table-cell;">
                                        <%#Eval("Author") %>
                                      </div>
                                    </div>
                                  </td>
                                  <td style="width:50%; text-align:right; vertical-align:middle;  padding-right:10px;">
                                    <%#Eval("TimeAgo") %>
                                  </td>
                                </tr>
                                <tr>
                                  <td style="width:100%; text-align:left;" colspan="2">&nbsp;
                                  </td>
                                </tr>
                                <tr>
                                  <td style="width:100%; text-align:left; padding-left:10px;padding-right:10px;" colspan="2">
                                    <div style="border-bottom: solid; border-width: 1px; border-color: #dddddd; padding-bottom: 15px;">
                                      <%#Eval("Comment") %>
                                    </div>
                                  </td>
                                </tr>
                              </table>
                            </ItemTemplate>
                            <FooterTemplate></FooterTemplate>
                          </asp:Repeater>
                        </div>
                      </div>
                    </ContentTemplate>
                  </asp:UpdatePanel>
                </div>
              </div>
            </td>
          </tr>
        </table>
      </ItemTemplate>
      <FooterTemplate></FooterTemplate>
    </asp:Repeater>

JavaScript

$(document).ready(
  function ()
    {
      $('[id*=btnLike]').click(function (event) {
        debugger;
        event.preventDefault(); //preventing button's default behavior
    
        var ActivityStreamID = $(this).find("input[type=hidden]").val();
        var UserID = document.getElementById('<%= hfUserID.ClientID %>').value;
    
        var element = $(this).parent().parent().parent();
    
        var result = PageMethods.LikeActivityStream(ActivityStreamID, UserID, onPostLikeSuccess, onPostLikeFailure);
        UpdateUpdPanel(element);
      });
    
      $('[id*=btnComment]').click(function (event) {
        debugger;
        event.preventDefault(); //preventing button's default behavior
        var ASID2 = $(this).find("input[type=hidden]").val();
    
        var element = $(this).parent().parent().parent();   //get the update panel
        var commentdiv = element.find(".commentsDiv");      // find commentsDiv in the update panel
        commentdiv.css("display", "block");                 // set the text to red as a test.
      });
    
      function UpdateUpdPanel(element) {
        __doPostBack(element, '');
      }
    
      function onPostLikeSuccess(result) {
        //refresh repeater / update panel ?
      }
    
      function onPostLikeFailure(result) {
        likeerror();
      }
    
      function likeerror() {
        swal({
          title: 'Uh-Oh!',
          text: 'Something went wrong while liking this post! Please try again and if the problem persists, please contact the system administrator.',
          type: 'error'
        });
      }
    });

    $(document).on("click", ".post-Comment", function () {
        
      var ActivityStreamID = $(this).data('id');
      var UserID = document.getElementById('<%= hfUserID.ClientID %>').value;
    
      var element = $(this).parent().parent();
      var element2 = $(this).parent().parent().parent();
      var commentboxdiv = element.find(".commentBoxDiv");
      var commentbox = commentboxdiv.find(".commentBox");
      var comment = commentbox.val();
    
      if (comment != "") {
        commentboxdiv.removeClass('has-error');
        var result = PageMethods.CreateActivityStreamComment(ActivityStreamID, comment, UserID, onPostCommentSuccess, onPostCommentFailure, element2);
      }
      else {
        commentboxdiv.addClass('has-error');
      }
    
      function onPostCommentSuccess(result, context) {
        //refresh repeater / update panel?
        debugger;
        var element = context;
        UpdateUpdPanel(element);
      }
    
      function UpdateUpdPanel(element) {
        debugger;
        __doPostBack(element, '');    
      }
    
      function onPostCommentFailure(result) {
        commenterror();
      }
    
      function commenterror() {
        swal({
          title: 'Whaaaa?!',
          text: 'Something went wrong while posting your comment! Please try again and if the problem persists, please contact the system administrator.',
          type: 'error'
        });
      }
    });

C# code (refreshing comments repeater in update panel)

protected void UpdPnlComments_Load(object sender, EventArgs e)
{
  // Missing code here to create an instance of the rptSocialData and rptComments repeaters
  // so that they can be data bound
  // hfActivityStream will also have to be accessed

  DatabaseHelper dh = new DatabaseHelper();

  DataTable dtSocialData = new DataTable();
  dtSocialData = dh.GetActivityStreamSocialData(hfActivityStreamID.Value);
  rptSocialData.DataSource = dtSocialData;
  rptSocialData.DataBind();

  DataTable dtComments = new DataTable();
  dtComments = dh.GetActivityStreamComments_All(hfActivityStreamID.Value);
  rptComments.DataSource = dtComments;
  rptComments.DataBind();
}

Example of how I achieve this in the OnDataBound method completely server side

protected void rptActivityStream_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
    {
        Repeater rptSocialData = (Repeater)e.Item.FindControl("rptSocialData");
        Repeater rptComments = (Repeater)e.Item.FindControl("rptComments");

        HiddenField hfActivityStreamID = (HiddenField)e.Item.FindControl("hfActivityStreamID");

        DatabaseHelper dh = new DatabaseHelper();

        DataTable dtSocialData = new DataTable();
        dtSocialData = dh.GetActivityStreamSocialData(hfActivityStreamID.Value);
        rptSocialData.DataSource = dtSocialData;
        rptSocialData.DataBind();

        DataTable dtComments = new DataTable();
        dtComments = dh.GetActivityStreamComments_All(hfActivityStreamID.Value);
        rptComments.DataSource = dtComments;
        rptComments.DataBind();
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Joachim Prinsloo
  • 618
  • 3
  • 12
  • 31
  • I don'r really get it...And there is a bit much code here.. Can't you use `ActivityStreamID`? You place that in a hidden field already. – VDWWD Feb 26 '18 at 09:56
  • @VDWWD The comments repeater and socialData repeater both use the Activity streamID to fetch relevant data from the sql server database. that result is then databound to each of the repeaters. The problem is that when using JavaScript, I have to somehow get an instance of the repeater so that I can databind it and cause a refresh. This is what I don't know how to achieve. I have added an Example of how I do this in the OnItemDataBount of the top level repeater. – Joachim Prinsloo Feb 26 '18 at 10:56

1 Answers1

0

Not sure if this is what you are looking for, but if you want to make every item in a Repeater unqiue, you can use the ClientID together with the ItemIndex.

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <div id="<%# Repeater1.ClientID + "_" + Container.ItemIndex %>">Content</div>
    </ItemTemplate>
</asp:Repeater>

Or

<div id="<%= Repeater1.ClientID %>" class="repeaterContainer">
    <asp:Repeater ID="Repeater1" runat="server">
        <ItemTemplate>
            <div id="item_<%# Container.ItemIndex %>">Content</div>
        </ItemTemplate>
    </asp:Repeater>
</div>

With the last one you could bind a jQuery event to the class repeaterContainer and get the item_xx with that.

UPDATE

If you want to know in which repeater the triggered button is located, you can do 2 things. Use a normal button and navigate to the parent, or use the ItemCommand. The first repeater uses a normal button click while the second uses the ItemCommand.

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button1_Click" />
    </ItemTemplate>
</asp:Repeater>

<asp:Repeater ID="Repeater2" runat="server" OnItemCommand="Repeater2_ItemCommand">
    <ItemTemplate>
        <asp:Button ID="Button2" runat="server" Text="Button" />
    </ItemTemplate>
</asp:Repeater>

Then in code behind you can cast the sender or source back to the correct type and get the ID

protected void Button1_Click(object sender, EventArgs e)
{
    Label1.Text = ((Button)sender).Parent.Parent.ID;
}

protected void Repeater2_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    Label1.Text = ((Repeater)source).ID;
}
VDWWD
  • 35,079
  • 22
  • 62
  • 79
  • Thanks for this, I dont think it is quite it. lets say I have an html button inside of this repeater with a JavaScript method like onclick="RefreshRepeater1();" RefreshRepeater1() would execute a PageMethod, how do I identify the repeater or repeater item serverside? basically refreshing a repeater from JavaScript. – Joachim Prinsloo Feb 26 '18 at 12:40
  • 1
    Updated my answer. And with jQuery you can trigger one of those buttons and you then have the correct repeater (LinkButtons will also work) – VDWWD Feb 26 '18 at 13:17
  • Item command might be an option. would this not trigger a postback and refresh the entire page? – Joachim Prinsloo Feb 26 '18 at 13:20
  • Yes, but that would be the case in any event. Clicking a (link)button will always trigger a PostBack. But you do have UpdatePanels so you won't see a page refresh. Having an UpdatePanel does not mean there is no PostBack. – VDWWD Feb 26 '18 at 13:22