J'ai un formulaire XPage à onglets assez long à remplir par les visiteurs, et j'aimerais enregistrer automatiquement dans le backend toutes les quelques minutes.

Le formulaire entier représente un bean géré, et je peux remplir / enregistrer un document Domino à partir des valeurs du bean à l'aide d'un bouton manuellement simplement en appelant ...

portfolio.save(sessionScope.unid,false)

J'ai trouvé cet excellent article de Jeremy Hodge (excellent à quel point les conseils plus anciens résistent à l'épreuve du temps!) Qui explique la technique ...

http://xpages.info/XPagesHome.nsf/Entry.xsp?documentId=88065536729EA065852578CB0066ADEC

J'ai ensuite trouvé une réponse au forum de Paul Calhoun qui décrit l'utilisation de la technique avec une minuterie pour déclencher des sauvegardes de documents régulières ...

https://www-10.lotus.com/ldd/xpagesforum.nsf/xpTopicThread.xsp?documentId=B5ECAEC50241A3EE85257B32008248FC

J'ai implémenté la technique sur ma XPage, mais le SSJS ne fonctionne tout simplement pas. J'ai même placé des événements «onStart» et «onComplete» pour valider que tout fonctionne comme prévu. Le compteur fonctionne, la console affiche la minuterie et les alertes apparaissent toutes les 5 secondes environ ... mais le SSJS n'est tout simplement pas lancé.

Mon gestionnaire d'événements qui fait le travail ...

