I am having issues getting a commandLink to call a javaScript function (javaScript remoting that calls an apex function) and then reRender an outputPanel in VisualForce. The JS function gets called, the apex function completes, but the outputPanel does not reRender.
The scenario is that I have created a VisualForce page to display a Chatter Group Feed. I have extended my controller to do the JS remoting. In the same page, I use a commandButton to post a new comment via JS remoting which works fine and reRenders the outputPanel. I have created the "Like" and "UnLike" links using commandLinks that call JS functions that perform the JS remoting and set the reRender attribute to the id of the outputPanel I would like to reRender after the JS remoting call has completed. The "Like" is added or removed, but the panel does not reRender to show the change.
Any help is appreciated. Here is the code for the VF page and the controller extension:
<apex:page controller="CanNewsChatterFeedController" extensions="CanNewsChatterFeedExtension" id="feedcontroller" sidebar="false" showHeader="false" standardStylesheets="false" >
<script type="text/javascript">
var j$ = jQuery.noConflict();
function likeFeedItem(itemId){
CanNewsChatterFeedExtension.addLikeToFeedItem(itemId, handleAddLike);
}
function handleAddLike(result, event){
return null;
}
function unLikeFeedItem(likeId){
CanNewsChatterFeedExtension.removeLikeFromFeedItem(likeId, handleUnLike);
}
function handleUnLike(result, event){
return null;
}
function showCommentBox(itemId){
j$('#comBox_'+itemId).show();
}
function clearCommentToAdd(itemId){
j$('#comIn_'+itemId).val('');
}
function addComment(itemId){
var commentToAdd = j$('#comIn_'+itemId).val();
CanNewsChatterFeedExtension.addComment(commentToAdd, itemId, handleAddComment);
}
function handleAddComment(result, event){
return null;
}
</script>
<style type="text/css">
....
</style>
<div id="feed-display-div">
<apex:form >
<apex:actionPoller action="{!refreshFeed}" rerender="feedRows" interval="60" />
<apex:outputPanel id="feedRows" >
<apex:repeat value="{!newsFeedForDisplay}" var="feedItemInfo" rows="10" rendered="{!NOT(ISNULL(newsFeedForDisplay))}">
<div class="row">
<div>
<div style="display:inline-block;vertical-align:top;">
<a href="/{!feedItemInfo.userId}">
<apex:image style="margin:4px" width="40" url="{!feedItemInfo.feedItem.photoUrl}"/>
</a>
</div>
<div style="display:inline-block;vertical-align:top;width:220px; color:#087bf5;">
<a href="/{!feedItemInfo.userId}">
<b>{!feedItemInfo.userName}</b>
</a><br/>
<apex:outputText style="color:#000000;" value="{!feedItemInfo.formattedText}" />
<apex:outputPanel layout="block" rendered="{!IF(feedItemInfo.linkUrl == null, false, true)}" >
<a href="{!feedItemInfo.linkUrl}">
<b>{!feedItemInfo.linkTitle}</b>
</a>
</apex:outputPanel>
<apex:outputPanel >
<div class="comLikeDiv">
<a href="#" onclick="showCommentBox('{!feedItemInfo.feedItemId}')">Comment</a><span class="separatorDot">.</span>
<apex:outputPanel rendered="{!IF(feedItemInfo.isLikedByUser == true, false, true)}">
<apex:commandLink onclick="likeFeedItem('{!feedItemInfo.feedItemId}')" value="Like" reRender="feedRows" /><span class="separatorDot">.</span>
</apex:outputPanel>
<apex:outputPanel rendered="{!IF(feedItemInfo.isLikedByUser == false, false, true)}">
<apex:commandLink onclick="unLikeFeedItem('{!feedItemInfo.myLikeId}')" value="UnLike" reRender="feedRows" /><span class="separatorDot">.</span>
</apex:outputPanel>
<apex:outputText styleClass="createdDate" value="{!feedItemInfo.relativeCreatedDate}" />
</div>
</apex:outputPanel>
</div>
<apex:outputPanel layout="block" rendered="{!IF(feedItemInfo.contentDownloadUrl != null && feedItemInfo.imageUrl != null && feedItemInfo.hasImagePreview, true, false)}" >
<div style="left: 3em; width: 85%; padding: 2px; position: relative;">
<apex:image style="margin:4px" width="60" url="{!feedItemInfo.imageUrl}"/>
<div style="float:right;position:relative;padding:2px;width:65%;">
<a href="{!feedItemInfo.contentDownLoadUrl}">Download:<br />{!feedItemInfo.contentTitle }</a>
</div>
</div>
</apex:outputPanel>
</div>
<apex:outputPanel rendered="{!IF(feedItemInfo.likesMessage != '', true, false)}">
<div class="likeBox">
<div style="margin-left:4px;width:95%;">
<div style="display:inline-block;vertical-align:top;">
<apex:image value="{!$Resource.LikeThumb}" />
</div>
<div style="display:inline-block;width:80%;padding-top:2px;">
<apex:outputText style="margin-left:4px;" value="{!feedItemInfo.likesMessage}" />
</div>
</div>
</div>
</apex:outputPanel>
<apex:outputPanel rendered="{!IF(feedItemInfo.commentCount > 0, true, false)}">
<div class="commentBox">
<apex:repeat value="{!feedItemInfo.comments}" var="commentInfo">
<div class="commentBox-inner">
<div style="display:inline-block;vertical-align:top;">
<apex:image style="margin:4px" width="25" url="{!commentInfo.comment.user.photo.smallPhotoUrl}"/>
</div>
<div style="display:inline-block;vertical-align:top;width:80%">
<a href="/{!commentInfo.userId}">
<b>{!commentInfo.userName}</b>
</a>:
<apex:outputText value="{!commentInfo.formattedText}" />
<div class="createdDate">
<apex:outputText value="{!commentInfo.relativeCreatedDate}" />
</div>
</div>
<apex:outputPanel rendered="{!IF(commentInfo.imageUrl == null, false, true)}" >
<div style="padding-left:4px;display:inline-block;vertical-align:top;float:left;position:relative;width:95%" >
<apex:image style="padding:4px" width="60" url="{!commentInfo.imageUrl}"/>
<div style="float:right;position:relative;padding:2px;width:65%;">
<a href="{!commentInfo.contentDownLoadUrl}">Download:<br />{!commentInfo.contentTitle }</a>
</div>
</div>
<div style="clear: both;" />
</apex:outputPanel>
</div>
</apex:repeat>
</div>
</apex:outputPanel>
<div class="addComment" id="comBox_{!feedItemInfo.feedItemId}">
<input type="text" id="comIn_{!feedItemInfo.feedItemId}" style="border:1px solid #AAAAAA;" value="Add a comment..." onfocus="clearCommentToAdd('{!feedItemInfo.feedItemId}')" />
<apex:commandButton onclick="addComment('{!feedItemInfo.feedItemId}')" value="Comment" reRender="feedRows" />
</div>
</div>
</apex:repeat>
</apex:outputPanel>
</apex:form>
</div>
public class CanNewsChatterFeedExtension {
// Constructor. Needed to use as an extension.
public CanNewsChatterFeedExtension(CanNewsChatterFeedController custController) {}
// Remote Action function lets JavaScript call Apex directly
// method to add the comment passed in from a Visualforce page JavaScript function to the feedItem that was passed in
@RemoteAction
public static Boolean addComment(String theComment, String theFeedItemId){
try{
FeedComment fcomment = new FeedComment();
fcomment.FeedItemId = theFeedItemId;
fcomment.CommentBody = theComment; //String.escapeSingleQuotes(theComment); <--prevents SOQL injection. Necessary?
insert fcomment;
return true;
}catch(Exception e){
System.debug(e.getMessage());
return false;
}
}
@RemoteAction
public static Boolean addLikeToFeedItem(String theFeedItemId){
try{
ConnectApi.ChatterFeeds.likeFeedItem(null, theFeedItemId);
return true;
}catch(Exception e){
System.debug(e.getMessage());
return false;
}
}
@RemoteAction
public static Boolean removeLikeFromFeedItem(String theLikeId){
try{
ConnectApi.ChatterFeeds.deleteLike(null, theLikeId);
return true;
}catch(Exception e){
System.debug(e.getMessage());
return false;
}
}
}
First Result: I got this to work with apex:commandLink by removing the rerender attribute. However, now, after returning from the remote action, the page refreshes and it's a little jumpy. Without an action attribute in the commandLink, I believe it's just refreshing the page not rerendering and that's why it's jumping.
Here's what I changed:
<apex:outputPanel rendered="{!IF(feedItemInfo.isLikedByUser == true, false, true)}">
<apex:commandLink onclick="likeFeedItem('{!feedItemInfo.feedItemId}')" value="Like" />
</apex:outputPanel>
<apex:outputPanel rendered="{!IF(feedItemInfo.isLikedByUser == false, false, true)}">
<apex:commandLink onclick="unLikeFeedItem('{!feedItemInfo.myLikeId}')" value="Unlike" />
</apex:outputPanel>
The last commandButton (used for adding comments and unchanged) works perfectly and reRenders the "feedRows" the way it should. I tried using re-styled commandButtons (the same way) to perform the "Like" actions, but they would not rerender the "feedRows". As I said, the changes I made to the commandLinks above work, but this is NOT the optimal solution. While the "Like" or "Unlike" is added or removed from the feedItem, the "feedRows" do not reRender. Due to the fact that there is no "action" attribute in the commandLinks, the page simply refreshes which is jumpy/choppy and not the optimal solution.
Any other ideas?