Search code examples
javascriptxpathxformsxsltforms

XForms Refresh not working? (XSLTForms 1.7)


I need to alter XForms instance data from inside Javascript. The actual modification to the XML seems to work - but the UI doesn't update - despite me explicitly refreshing XForms - I tried both the 'xf:refresh' element and the manual JS to do this - neither result in the UI being updated - this is in despite that fact that I can see changes have taken place on the model.

<?xml
    version="1.0"
    encoding="UTF-8"?>
<?xml-stylesheet
    href="xsltforms-1.7/xsltforms.xsl"
    type="text/xsl"?>
<?xsltforms-options
    debug="no"?>
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:ht="http://www.w3.org/1999/xhtml"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xf="http://www.w3.org/2002/xforms"   
      xmlns:ev="http://www.w3.org/2001/xml-events"
      lang="en">
<head>
    <script type="text/javascript">
        <![CDATA[
            function js_xforms() {
                console.log("js_xforms called");
                var xmodel=document.querySelector('#model');
                var person=xmodel.getInstanceDocument();
                var fname=person.querySelector('fname');
                console.log(fname.textContent);

                fname.textContent='Fred';
                fname.setAttribute("js", "value");
                
                xmodel.rebuild();
                xmodel.recalculate();
                xmodel.revalidate();
                xmodel.refresh();   
            }
        ]]>
    </script>
    <xf:model id="model">
        <xf:instance id="person">
            <person xmlns="">
                <fname js="initial">Joe</fname>
                <lname>Bloggs</lname>
                <tel>1234-5678</tel>
            </person>
        </xf:instance>
    </xf:model>
</head>
<body>
    <xf:input ref="fname"/>
    <xf:input ref="lname"/>
    <xf:input ref="tel"/>

    <xf:trigger>
        <xf:label>JS</xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:load resource="javascript:js_xforms()"/>
            <xf:refresh model="model"/>
        </xf:action>
    </xf:trigger>
</body>
</html>

Neither the 'xf:refresh' nor the explicit JS call 'xmodel.refresh()' (etc) appear to work? What am I doing wrong here?

I am 99% sure this is just an issue with the UI not refreshing - since if I click the 'JS' button twice (or use fleur("instance('person')") from the console) - I can see the modification to the Xf:model has happened.

Same result on both Chromium and Firefox.


Solution

  • It seems that XSLTForms has not implemented the refresh method, see here.

    You can achieve the desired UI update if you follow the Javascript call with a (seemingly vacuous) setvalue statement:

    <xf:load resource="javascript:js_xforms()" />
    <xf:setvalue ref="instance()/fname" value="." />
    

    But this approach has the limitation that a setvalue is needed for every value that the Javascript code may change, so another

    <xf:setvalue ref="instance()/fname/@js" value="." />
    

    is needed.

    <xf:setvalue ref="instance()//*|instance()//@*" value="." />
    

    works as well in XSLTForms, although it is against the XForms 1.1 specification, which says that setvalue has a single node binding only.

    (Side remark: You can omit the

    xmodel.recalculate();
    xmodel.revalidate();
    xmodel.refresh();
    

    because they are already triggered by the xmodel.rebuild();.)