Hi Thierry,
With FIC and in web mode, the message is ignored with wWait (...).
Would it be possible to integrate a bootstrap component such as "Alerts
" ?
Thanks in advance
Hi Vincent,
Due to the client-server mechanism, we can only display one message when starting the event, and hide it when server has completed the request and returned the response; IOW we can't show/hide message(s) during the course of an event like you used to do with WAIT
, just one message per event (like we do for the wait spinning icon)
We could maybe create a awFrm.wBSalertEvent()
method as a shortcut to .wcScriptEventClientServer()
to automatically display an alert in the browser and hide it when request is complete.
@everyone, any interest for such a feature?
That's exactly what I thought. More aesthetic with bootstrap ?
More aesthetic with bootstrap ?
Sure! No interest expressed by other devs however…
You may want to develop that in your xxxForm
Class… Bootstrap notify could be a good helper for that.
Let us know what you plan, we'll help you implement the feature.
Thank you, surely a bit too complex to implement for me ...
Challenging but a good way to learn web development!
I tried this code (in a label control) without success. The JQuery code seems to run but nothing happens. Wrong FIC programming or incorrect Bootstrap declaration ?
wcHTMLgen:
LPARAMETERS toHTMLgen AS awHTMLgen OF awHTML.prg, tlInnerHTML
IF THISFORM.wBSlHTMLgen
THIS.wcHTML = Textmerge([<div id="<<THIS.wcID>>" class="alert alert-info" role="alert"><<cEscaped(THIS.Caption)>></div>])
ENDIF
function called:
IF THISFORM.wBSlHTMLgen
RETURN TEXTMERGE ([jQuery('#<<THIS.wcID>>').alert();])
ENDIF
which event calls the function?
A click in another control
It's ok if I don't call my fonction but execute the code directly from a click method
I will try to integrate Notify.js
whose very professional look seems to me well in the vein of FIC ...
Hello Vincent,
Here is how you can proceed:
Add notify.js
to your pages
copy notify.js
to your web site root, then
modify command xxxServer
…
define class xxxProcess aw awProcess
…
PROTECTED FUNCTION cawJSinc && <script></script>+ {en} Scripts for FoxInCloud, application, form [, custom] {fr} Scripts de FoxInCloud, de l'application, du formulaire[, spécifiques]
LPARAMETERS ;
tcJSAdd; && [''] {en} Application, current form[, and custom] {fr} JS files URLs (UTF-8 encoded) {fr} URL des fichiers JS de l'application et du formulaire courant (encodés en UTF-8)
, toForm as awFrm of aw.vcx; && {en} Reference to form && {fr} Référence au formulaire
, tcForm; && {en} .Name of form {fr} Nom du formulaire
&& {en} Standard implementation:
&& {fr} Implémentation standard :
RETURN DoDefault('notify.js')
After that, you should see this in your HTML (view page source):
<script charset="utf-8" src="…/notify.js"></script>
where …/
is the path to your app within locahost
Create a notification class
you could create a custom class:
define class xxxNotify as xxxCst of xxx
procedure notify(message, options)
return textmerge(if vartype(m.message) == 'C' and !empty(m.message);
, 'jQuery.notify(<<cLitteralJS(m.message)>>, <<cLitteralJS(m.options)>>)';
, ''; && Seen no method to trigger end of notification; time out only
)
enddefine
You can add an instance of this Class to your xxxFrm
form class:
procedure load
…
dodefault()
…
if thisForm.wlWeb
thisForm.newObject('oNotify', 'xxxNotify', 'xxx.vcx')
endif
… or you can just add a wNotify()
method to your form base class xxxFrm
Call notify from within a user event
procedure click && or any other
if thisForm.wlHTMLgen
return thisForm.wcEventClientServer(thisForm.oNotify.notify('message', 'warning'))
endif
…
to declare the library, I tried to include this in the wcHTML
method of my screen, the bootstrap-notify.js file being in. \ site:
this.wcHTML = [<script src = "bootstrap-notify.js" type = "text / javascript"> </ script>]
Which seems to have no effect.
More explicit, this screenshot:
yes, all form HTML gets replaced by this <script>
instruction
This translation has only been made here. My code is:
this.wcHTML = [<script src="bootstrap-notify.js" type="text/javascript"></script>]
Again ... grrrr. Please, can you have a look to my screenshot ?
This code can’t work (this.wcHTML =
replaces the whole form HTML)… you’d better try the code I suggested
I have tried this code before:
m.toHTMLgen.cScriptJSadd([<script src="bootstrap-notify.js" type="text/javascript"></script>])
sorry, I did not see your previous post !
I get this in my HTML code:
<script charset="utf-8" src="/dooTest/notify.js?2.26.2-beta.3"></script>
Is this a good way because I'm getting "notify is not a function" ?
Thank you for your code ...
Looks fine …
Please check the file name and location, and the network pane of browser dev tool
Hello Thierry,
Do you think to integrate this library in FIC ?
once developed, probably
Not that easy, because when I insert the bootstrap-notify library in xxxserver.prg, my screen no longer responds to click events
If I comment my code, everything becomes normal again
can you see any JavaScript error in the browser dev tools?
The event no longer seems to be handled. No mistake
my bad
PROTECTED FUNCTION cawJSinc && <script></script>+ {en} Scripts for FoxInCloud, application, form [, custom] {fr} Scripts de FoxInCloud, de l'application, du formulaire[, spécifiques]
LPARAMETERS ;
tcJSAdd; && [''] {en} Application, current form[, and custom] {fr} JS files URLs (UTF-8 encoded) {fr} URL des fichiers JS de l'application et du formulaire courant (encodés en UTF-8)
, toForm as awFrm of aw.vcx; && {en} Reference to form && {fr} Référence au formulaire
, tcForm; && {en} .Name of form {fr} Nom du formulaire
&& {en} Standard implementation:
&& {fr} Implémentation standard :
RETURN DoDefault(m.tcJSadd + ', bootstrap-notify.js')
Hello Thierry,
It is done. I added a wNotify method in my screen class with the following code:
* Notifications utilisant Bootstrap-notify.js - Mnbtype is similar to MessageBox nDialogBoxType - Ex: THISFORM.wNotify("Bel essai", "mon titre", 48)
LPARAMETERS MbnMessage, MbnTitre, MbnType
MbnTitre = IIF (.NOT. EMPTY (MbnTitre), MbnTitre, Vierge)
MbnChaine = '{title: "<b>' + ALLTRIM (MbnTitre) + '</b>:",' + 'message: "' + ALLTRIM (MbnMessage) + '",'
MnbIcone = ICASE (EMPTY (MbnType) .OR. VARTYPE (MbnType) # Cnume .OR. .NOT. INLIST (MbnType, 16, 32, 48, 64), "fa fa-info-circle", MbnType = 16, "fa fa-times-circle", MbnType = 32, "fa fa-question-circle", MbnType = 48, "fa fa-exclamation-circle", "fa fa-info-circle")
MbnType = ICASE ("times" $ MnbIcone, "danger", "exclamation" $ MnbIcone, "warning", "info")
MbnChaine = MbnChaine + 'icon: "' + ALLTRIM (MnbIcone) + '"},'
MbnChaine = MbnChaine + '{type: "' + ALLTRIM (MbnType) + '"}'
IF THISFORM.wlHTMLgen
RETURN THISFORM.wcScriptEventClientServer(TEXTMERGE([jQuery.notify(<<MbnChaine>>);]))
ELSE
wWait (IIF (.NOT. EMPTY (MbnTitre), MnbTitre + Deuxpt + Espace, Vierge) + MbnMessage, "WINDOW TIMEOUT 5")
ENDIF
It is very pleasant to use. It would certainly be useful to create a function allowing a call outside THISFORM.
congrats, first success in 'easy web development' with FoxInCloud!
It would certainly be useful to create a function allowing a call outside THISFORM
As it has to be linked to a user event, not sure you could use it in a standalone procedure
Thank you. It's a long (and very interesting) way ...
Question: why this code does not work in the click method ?
IF (Type('m.thisForm.wlHTMLgen') == 'L' AND m.thisForm.wlHTMLgen)
RETURN IIF (Avant_c.Type_bien = "appartement", THISFORM.wnotify ("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64), .T.)
ENDIF
...
thisForm.wNotify()
should only return the JavaScript instruction and THISFORM.wcScriptEventClientServer()
should be called right from the .click()
event:
procedure thisForm.wNotify()
…
IF THISFORM.wlHTMLgen
RETURN TEXTMERGE([jQuery.notify(<<MbnChaine>>);])
ELSE
wWait (IIF (.NOT. EMPTY (MbnTitre), MnbTitre + Deuxpt + Espace, Vierge) + MbnMessage, "WINDOW TIMEOUT 5")
ENDIF
procedure obj.click
IF (Type('m.thisForm.wlHTMLgen') == 'L' AND m.thisForm.wlHTMLgen)
RETURN IIF (Avant_c.Type_bien = "appartement";
, THISFORM.wcScriptEventClientServer(THISFORM.wNotify("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64));
, .T.;
)
ENDIF
…
From the top of my mind, THISFORM.wcScriptEventClientServer()
considers the calling method as the event method.
Thanks Thierry, I wanted to avoid systematically including THISFORM.wcScriptEventClientServer in the event of the object
In a click, the RETURN THISFORM.wNotify (...)
works well.
But it does not work in an InteractiveChange ()
of a checkbox.
And the RETURN IIF
... is not interpreted, whatever I do.
Vincent, I can help only with code…
procedure click
IF (Type('m.thisForm.wlHTMLgen') == 'L' AND m.thisForm.wlHTMLgen)
1) RETURN IIF (Avant_c.Type_bien = "appartement" .AND. .NOT. Lotnumero $ THIS.Value, THISFORM.wcScriptEventClientServer(THISFORM.wNotify("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64)), .T.)
2) RETURN THISFORM.wcScriptEventClientServer(THISFORM.wNotify("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64))
ENDIF
Code 1) does not work
Code 2) works
on a checkbox, in InteractiveChange method:
IF (Type('m.thisForm.wlHTMLgen') == 'L' AND m.thisForm.wlHTMLgen)
1) RETURN THISFORM.wcScriptEventClientServer(THISFORM.wNotify("La vente d'un bien loué est une affaire de spécialiste, compte tenu notamment d'un éventuel droit de préemption du locataire", "Bien loué", 48))
2) RETURN THISFORM.wNotify("La vente d'un bien loué est une affaire de spécialiste, compte tenu notamment d'un éventuel droit de préemption du locataire", "Bien loué", 48)
ENDIF
Code 1) works
Code 2) does not work
procedure click
This code doesn't work (with a new IF condition):
IF Avant_c.Type_bien = "appartement" .AND. (Type('m.thisForm.wlHTMLgen') == 'L' AND m.thisForm.wlHTMLgen)
RETURN THISFORM.wcScriptEventClientServer(THISFORM.wNotify("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64))
ENDIF
or:
IF (Type('m.thisForm.wlHTMLgen') == 'L' AND m.thisForm.wlHTMLgen) .AND. Avant_c.Type_bien = "appartement"
...
Hi Vincent,
You need to differentiate between design/compile time and run time
- HTML generation occurs only once at form startup, first time a user needs it; it's similar to design time -- IT CAN'T DEPEND ON THE VALUE OF DATA
- Displaying a notification or not is something your code must decide at runtime, in whatever current conditions when user event occurs.
So you need to:
- always generate the JavaScript to display a notification
- in JavaScript, test a condition to decide whether to display the notification at runtime
As this condition is based on the value of a table field (Avant_c.Type_bien = "appartement"
seemingly), you need to make sure the JavaScript is aware of the value of this condition.
Here is code that should meet your requirements:
procedure userEvent
IF THISFORM.wlHTMLgen
RETURN THISFORM.wcScriptEventClientServer(THISFORM.wNotify("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64))
ENDIF
procedure THISFORM.wNotify
…
IF THISFORM.wlHTMLgen
RETURN TEXTMERGE([if(jQuery('#<<thisForm.wcID>>').prop('lNotify')) jQuery.notify(<<MbnChaine>>);])
ELSE
wWait (IIF (.NOT. EMPTY (MbnTitre), MnbTitre + Deuxpt + Espace, Vierge) + MbnMessage, "WINDOW TIMEOUT 5")
ENDIF
procedure THISFORM.wUserAction_Post && {en} documentation in code inherited from aw.vcx!awFrm {fr} documentation dans code hérité de aw.vcx!awFrm
lparameters tcAppHandler, tlPropAssign, tuResult
thisForm.wcScriptJSadd(TEXTMERGE([jQuery('#<<thisForm.wcID>>').prop('lNotify', <<cLitteralJS(Avant_c.Type_bien = "appartement")>>)]))
Thank's Thierry,
It's clear. But I have failed to refresh the condition and reset to true for calls to other places after its execution.
What do you mean? THISFORM.wUserAction_Post()
does not execute or does not provide the expected result?
The execution is good, but only at the second launch
.
I wanted the condition to be true by default and that at runtime it could be tested, run, and then restored to true for other launches (possibly unconditional). I give up ...
never give up… this will create the lNotify
property right when form is loaded:
procedure thisForm.wcHTMLgen
lparameters toHTMLgen, tlInnerHTML
m.toHTMLgen.cScriptJSadd(TEXTMERGE([jQuery('#<<thisForm.wcID>>').prop('lNotify', true);]))
I wrote the same code in the wNotify () method and it worked well, from the first launch. I then tried to change the value of lNotify at launch and then restore to true, and there it goes bad ...
Could you post your whole code to be sure I understand?
otherwise,
this executes at launch time, same for all users:
procedure button.click
IF THISFORM.wlHTMLgen
RETURN THISFORM.wcScriptEventClientServer(THISFORM.wNotify("Pour une saisie plus facile et plus sûre, il est recommandé d'utiliser l'assistant permettant d'insérer un lot de copropriété", "Saisie d'un lot", 64))
ENDIF
procedure THISFORM.wNotify
…
IF THISFORM.wlHTMLgen
RETURN TEXTMERGE([if(jQuery('#<<thisForm.wcID>>').prop('lNotify')) jQuery.notify(<<MbnChaine>>);])
ELSE
wWait (IIF (.NOT. EMPTY (MbnTitre), MnbTitre + Deuxpt + Espace, Vierge) + MbnMessage, "WINDOW TIMEOUT 5")
ENDIF
procedure thisForm.wcHTMLgen
lparameters toHTMLgen, tlInnerHTML
m.toHTMLgen.cScriptJSadd(TEXTMERGE([jQuery('#<<thisForm.wcID>>').prop('lNotify', true);]))
it adds this to form.js, executed when form loads (either as a page or a sub-form):
jQuery('#button').click(function(event){ // sets event handler on button.onclick()
if(jQuery('#formID').prop('lNotify')) jQuery.notify(…);
FoxInCloud.DOMEvent(event…); // sends event to the server
});
jQuery('#formID').prop('lNotify', true); // sets a 'lNotify' property on form element
this executes after each user action
procedure THISFORM.wUserAction_Post && {en} documentation in code inherited from aw.vcx!awFrm {fr} documentation dans code hérité de aw.vcx!awFrm
lparameters tcAppHandler, tlPropAssign, tuResult
thisForm.wcScriptJSadd(TEXTMERGE([jQuery('#<<thisForm.wcID>>').prop('lNotify', <<cLitteralJS(Avant_c.Type_bien = "appartement")>>)]))
it adds this to the script executed when user action completes:
jQuery('#formID').prop('lNotify', true or false depending on data); // changes the 'lNotify' property of form element
when user clicks the button, the handler executes (see above):
if(jQuery('#formID').prop('lNotify')) jQuery.notify(…);
FoxInCloud.DOMEvent(event…); // sends event to the server
Hi Thierry,
I have evolved my function to remove it from the methods of the screen and make it an independent procedure.
This is much more convenient, especially for a condition-dependent launch, because the call can take place after the one on the screen.
As a result, this could be an alternative to wWAIT
.
Hi Vincent,
Thanks for sharing
Maybe your function's code would help understand what you intend to do.
In all modesty, here is my code if it can serve.
In particular, CSS makes it possible to reduce the thickness of the progress bar.
PROCEDURE wNOTIFY
* Notifications utilisant [bootstrap-notify.js] - MbnType est équivalent à MessageBox nDialogBoxType - Condition possible évaluée avec lNotify (initialisation dans vhecr.vcx)
LPARAMETERS MbnMessage, MbnTitre, MbnType, MbnElement, MbnProgress, Mbndelai
LOCAL wActiveForm, MbnChaine
wActiveForm = IIF (VARTYPE (MbnElement) # Cobjet, wActiveForm(), MbnElement)
MbnMessage = IIF (GETWORDCOUNT (MbnMessage) = 1 .AND. VARTYPE (MbnMessage) = Ccarac, MbnMessage, cLitteralJS(MbnMessage)) && Passage d'un texte ou d'une variable (à initialiser - Ex: THISFORM.wcScriptJSadd(TEXTMERGE([mPrompt = '<<Ma_variable>>';]))
MbnTitre = IIF (.NOT. EMPTY (MbnTitre), RicheHTML (MbnTitre, "b") + IIF (Deuxpt $ MbnTitre, Vierge, Deuxpt), Vierge)
MnbIcone = ICASE (EMPTY (MbnType) .OR. VARTYPE (MbnType) # Cnume .OR. .NOT. INLIST (MbnType, 16, 32, 48, 64), "fa fa-info-circle", MbnType = 16, "fa fa-times-circle", MbnType = 32, "fa fa-question-circle", MbnType = 48, "fa fa-exclamation-circle", "fa fa-info-circle")
MbnType = ICASE (MbnProgress = .T., "success", "times" $ MnbIcone, "danger", "exclamation" $ MnbIcone, "warning", "info")
Mbndelai = IIF (EMPTY (Mbndelai), 5000, Mbndelai)
MbnChaine = TEXTMERGE ([{icon: '<<MnbIcone>>', title: <<cLitteralJS(MbnTitre)>>, message: <<MbnMessage>>},{type: "<<MbnType>> notify", element: '#<<wActiveForm.wcID>>', showProgressbar: <<Logique_xml(MbnProgress)>>, delay: <<Mbndelai>>}]) && Création classe "notify"
DO CASE
CASE wlLAN()
wWait (IIF (.NOT. EMPTY (MbnTitre), MbnTitre + Deuxpt + Espace, Vierge) + MbnMessage, "WINDOW TIMEOUT 5")
CASE wActiveForm.wlHTMLgen
RETURN TEXTMERGE([if(jQuery('#<<wActiveForm.wcID>>').prop('lNotify') != false) jQuery.notify(<<MbnChaine>>);])
OTHERWISE
RETURN wActiveForm.wcScriptJSadd(TEXTMERGE([if(jQuery('#<<wActiveForm.wcID>>').prop('lNotify') != false) jQuery.notify(<<MbnChaine>>);]))
ENDCASE
RETURN
[CSS]
.notify {
width: 400px;
font-size: 90%;
}
.notify > [data-notify="progressbar"] {
margin-bottom: 0px;
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
height: 5px;
}
Example:
wNOTIFY ("Confection du projet d'acte et contrôles de cohérence", "Validation", 64, Dooxi, .T., 10000)
Here is an example:
Thanks for sharing Vincent, I will test on my project.
Vincent, RicheHTML function is missing.
Hi Arcadio,
Yes, and other constants ...
PROCEDURE wNOTIFY
* Notifications utilisant [bootstrap-notify.js] - MbnType est équivalent à MessageBox nDialogBoxType - Condition possible évaluée avec lNotify (initialisation dans vhecr.vcx)
LPARAMETERS MbnMessage, MbnTitre, MbnType, MbnElement, MbnProgress, Mbndelai
LOCAL wActiveForm, MbnChaine
wActiveForm = IIF (VARTYPE (MbnElement) # "O", wActiveForm(), MbnElement)
MbnMessage = IIF (GETWORDCOUNT (MbnMessage) = 1 .AND. VARTYPE (MbnMessage) = Ccarac, MbnMessage, cLitteralJS(MbnMessage)) && Passage d'un texte ou d'une variable (à initialiser - Ex: THISFORM.wcScriptJSadd(TEXTMERGE([mPrompt = '<<Ma_variable>>';]))
MbnTitre = IIF (.NOT. EMPTY (MbnTitre), "<b>" + MbnTitre + "</b>" + IIF (":" $ MbnTitre, "", ":"), "")
MnbIcone = ICASE (EMPTY (MbnType) .OR. VARTYPE (MbnType) # "N" .OR. .NOT. INLIST (MbnType, 16, 32, 48, 64), "fa fa-info-circle", MbnType = 16, "fa fa-times-circle", MbnType = 32, "fa fa-question-circle", MbnType = 48, "fa fa-exclamation-circle", "fa fa-info-circle")
MbnType = ICASE (MbnProgress = .T., "success", "times" $ MnbIcone, "danger", "exclamation" $ MnbIcone, "warning", "info")
Mbndelai = IIF (EMPTY (Mbndelai), 5000, Mbndelai)
MbnChaine = TEXTMERGE ([{icon: '<<MnbIcone>>', title: <<cLitteralJS(MbnTitre)>>, message: <<MbnMessage>>},{type: "<<MbnType>> notify", element: '#<<wActiveForm.wcID>>', showProgressbar: <<Logique_xml(MbnProgress)>>, delay: <<Mbndelai>>}]) && Création classe "notify"
DO CASE
CASE wlLAN()
wWait (IIF (.NOT. EMPTY (MbnTitre), MbnTitre + ":" + " ", "") + MbnMessage, "WINDOW TIMEOUT 5")
CASE wActiveForm.wlHTMLgen
RETURN TEXTMERGE([if(jQuery('#<<wActiveForm.wcID>>').prop('lNotify') != false) jQuery.notify(<<MbnChaine>>);])
OTHERWISE
RETURN wActiveForm.wcScriptJSadd(TEXTMERGE([if(jQuery('#<<wActiveForm.wcID>>').prop('lNotify') != false) jQuery.notify(<<MbnChaine>>);]))
ENDCASE
RETURN