View Full Version : Binding with clientside generated controls
Danne
08-28-2006, 08:53 PM
Hi,
I'm creating input elements on the clientside using JavaScript/DOM. These are then submitted to the serverside. There are usually collections of elements; several elements with the same value in the name property.
Can I still use the Binding features of Spring.net to get the values into a serverside object?
As I understand it, from reading the examples, the binding requires .NET controls (like: <asp:TextBox..>)
Edit:
I'm using a naming standard for the inputs. For instance:
<input name="Person.name" />
<input name="Person.Address.name" value="Home address"/>
<input name="Person.Address.street" />
<input name="Person.Address.name" value="Work address" />
<input name="Person.Address.street" />
Thanks,
Daniel
Erich Eichinger
08-29-2006, 06:40 PM
Yes - this is possible.
DataBinding uses Spring's expression library to evaluate expressions. Thus you can use (almost) any expression you like.
I'm not quite sure about the syntax, but to bind simple request values, you can use "Request['paramname']" as expression to access the Request's value collection.
cheers,
Erich
Danne
08-30-2006, 05:16 PM
Thanks, that is good news.
However I can't make it work.
This is the client control I'm using:
<input type="text" name="Receita_strReceita" />
Here's some serverside code to test (inside InitializeDataBindings):
receita = new Receita();
receita.strReceita = "init";
Response.Write("Request['Receita_strReceita']: " + Request["Receita_strReceita"] + "<br>");
BindingManager.AddBinding("Request[Receita_strReceita]", "receita.strReceita");
Response.Write("receita.strReceita: " + receita.strReceita + "<br>");
I also tried:
BindingManager.AddBinding("Request['Receita_strReceita']", "receita.strReceita");
The InitializeBindings is called from Page_Load:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
InitializeDataBindings();
}
}
Actually it feels like I'm doing this completly wrong. Isn't the InitializeBindings called somewhere inside Spring.Web.UI.Page?
And the receita should be injected, but unless I add new Receita() it remains null.
Anyway the output of the Response.Write is (when "test" is submitted):
Request['Receita_strReceita']: test
receita.strReceita: init
So the binding didn't work.
Any ideas on how to solve this?
Thanks,
Daniel
Erich Eichinger
08-30-2006, 09:05 PM
Hi,
To make DataBinding work, you basically should do 2 things:
1) override the Page's InitializeDataBindings() method and add your DataBindings there
2) Provide a Property with your domain object
A simple sample page class handling your problem looks like this:
class MyPage : Spring.Web.UI.Page
{
private Receita _receita = new Receita();
protected Receita TheReceita
{
get { return _receita; }
}
// this method is only called once during application lifetime!
protected override void InitializeDataBindings()
{
BindingManager.AddBinding(
"Request['Receita_strReceita']",
"TheReceita.strReceita,
BindingDirection.SourceToTarget );
}
protected override void OnLoad( EventArgs ev )
{
// Data "unbinding" magic is done here
base.OnLoad();
if (this.IsPostBack)
{
// will write out the posted value
Response.Write( this.TheReceita.strReceita );
}
}
}
You should know, that InitializeDataBindings() is only called once during application lifetime for each Page-Type.
Values are "unbound" from the Request ("source") into your Domain-Object ("target") during OnLoad(). Values get "bound" from the target back onto the "source" during OnPreRender().
In your case it is not possible to write values into the Request. Thus you should specify a one-way BindingDirection.
Does this clear up things for you?
cheers,
Erich
Danne
08-30-2006, 10:37 PM
Yes, it all became a lot clearer now. Thanks!
And the example works very well too.
Now to continue the complexity. My domain object Receita has a collection of Etapas:
public Etapa[] Etapas
This domain has a property called strEtapa.
On the clientside I do not know just how many etapas the user will add. I will generate the inputs on the fly as he decides to add more, using javascript. The names of the inputs could be:
Receita_Etapas0_strEtapa,
Receita_Etapas1_strEtapa,
... Receita_Etapasn_strEtapa
I imagine the binding something like this, using a regular expression for the index:
BindingManager.AddBinding(
"Request['Receita_Etapas/([0-9]+)/_strEtapa']",
"receita.Etapas[\1].strEtapa",
BindingDirection.SourceToTarget);
So basically the regular expression /([0-9]+)/ searches for a number in the source and replaces \1 with it in the target. And then use this number as an index to create new instances of Etapa.
Would the parser support anything like that?
Since this is done once during application lifetime, perhaps it will not work at all?
Thanks again,
Daniel
Erich Eichinger
08-31-2006, 07:17 AM
Hi Daniel,
I'm pretty sure, this won't work. As you said, the expressions are parsed only once during an application, Regexp's cannot be used.
But there is a simple workaround:
1)
On the clientside give all your strEtapa input fields the same(!) name.
-> The values will be available in the Request.Form through Form.GetValues() as a string-array
2)
Write a helper property on your page, that correctly sets the array on your Receita collection.
This might look like this:
// HTML Form
<br><input type="text" name="vallist" />
<br><input type="text" name="vallist" />
<br><input type="text" name="vallist" />
class MyPage : Spring.Web.UI.Page
{
private string[] _vallist;
public string[] ValueList
{
get { return _vallist; }
set {
// you would iterate the array and set on your Receita-Objects here
_vallist = value;
}
}
protected override void InitializeDataBindings()
{
BindingManager.AddBinding(
"Request.Form.GetValues('vallist')",
"ValueList",
BindingDirection.SourceToTarget);
}
...
}
cheers,
Erich
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.