Re: Programmatically instantiating WOComponents
"John Bruce" <[email protected]>
| Newsgroups | gmane.comp.web.webobjects.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Yann,
Basically the reason you are having problems is that you're fighting
the way WebObjects works. This is understanable if you're coming from
a PHP background but WO does things differently.
There are a few ways to approach the problem you have.
1. Have 1 address component that "knows" what fields are needed
depending on what country the address is for
2. Have many components for each country that you need to support
where the component to be used is choosen when the page is generated.
I'll go over option 1 as it is generally better to have less
components that can handle more situations. This helps to build up a
resuable library of components which help to save you time inthe
future.
I'm going to make some assumptions about your address entity. I'm
going to assume that it has attributes that make it fit for any
country's address type and that all you need to do is hide certain
fields like State when they don't apply.
Also I'm going to assume that you are using a subclass of
EOGenericRecord. By that I mean that you have generated a Java class
file for your address entity. If you haven't I strongly suggest that
you do this. Also when you do it is best to use a tool like
eogenerator to do it. This tool uses the Generation Gap pattern. The
key benefit is that instead of editing the class file that EOModeler
generates directly and then having to merge changes later on you can
just re run eogenerator and not worry about losing any of your changes
to the generated file.There is more about this technique online in the
wiki book I think as well as it being covered in Practical WebObjects.
Even if you don't understand how it works or what it is doing fully it
will be better in the long run to start using it now.
So the only other assumption I'm going to make is that you have a
WOComponent called AddressComponent.
The simplest way to change what is rendered in a WOComponent is to use
the WOConditional component. This component will only render it's
child components if it's condition binding evaluates to true.
To make this work you AddressComponent.java file should have a
variable called address.
public Address address;
I'm assuming your address entity is called Address. It needs to be
public to allow Key-Value coding to work. This is how you will pass
the Address instance that you want to edit to the AddressComponent. In
you parent component you will bind the address instance to the address
binding. WO takes care of setting the value of these bindings for you
so you do not need to do it manually. More about this process can be
found in the apple docs and in the various WO books.
Now that we have our particular address instance in our component
let's render the html to work for the address of that country. I'll
leave out all the fields except for State and country to give you the
idea of how it works.
In the AddressComponent you need something which looks like this - in
src view if using WOBuilder.
<webobject name="ShowStateConditional">
State: <webobject name="State"></webobject>
</webobject>
<webobject name="Country"></webobject>
The Country component is a WOPopup which lists the different
countries. Add a binding to this called:
onchange = "this.form.submit();"
you will need to check my javascript as I am writing from memory. This
will cause the page to be submitted when the value for the country
changes causing the AddressComponent to render itself again and
determine if the state field should be shown.
Now to determin if the state field should be shown requires creating a
mehtod that returns a boolean. I would strongly suggest creating this
method in the Address.java file that was generated.
I would do something along these lines in Address.java:
public boolean hasState() {
if (this.state() == null)
return true;
return this.country().hasState();
}
you can replace the country().hasState() method to perform what ever
logic you need to determin if this address has a state.
Now in the AddressComponent you can setup the bindings for the
"ShowStateConditional" as:
ShowStateConditional: WOConditional {
condition = address.hasState;
}
If address.hasState() evaluates to true then the state field will be
shown otherwise it will not.
you can repeat this for other conditional fields.
In general you should not override appendToResponse. The key times to
do this are when you want to totally change the content of the
component for example if you are generating a PDF or if you want to
alter the http response headers. There are other times but for
situations like this you would never overide that method. All the
presentation logic should be done in the main part of the component by
using elements like WOConditional or WOSwitchComponent etc. There
sublasses of WOConditional that are usefull as well. Some examples
from WONDER, a major opensource library for WO, such as
ERXNonNullConditional which will only render their content if the
condition evaulates to non null.
HTH
John
On 8/14/06, Yann Bizeul <[email protected]> wrote:
> Hello list, please welcome the WONewbie that I am !
>
> I'm starting a new web application using WO because tired of
> reinventing the wheel with each line of PHP, and I really love what I
> see of WO.
> But since I'm trying to do things that are beyond my knowledge, and
> that I think this is the better way to learn, I would need your help :-)
>
> Here is the situation :
>
> I made a WOComponent "AddressComponent" to display to the user text
> fields to type a postal address.
> The content of this component should be dynamic, and programmatically
> generated, because there is a "country" menu that, when changed,
> reload the DIV where is loaded the form to make it suit different
> localization.
>
> For example, a US address should have a state field, and a french
> address should not.
>
> Basically, here is the way I'm trying to implement this in
> AddressComponent.java :
>
> === MY CODE ===
> public void appendToResponse(WOResponse aResponse,WOContext aContext)
> {
> [...]
> // Using a format string parsed above, get the name of the
> component to add (CityComponent, StreetComponent, ...)
> // There is just a single WOTextField in this component, bound to
> their "address" instance variable
> String componentName = token.substring(0,1).toUpperCase() +
> token.substring(1,token.length()).toLowerCase() + "Component";
>
> // Get the component
> AbstractAddressComponent component = (AbstractAddressComponent)
> pageWithName(componentName);
>
> // Set the address and add it to the response
> component.setValueForBinding(address,"address");
> component.appendToResponse(aResponse,aContext);
> [...]
> super.appendToResponse(aResponse,aContext);
> }
> ===============
>
> Visually, it seem to work fine when I load the page, the bindings
> seem to be there because the chosen country is well reflected in the
> displayed form. Even the dynamic update of the address div seem to
> work fine, which is implemented by this excerpt of the code that set
> the result as my DIV's innerHTML:
>
> === JAVASCRIPT CODE ===
> http = getHTTPObject();
> http.open("Get","<webobject name="ResourceURL1"></webobject>?
> countryCode=" + code + "&idLocation=" + "<webobject name="String1"></
> webobject>",false);
> ===== HTML OUTPUT =====
> http = getHTTPObject();
> http.open("Get","/cgi-bin/WebObjects/MyApp.woa/wo/
> xpv37pbTrSRWvRhOjU1weg/2.3?countryCode=" + code,false);
> =======================
>
> The problem is that everything in the address is null when I submit
> the form the rest of the form is OK). Obviously, there is something
> wrong with the HTML code generated, every field has the same name and
> an identifier missing (since I have a subcomponent, it should be
> 7.6.x, with x incrementing, this is my understanding of the situation):
>
> === HTML OUTPUT ===
> <input size="30" type="text" name="7.6"><br>
> <input size="7" type="text" name="7.6"> <input size="15" type="text"
> name="7.6"><br>
> <input size="4" type="text" name="7.6"><br>
> ===================
>
> So I guess I'm doing this the wrong way, and would need some advice.
> I found no sample of programmatically instanciated WOComponent.
>
> By advance, thanks for your help
>
> Yann Bizeul • yann at tynsoe.org
> Cocoa Developer
>
> Tynsoe Projects
> BuddyPop • GeekTool • SSH Tunnel Manager • ...
> http://projects.tynsoe.org/
>
>
> _______________________________________________
> WebObjects-dev mailing list
> [email protected]
> http://www.omnigroup.com/mailman/listinfo/webobjects-dev
>