<xp:eventHandler event="onfubar" id="autoSave" submit="false">
    <xp:this.action><![CDATA[#{javascript:portfolio.save(sessionScope.unid,false);}]]>
    </xp:this.action>
</xp:eventHandler>

... et le gestionnaire d'événements qui déclenche la sauvegarde régulière (oui, je sais que j'ai massacré la commande 'executeOnServer' et ajouté manuellement les paramètres supplémentaires - juste pour essayer d'isoler le problème) ...

    <xp:eventHandler event="onClientLoad" submit="false">
        <xp:this.script><![CDATA[
var executeOnServer = function () {
    // must supply event handler id or we're outta here....
    if (!arguments[0])
        return false;

    // the ID of the event handler we want to execute
    var functionName = arguments[0];

    // OPTIONAL - The Client Side ID that you want to partial refresh after executing the event handler
    var refreshId = (arguments[1]) ? arguments[1] : "@none";
    var form = (arguments[1]) ? XSP.findForm(arguments[1]) : dojo.query('form')[0];

    // OPTIONAL - Options object contianing onStart, onComplete and onError functions for the call to the 
    // handler and subsequent partial refresh
    var options = (arguments[2]) ? arguments[2] : {};

    // Set the ID in $$xspsubmitid of the event handler to execute
    dojo.query('[name="$$xspsubmitid"]')[0].value = form.id + ':' + functionName;
    XSP._partialRefresh("post", form, refreshId, options);
}

var x = 0;
var form = document.forms[0];

t = new dojox.timing.Timer(3600);
t.onTick = function() {
    x+=1;
    console.info(x);
    if(x > 4){
        x = 0;
        console.info("reset");
        executeOnServer('autoSave','@none',{
            onStart: function() { alert('starting!'); },
            onComplete: function() { alert('complete!'); },
            onError: function() { alert('DANGER WILL ROBINSON!'); }
        });
    }
}

t.onStart = function() {
 console.info("Starting timer");
}

t.start();]]></xp:this.script>
    </xp:eventHandler>

Je sais que je dois manquer quelque chose, et je le regarde probablement directement, mais je ne peux tout simplement pas comprendre où je me suis trompé.

Merci beaucoup pour tout aperçu du problème (et un point dans la bonne direction!).

0
Terry Boyd 23 mai 2018 à 16:33

3 réponses

Meilleure réponse

Cela peut en fait être beaucoup plus simple que les extraits que vous avez trouvés (vous pouvez supprimer tout cela) ... Considérez le bean suivant:

public class PortfolioBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private Map<String, Object> data = new HashMap<String, Object>();

    public Map<String, Object> getData() {
        return data;
    }

    public void autoSave(String unid, Boolean something) {
        System.out.println("The unid is " + unid + " and something is " + something);

        data.put("stamp", "autosave at " + new Date());
    }

}

Et la source xsp suivante:

<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:div id="myForm" style="padding: 20px;">
        <xp:eventHandler event="onautosave" id="eventAutoSave"
            submit="false" action="#{javascript:portfolio.autoSave(sessionScope.unid, false)}" />

        <p>Stamp</p>

        <xp:inputText id="inputStamp" value="#{portfolio.data.stamp}" size="60" />
    </xp:div>

    <xp:scriptBlock value="
        XSP.addOnLoad(function() {
            window.setInterval(function() {
                XSP.partialRefreshPost('#{id:inputStamp}', {
                    execId: '#{id:myForm}',
                    params: { '$$xspsubmitid' : '#{id:eventAutoSave}' },
                    onComplete: function() { console.log('complete at ' + new Date()); }
                });
            }, 5000);
        });" />

</xp:view>

J'ai créé un conteneur myForm pour créer une "ancre" et affiner la partie de la page qui est évaluée, lue soumise ou exécutée (meilleure pratique en vue des meilleures performances). myForm est donc l'id d'exécution. Il est fondamental que l'ID d'exécution appartient à un élément qui contient le gestionnaire d'événements que vous souhaitez déclencher . Si, par exemple, je plaçais l'événement onautosave en dehors de la division myForm, l'événement ne serait pas déclenché. Si vous ne vous en souciez pas (mauvais!), Vous pouvez supprimer la propriété execId: '#{id:myForm}' passée à l'objet dans l'appel de méthode XSP.partialRefreshPost et, à ce stade, cela fonctionnerait indépendamment de l'arrangement des composants xsp.

De plus, avec XSP.partialRefreshPost, vous pouvez décider si vous souhaitez actualiser partiellement un élément de la page ou non. J'ai mis #{id:inputStamp} pour que vous puissiez voir le champ de saisie se remplir avec le texte résultant du déclenchement de la sauvegarde automatique. Si vous savez que vous n'avez pas à afficher de modification DOM qui résulterait de l'évaluation de la méthode côté serveur, vous pouvez spécifier une chaîne vide (comme celle-ci XSP.partialRefreshPost('',) et cela signifierait norefresh sur le côté client. Mais vous pouvez toujours faire quelque chose à la fin de l'opération en utilisant la propriété onComplete comme vous pouvez le voir dans l'exemple.

Dans la propriété params se trouve un objet supplémentaire avec une propriété qui définit l'id de l'action que vous souhaitez déclencher: { '$$xspsubmitid' : '#{id:eventAutoSave}' }.

En conclusion, toutes les 5 secondes, le code ci-dessus:

  1. imprimer sur la console Domino du texte pour vous montrer que l'événement a été évalué côté serveur
  2. remplir le champ avec un cachet et la date de l'exécution
  3. imprimer sur la console du navigateur au moment de l'exécution de la méthode

Aucune dépendance ou extrait supplémentaire. Cela fonctionne comme ça hors de la boîte.

4
shillem 24 mai 2018 à 18:11

Assurez-vous de référencer l'ID correct. Voici un exemple de travail simple (sans la fonction executeOnServer et votre logique de temporisation). Le code s'exécute lorsque le chargement de la page est terminé:

<xp:scriptBlock id="scriptBlockAutoSave">
    <xp:this.value><![CDATA[
        XSP.addOnLoad(function(){
            executeOnServer('#{javascript:getComponent('autoSave').getClientId(facesContext)}');
        });
    ]]></xp:this.value>
</xp:scriptBlock>
0
Per Henrik Lausten 24 mai 2018 à 08:56

Terry, juste un conseil, avez-vous regardé la console du navigateur pour voir si des erreurs sont levées (du code côté client)? La journalisation des erreurs est-elle activée pour voir si des erreurs sont générées dans votre code SSJS / Java?

0
Howard 23 mai 2018 à 14:29