So following on from my comment above, I'm hoping I have the answer you're after. It's not precisely the same as your situation, but the errors were exactly the same, and the issues involved were very similar.
The Problem
In my situation, we had an <apex:tabPanel>
on a custom Account page with different <apex:tab>
s corresponding to different bits of Account information.
In each of these, we were using <apex:composition>
to pull in different visualforce pages laying out this information.
In one of these pages pulled in using <apex:composition>
I was importing jQuery and a few other bits and bobs to get some enhanced table functionality. Now as the <apex:tabPanel>
tag had the attribute switchType="server"
set, I was surprised to find my static jQuery resource was being pulled into the page's source when I wasn't viewing the jQuery tab. This was of course combined with the fact that none of the tabs functioned correctly, and I was getting exactly the same error messages as you.
So long story short - it didn't matter which tab I was viewing, something about the <apex:tabPanel>
thought it would be clever and get all javascript imports from all tabs and make sure I could see them at all times.
The Solution
Of course, my first thought was "OK, easy fix, slap jQuery.noConflict()
into a <script>
tag inside the page where I import jQuery". No such luck. While using the <apex:tabPanel>
does pull any js imports from non-active tabs in, it doesn't pull any <script>
tags an.
So I chucked the same thing into the page containing the <apex:tabPanel>
instead (with a check that the jQuery var had been attached to the window). And bam: the errors were gone :)
So to bring it on home/TL;DR
On the page containing the <apex:tabPanel>
(not necessarily the page that actually imports jQuery, unless it can be accessed/is used in other contexts where there may be a conflict on the $ alias!) chuck the following in. This checks to see if jQuery has been loaded onto the page. If it has, it calls jQuery.noConflict(). The major side-effect of this, for those unfamiliar with noConflict, is that you now cannot use the $ alias for jQuery, and instead need to use the full jQuery namespace var.
<script type="text/javascript" language="javascript">
if(jQuery) {
jQuery.noConflict();
}
</script>
SOLUTION FOUND!!! The suggestion by Mohith Kumar to use actionFunction was the correct way to go. It just took a little research and better understanding of how actionFunction works to implement the solution. After some googling, I finally found a blog post (http://shivasoft.in/blog/salesforce/passing-parameter-in-actionfunction-in-visualforce/) that really helped me understand how to use actionFunction for my solution.
Here is the final code for the controller extension:
public with sharing class CanNewsChatterFeedExtension {
//declare class variables
public String feedItemId {get;set;}
public String likeId {get;set;}
public String commentToAdd {get;set;}
// Constructor. Needed to use as an extension.
public CanNewsChatterFeedExtension(CanNewsChatterFeedController custController) {}
//call via javascript and actionFunction. Class variables feedItemId and commentToAdd are set by passing params via actionFunction
public void addCommentToFeedItem(){
try{
FeedComment fcomment = new FeedComment();
fcomment.FeedItemId = feedItemId;
fcomment.CommentBody = commentToAdd; //String.escapeSingleQuotes(commentToAdd); <--prevents SOQL injection. Necessary?
insert fcomment;
}catch(Exception e){
System.debug(e.getMessage());
}
}
//call via javascript and actionFunction. Class variable feedItemId is set by passing params via actionFunction
public void addLikeToFeedItem(){
try{
ConnectApi.ChatterFeeds.likeFeedItem(null, this.feedItemId);
}catch(Exception e){
System.debug(e.getMessage());
}
}
//call via javascript and actionFunction. Class variable likeId is set by passing params via actionFunction
public void removeLikeFromFeedItem(){
try{
ConnectApi.ChatterFeeds.deleteLike(null, this.likeId);
}catch(Exception e){
System.debug(e.getMessage());
}
}
}
And the VF page final code:
<apex:page controller="CanNewsChatterFeedController" extensions="CanNewsChatterFeedExtension" id="feedcontroller" sidebar="false" showHeader="false" standardStylesheets="false" >
<script type="text/javascript">
var j$ = jQuery.noConflict();
/*called via JS onclick to pass in the itemId.
When addLike() is called it fires the actionFunction of the same name defined below,
which in turn passes the param to the apex class, sets the class variable and calls the defined apex method.
*/
function likeFeedItem(itemId){
addLike(itemId);
}
/*called via JS onclick to pass in the likeId.
When removeLike() is called it fires the actionFunction of the same name defined below,
which in turn passes the param to the apex class, sets the class variable and calls the defined apex method.
*/
function unLikeFeedItem(likeId){
removeLike(likeId);
}
//displays the commentBox for adding new comments
function showCommentBox(itemId){
j$('#comBox_'+itemId).show();
}
//clears the text in the commentBox onFocus
function clearCommentToAdd(itemId){
j$('#comIn_'+itemId).val('');
}
/*called via JS onclick to pass in the itemId.
When addComment() is called it fires the actionFunction of the same name defined below,
which in turn passes the params to the apex class, sets the class variables and calls the defined apex method.
*/
function addCommentToFeedItem(itemId){
var commentToAdd = j$('#comIn_'+itemId).val();
addComment(itemId, commentToAdd);
}
</script>
<style type="text/css">
.....
</style>
<div id="feed-display-div">
<apex:form >
<apex:pageMessages />
<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>
<div class="comLikeDiv">
<a href="#" onclick="showCommentBox('{!feedItemInfo.feedItemId}')">Comment</a><span class="separatorDot">.</span>
<apex:outputPanel rendered="{!IF(feedItemInfo.isLikedByUser == true, false, true)}">
<span class="likeSpan" onclick="likeFeedItem('{!feedItemInfo.feedItemId}')">Like</span>
</apex:outputPanel>
<apex:outputPanel rendered="{!IF(feedItemInfo.isLikedByUser == false, false, true)}">
<span class="likeSpan" onclick="unLikeFeedItem('{!feedItemInfo.myLikeId}')">Unlike</span>
</apex:outputPanel>
<span class="separatorDot">.</span>
<apex:outputText styleClass="createdDate" value="{!feedItemInfo.relativeCreatedDate}" />
</div>
</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="addCommentToFeedItem('{!feedItemInfo.feedItemId}')" value="Comment" rerender="feedRows" />
</div>
</div>
</apex:repeat>
<apex:actionFunction name="addLike" action="{!addLikeToFeedItem}" rerender="feedRows">
<apex:param name="theItemId" assignTo="{!feedItemId}" value="" />
</apex:actionFunction>
<apex:actionFunction name="removeLike" action="{!removeLikeFromFeedItem}" rerender="feedRows">
<apex:param name="theLikeId" assignTo="{!likeId}" value="" />
</apex:actionFunction>
<apex:actionFunction name="addComment" action="{!addCommentToFeedItem}" rerender="feedRows">
<apex:param name="theItemId" assignTo="{!feedItemId}" value="" />
<apex:param name="theComment" assignTo="{!commentToAdd}" value="" />
</apex:actionFunction>
</apex:outputPanel>
</apex:form>
</div>
Best Answer
Providing this script is not in the part of the page being re-rendered:
you can invoke the initialisation code after the Ajax request completes by using the
oncomplete
attribute like this: