Update SalesForce rich text area in a VisualForce page

I've just come across this post by Matt Lacey, a day too late as I discovered this yesterday!

Basically the issue is that Salesforce has rich text fields which are not in the least bit easy to re-render. A colleague had a requirement to change the text within the rich text area depending upon the user changing a select value, the base starting points for the rich text area were contained within hidden fields on the form but he needed to update the rich text area upon the select being changed without Salesforce complaining too much.

I inspected the elephant and clocked that the ids he had given to various apex components were coming through properly but that they were mixed up in some sort of colon-and-alphabet soup. That's where I got to thinking about jQuerys selectors and had a wee brain wave... the missing piece then was looking at the CKEDITOR object and its setData method and we were in business.

Given this structure on the visualforce page:

<apex:pageBlockSection rendered="{!NOT(draftMode)}">
  <apex:selectList 
    label="Request Description source:"
    value="{!descriptionSelected}" 
    multiselect="false" 
    size="1"
    id="descOption">
    <apex:selectOptions 
      value="{!descriptionList}" />
  </apex:selectList>
</apex:pageBlockSection>

 ... 

<apex:pageBlockSection>
  <apex:inputField 
    label="Request" 
    value="{!pagePubRec.Published_Request__c}"
    id="requestText" />
</apex:pageBlockSection>

 ... 

<apex:inputHidden 
  id="customerDescription" 
  value="{!customerDescription}"
  />
<apex:inputHidden 
  id="caseDescription" 
  value="{!caseDescription}" />

We can use this javascript:

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
  $(function(){
    // Select the select that ends with the id of 'descOption'
    // and listen to it changing...
    $("[id$='descOption']").on("change", function(){
      // Probably not needed but better safe than sorry.
      var $this = $(this);
      // Get the full id if the textarea which contains 'requestText',
      // including all the salesforcie stuff, as that'll be the reference
      // we'll use to grab the correct CKEDITOR instance.
      var cke_editor_instance = $("textarea[id*='requestText']").attr("id");
      if ($this.val() === "Customer Request description"){
        // If the value of the select is "Customer Request description"
        // update the textarea which underlays the rich text editor with 
        // the data from our hidden field...
        $("textarea[id*='requestText']")
          .val($("[id$='customerDescription']").val());
        // ...and set the data for the CKEDITOR instance with the same value.
        CKEDITOR.instances[cke_editor_instance]
          .setData($("[id$='customerDescription']").val());
      }else{
        // We've only got 2 so no need to use a switch or 
        // something else more fun.
        $("textarea[id*='requestText']")
          .val($("[id$='caseDescription']").val());
        CKEDITOR.instances[cke_editor_instance]
          .setData($("[id$='caseDescription']").val());
      }
    });
  });
</script>

Yon Matt Lacey is right though, this is something of a hack... it's not a terrible hack... but it is a hack! There's no guarantee that this approach will continue to work, but I'll keep my fingers crossed while I look around for other alternatives.