Hi
I want to add a jqueryUI Slider and I get it working in the browser. Cool. Now, what's the way back to Delphi? If I move the slider I need a callback in Delphi to do some things. Any hint?
{code}
$(function(){
// Slider
$('#slider').slider({
});
});
{code}
Greetings
Sven
Hi, Sven!
1. You need to write Ajax handler as a published method of your IWForm
procedure MyAjaxHandler(EventParams: TStringList);
2. Register the handler on IWFormCreate:
WebApplication.RegisterCallBack('MyAjaxHandler', MyAjaxHandler);
3. In JS code you can execute your callback something like this:
executeAjaxEvent("&myExtraParam=blablabla", null,"MyAjaxHandler",false, null, false);
Your extra params will be accessible through EventParams list among with the standard event parameters on the server side.
Thanks for this post, it was was very helpful. One note I would add, which I found out the hard way:
Make sure to give your AJAX event a name that is *unique in your entire program*.
I found out because I had registered "MyAjaxHandler" on one form, then did it again on another. Well, the event on the second one started getting the call from the first form. This is bad in itself, but it also caused an A/V because form2 had already been destroyed, and had not been re-created yet.
I'm not sure if I've seen the latest of A-to-Zed's docs on this, but they may want to stress that the event name needs to be unique -if this is correct, or describe a better way to handle it.
> {quote:title=Alexander Popov wrote:}{quote}
> Hi, Sven!
>
> 1. You need to write Ajax handler as a published method of your IWForm
>
> procedure MyAjaxHandler(EventParams: TStringList);
>
>
> 2. Register the handler on IWFormCreate:
>
>
> WebApplication.RegisterCallBack('MyAjaxHandler', MyAjaxHandler);
>
>
> 3. In JS code you can execute your callback something like this:
>
>
> executeAjaxEvent("&myExtraParam=blablabla", null,"MyAjaxHandler",false, null, false);
>
>
> Your extra params will be accessible through EventParams list among with the standard event parameters on the server side.
This is what I have at the moment. I still can't seem to get the Value of the slider into Delphi. In can use the value from Javascript without any problems. I would need it in Delphi.
Thanks for any help anyone can give me.
{code}
{code}
In Delphi
{code}
procedure TFrmAdmin.MyAjaxHandler(EventParams: TStringList);
begin
IWButton1.Caption := EventParams.Values['which'];
WebApplication.ShowMessage(EventParams.Values['value']);
// WebApplication.ShowMessage(EventParams.Text);
end;
procedure TFrmAdmin.IWAppFormCreate(Sender: TObject);
begin
WebApplication.RegisterCallBack('MyAjaxHandler', MyAjaxHandler);
end;
{code}
Hi Alexander,
thats so simple? That's cool... Thanks a lot!!!
Sven
> {quote:title=Alexander Popov wrote:}{quote}
> Hi, Sven!
>
> 1. You need to write Ajax handler as a published method of your IWForm
>
> procedure MyAjaxHandler(EventParams: TStringList);
>
>
> 2. Register the handler on IWFormCreate:
>
>
> WebApplication.RegisterCallBack('MyAjaxHandler', MyAjaxHandler);
>
>
> 3. In JS code you can execute your callback something like this:
>
>
> executeAjaxEvent("&myExtraParam=blablabla", null,"MyAjaxHandler",false, null, false);
>
>
> Your extra params will be accessible through EventParams list among with the standard event parameters on the server side.
My calls were on separate forms. Could there be a problem if you created the same events with controls of the same name?
I did a test app with 2 IWEdits named the same on 2 different forms with ASyncOnChange events. No problems.
I then added my own AJAX event on the both forms named the same thing (with the control name in it). If I run it, open form2, then close(release) form2, then hit the button on form1 to run the js that will run the event, it ends up trying to run the event code on form2, and causes an A/V. Does Intraweb do some sort of clean up or un-register call of it's Async callbacks when a form is destroyed? Or am I doing something else entirely wrong.
I used IW11.0.60 in the test
{code}
unit Unit1;
interface
uses
Classes, SysUtils, IWAppForm, IWApplication, IWColor, IWTypes, Controls,
IWVCLBaseControl, IWBaseControl, IWBaseHTMLControl, IWControl,
IWCompButton, IWCompMemo, IWCompEdit;
type
TIWForm1 = class(TIWAppForm)
IWButton1: TIWButton;
IWEdit1: TIWEdit;
IWMemo1: TIWMemo;
IWButton2: TIWButton;
ebResult: TIWEdit;
procedure IWButton1Click(Sender: TObject);
procedure IWEdit1AsyncChange(Sender: TObject;
EventParams: TStringList);
procedure IWAppFormCreate(Sender: TObject);
procedure IWEDIT1MyAjaxHandler(EventParams: TStringList);
procedure IWButton2Click(Sender: TObject);
public
end;
implementation
uses Unit2, IWForm, IWBaseForm;
{$R *.dfm}
procedure TIWForm1.IWButton1Click(Sender: TObject);
var frm:TIWform2;
begin
frm:=TIWform2.Create(WebApplication);
frm.Show;
end;
procedure TIWForm1.IWEdit1AsyncChange(Sender: TObject;
EventParams: TStringList);
begin
IWMemo1.Lines.Add(EventParams.Text);
end;
procedure TIWForm1.IWAppFormCreate(Sender: TObject);
begin
ExtraHeader.Add('');
ExtraHeader.Add('');
ExtraHeader.Add('');
WebApplication.RegisterCallBack('IWEDIT1MyAjaxHandler',IWEDIT1MyAjaxHandler);
end;
procedure TIWForm1.IWEDIT1MyAjaxHandler(EventParams: TStringList);
var c,v:String;
zControl:TIWControl;
begin
c:=EventParams.Names[1];
if (c<>'') AND
(FindComponent(c)<>nil)
then
begin
zControl:=TIWControl(FindComponent(c));
if zControl.ClassNameIs('TIWEdit') then
begin
TIWEdit(zControl).Text:=EventParams.Values[c];
TIWEdit(zControl).refresh;
//other stuff
end;
end;
end;
procedure TIWForm1.IWButton2Click(Sender: TObject);
begin
AddToInitProc('var sValue=''\u0026'+UpperCase(ebResult.Name)+'=''+escape($(''#IWEDIT1'').val()); executeAjaxEvent(sValue, null,"IWEDIT1MyAjaxHandler",false, null, true);');
end;
initialization
TIWForm1.SetAsMainForm;
end.
{code}
Form2:
{code}
unit Unit2;
interface
uses
Classes, SysUtils, IWAppForm, IWApplication, IWColor, IWTypes,
IWCompMemo, IWCompEdit, Controls, IWVCLBaseControl, IWBaseControl,
IWBaseHTMLControl, IWControl, IWCompButton;
type
TIWForm2 = class(TIWAppForm)
IWButton1: TIWButton;
IWEdit1: TIWEdit;
IWMemo2: TIWMemo;
ebResult: TIWEdit;
IWButton2: TIWButton;
procedure IWEdit1AsyncChange(Sender: TObject;
EventParams: TStringList);
procedure IWButton1Click(Sender: TObject);
procedure IWEDIT1MyAjaxHandler(EventParams: TStringList);
procedure IWButton2Click(Sender: TObject);
procedure IWAppFormCreate(Sender: TObject);
public
end;
implementation
{$R *.dfm}
procedure TIWForm2.IWEdit1AsyncChange(Sender: TObject;
EventParams: TStringList);
begin
IWMemo2.Lines.Add(EventParams.Text);
end;
procedure TIWForm2.IWButton1Click(Sender: TObject);
begin
Release;
end;
procedure TIWForm2.IWEDIT1MyAjaxHandler(EventParams: TStringList);
var c,v:String;
zControl:TIWControl;
begin
//WebApplication.ShowMessage('This is the Event on form 2');
c:=EventParams.Names[1];
if (c<>'') AND
(FindComponent(c)<>nil)
then
begin
zControl:=TIWControl(FindComponent(c));
if zControl.ClassNameIs('TIWEdit') then
begin
TIWEdit(zControl).Text:=EventParams.Values[c];
//other stuff
end;
end;
end;
procedure TIWForm2.IWButton2Click(Sender: TObject);
begin
AddToInitProc('var sValue=''\u0026'+UpperCase(ebResult.Name)+'=''+escape($(''#IWEDIT1'').val()); executeAjaxEvent(sValue, null,"IWEDIT1MyAjaxHandler",false, null, true);');
end;
procedure TIWForm2.IWAppFormCreate(Sender: TObject);
begin
ExtraHeader.Add('');
ExtraHeader.Add('');
ExtraHeader.Add('');
WebApplication.RegisterCallBack('IWEDIT1MyAjaxHandler',IWEDIT1MyAjaxHandler);
end;
end.
{code}
> {quote:title=Pedro Lopes wrote:}{quote}
> Hi
>
> Em 12/07/13 15:10, Dan Armstrong escreveu:
> > Make sure to give your AJAX event a name that is *unique in your entire program*.
> >
>
> Yes, for a given IW AControl, normally is AControl.HTMLName +
> '.MyAjaxHandler'
>
> Best Regards
>
> Pedro
>
> --
>
> http://www.cgdevtools.com
Francisco,
That's not what I was trying to do. My example DOES create 2 separate calls on 2 separate pages. What I was demonstrating is that if you name them the same thing, registering the second one will cause all the calls to the first one, to go to the second one. I was looking for guidance on best practices for naming these events, and wondering how IW seems to have no problems with same-named async event calls on 2 separate forms.
> {quote:title=Francisco Armando Dueñas Rodriguez wrote:}{quote}
> You cannot use a callback in a form that is used in another form, you have a call back per form, remember each form
> is a new webpage, so there is no problem registering again the callback it will be substituted. unless you create a global
> procedure in another unit and have a public variable that will contain the current TIWForm viewed. so it can be accessed by
> the callback method. but I think it is better if you copy the callback method code from form1 and add it to form2.
>
> Also you can create a new class like TIWMyEditCallBack in an external unit, and add the callback procedure as a method, just add a
> Constructor Create with a parameter to pass the current IWForm and store it in a variable/field like 'fIWForm: TIWForm'.
>
> {code}
> type
> TIWMyEditCallBack = class(tobject)
> protected
> fIWForm: TIWForm
> public
> constructor Create( AForm: TIWForm );
> procedure AjaxHandler(EventParams: TStringList);
> end;
> {code}
>
>
> Change the callback procedure code to search in the stored form reference.
> so ti should look something like this
> {code}
> procedure TIWMyEditCallback.AjaxHandler(EventParams: TStringList);
> var c,v:String;
> zControl:TIWControl;
> begin
> c:=EventParams.Names[1];
> if (c<>'') AND
> (fIWForm.FindComponent(c)<>nil)
> then
> begin
> zControl:=TIWControl(fIWForm.FindComponent(c));
> if zControl.ClassNameIs('TIWEdit') then
> begin
> TIWEdit(zControl).Text:=EventParams.Values[c];
> TIWEdit(zControl).refresh;
> //other stuff
> end;
> end;
> end;
> {code}
>
> Then instantiate this class per form in the OnCreate event of the form and destroy it in the OnDestroy event of the form
>
> You can have this object as a property or field of a form:
> {code}
> fMyEditCallBack := TIWMyEditCallBack.Create(self); //self is the current IWForm;
> {code}
>
> In the OnRender event of the form Register the callback, so it will re-register it even if the form is not freed and called again
> {code}
> procedure TIWForm1.IWAppFormRender(Sender: TObject);
> begin
> WebApplication.RegisterCallBack('IWEDIT1MyAjaxHandler', fMyEditCallBack.AjaxHandler);
> end;
> {code}
>
> Edited by: Francisco Armando Dueñas Rodriguez on Jul 12, 2013 8:13 PM
Vote for best answer.
Score: 0
# Vote: 0
Date Posted: 15-Jul-2013, at 10:15 AM EST
From: Dan Armstrong
Re: How to combine JQuery UI and IntraWeb AJAX [Edit]
> {quote:title=Dan Armstrong wrote:}{quote}
> Francisco,
> That's not what I was trying to do. My example DOES create 2 separate calls on 2 separate pages. What I was demonstrating is that if you name them the same thing, registering the second one will cause all the calls to the first one, to go to the second one. I was looking for guidance on best practices for naming these events, and wondering how IW seems to have no problems with same-named async event calls on 2 separate forms.
Hi Dan. Sorry I don't explained me well. I suggest you the above code because that replaces the same async event, when the form is rendered again, this because IW has a global async event registration per user session, it is not per form or owned object, so when you register the same event name with the second form it will replace the current record that was owned by the first form.
That is why I recommend you you rgister the call back in the OnRender event of the form, so it will re-register it when the form is rendered again. It is not so important to have to AsyncCalls that will do the same thing.
If you still want to have a record per Form then register it by using the current iwform name like this:
WebApplication.RegisterCallBack(Self.Name+'_IWEDIT1MyAjaxHandler', MyAjaxHandler);
Just remember this:
What RegisterCallback stores is a pointer to the MyAjaxHandler memory position, so if you free the form and recreate it again the pointer will be different, that Why it is so important you can to call RegisterCallback in the OnRender event To prevent AV errors.
I suggested the AjaxHandler Class approach because both routines in form1 and form2 does the same thing, so you have repeated code. the only thing that changes is the form that call it, so that is why the suggestion to have a single method.
It wa sjust a more OOP approach, You approach is not wrong, just dont foget, if you still want to manage teh same ajax event name, to register the function in the OnRender event of each form and not in the onCreate
Thank you Francisco. That explains it quite well. I came across the problem on accident. Your explanation suggests that the best practice would be to do the WebApplication.RegisterCallBack in the OnRender of the form. If I put it there (instead of OnCreate), I would have not come across the issue. Hopefully AtoZed has this noted in the docs, but this is all I've found: http://docs.atozed.com/docs.dll/classes/TIWApplication.html [http://docs.atozed.com/docs.dll/classes/TIWApplication.html|http://docs.
atozed.com/docs.dll/classes/TIWApplication.html]
It does note that the name should be unique, I think It should mention that the best practice would be to put it in the OnRender of the form in most cases.
You've been very helpful.
> {quote:title=Francisco Armando Dueñas Rodriguez wrote:}{quote}
> > {quote:title=Dan Armstrong wrote:}{quote}
> > Francisco,
> > That's not what I was trying to do. My example DOES create 2 separate calls on 2 separate pages. What I was demonstrating is that if you name them the same thing, registering the second one will cause all the calls to the first one, to go to the second one. I was looking for guidance on best practices for naming these events, and wondering how IW seems to have no problems with same-named async event calls on 2 separate forms.
>
> Hi Dan. Sorry I don't explained me well. I suggest you the above code because that replaces the same async event, when the form is rendered again, this because IW has a global async event registration per user session, it is not per form or owned object, so when you register the same event name with the second form it will replace the current record that was owned by the first form.
>
> That is why I recommend you you rgister the call back in the OnRender event of the form, so it will re-register it when the form is rendered again. It is not so important to have to AsyncCalls that will do the same thing.
>
> If you still want to have a record per Form then register it by using the current iwform name like this:
>
> WebApplication.RegisterCallBack(Self.Name+'_IWEDIT1MyAjaxHandler', MyAjaxHandler);
>
> Just remember this:
>
> What RegisterCallback stores is a pointer to the MyAjaxHandler memory position, so if you free the form and recreate it again the pointer will be different, that Why it is so important you can to call RegisterCallback in the OnRender event To prevent AV errors.
>
> I suggested the AjaxHandler Class approach because both routines in form1 and form2 does the same thing, so you have repeated code. the only thing that changes is the form that call it, so that is why the suggestion to have a single method.
>
> It wa sjust a more OOP approach, You approach is not wrong, just dont foget, if you still want to manage teh same ajax event name, to register the function in the OnRender event of each form and not in the onCreate