Search code examples
ajaxjsfjsf-2jsf-2.2codemirror

<f:ajax render="@all" /> does not work in production evnironment


In a jsf 2.2 application I have a form that has this tag

<h:inputTextarea id="code_editor_demo_1" value="#{testBean.question.code}" />

I use the id "code_editor_demo_1" so that a javascript plugin called CodeMirror format the textarea to this:

enter image description here

Now There is a button called “next” for navigation

<h:commandButton id="nextBtn" styleClass="btn default col-sm-offset-1" value="Next" action="#{testBean.nextQuestion}" >
    <f:ajax render="@all" />
</h:commandButton>

The method nextQuestion() does some processing and has a return type of void. Now on my local environment when I click next, the page is re-rendered to show new values + The plugin Codemirror is Re-Applied to the textarea.

On the production environment however (Application hosted on Cloud Paas, DB on AWS), the method get invoked BUT the UI is NOT updated, the ajax call to re-render @all does not happen.

I have tried:

Replacing @all with two specific id of <div jsf:id>.. it works, the new values are shown correctly EXCEPT that the codemirror plugin does not format the <h:inputTextarea id="code_editor_demo_1" value="#{testBean.question.code}" /> to be displayed like in the picture above. That’s Why I have to use @all, because it’s the only value that re-apply the plugin on the textarea.

Note: the plugin works by specifying the id to “code_editor_demo_1”

Why is that? And how Can I fix this? Thanks.

UPDATE

As the user @Kukeltje suggested, I did found the Javascript method that re-apply the codemirror plugin on the textarea.

<h:commandButton id="nextBtn" styleClass="btn default col-sm-offset-1" value="Next" action="#{testBean.nextQuestion}" >    
    <f:ajax render="pass-section ads-section" onevent="handleDemo1"/>    
</h:commandButton>

JS handledemo

var ComponentsCodeEditors = function () {

var handleDemo1 = function () {
    var myTextArea = document.getElementById('code_editor_demo_1');
    var myCodeMirror = CodeMirror.fromTextArea(myTextArea, {
        lineNumbers: true,
        matchBrackets: true,
        styleActiveLine: true,
        theme:"ambiance",
        mode: 'javascript'
    });
}


return {
    //main function to initiate the module
    init: function () {
        handleDemo1();
    }
};
}();

jQuery(document).ready(function() {    
   ComponentsCodeEditors.init(); 
});

However, the page that have this code is called test.xhtml and it always have a paramaeter called id . for example test.xhtml?id=5 .

The problem I’m encountering now is that After I click the next Btn (that execute the ajax part). The id parameter part of the url get removed, so instead of test.xhtml?id=5 the url change to test.xhtml .

Any Idea how Can I fix this? Thanks.


Solution

  • I have fixed the problem with the help of this answer https://stackoverflow.com/a/41794426/4255756 by Muzafar Ali. Here is How I solve it Created a new Javascript file with this content

    function qsa(sel) {
        return Array.apply(null, document.querySelectorAll(sel));
    }
    function apply_code_mirror() {
        qsa(".code-mirror").forEach(function(editorEl) {
            CodeMirror.fromTextArea(editorEl, {
                lineNumbers : true,
                matchBrackets : true,
                styleActiveLine : true,
                theme : "ambiance",
                mode : 'javascript'
            });
        });
    }
    

    Added the file as a resource + a call to the js method.

    <h:outputScript library="custom" name="codemirror/apply-as-class.js" />
    <script type="text/javascript">
        apply_code_mirror();
    </script>
    

    The textarea becomes

    <h:inputTextarea styleClass="code-mirror" value="#{display.question.code}" />
    

    And When I want to re-apply codemirror on a textarea because of an ajax update I use

    <h:commandButton id="nextBtn" styleClass="btn default col-md-offset-1" value="Next" action="#{testBean.nextQuestion}" >
        <f:ajax render="pass-section ads-section" onevent="apply_code_mirror"/>
    </h:commandButton>