Dynamic String in UiBinder (not for i18n) - gwt

I'm trying to make a Widget that generalizes a bootstrap style from twitter for collapsible items.
I got to make it work hardcoding it, but I find some dificulties abstracting it.
The widget looks like:
<div class="accordion" id="accordion1">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion1" href="#collapseOne">
... text to show collapsed ...
</a>
</div>
<div id="collapseOne" class="accordion-body collapse">
<div class="accordion-inner">
... anything to show expanded ...
</div>
</div>
</div>
</div>
The thing is, this uses a javascript which depends on ids of some div tags. The generalized widget would need this to be randomized or depending on some seed passed in the constructor.
It would also be nice to have access to those generated Strings from Java part, as it would be a fancy way to set the text showing in the widget.
My first approach was to use something like <ui:with type="com.a.b.c.IdGenerator" field="idGenerator"></ui:with> but it seems to instanciate dynamically the class IdGenerator so no access to the Strings is obtained in Java part.
Is there any fancy way to dinamically generate those Strings having access to them from the Java part?

You simply need a #UiField IdGenerator idGenerator on the Java side to have the instance created by the <ui:with> injected in it (or you can #UiField(provided = true) it).

Related

Change Component's content during rendering phase when loading its model fails

I have a widget components with simple markup inheritance like so
AbstractWidget
<wicket:panel>
<wicket:child />
<div wicket:enclosure="editButton" class="widget-edit-wrapper">
<button wicket:id="editButton" type="button" class="widget-edit">
<span class="glyphicon glyphicon-cog"></span>
</button>
<div style="display:none;">
<div wicket:id="editPanel" class="widget-settings"></div>
</div>
</div>
</wicket:panel>
LabelWidget
<wicket:extend>
<div wicket:id="container" class="label-widget flex-container">
<div wicket:id="label"></div>
</div>
</wicket:extend>
Now imagine the label content is taken from a loadable detachable model and loading the model throws an Exception.
I need to show some feedback to the user on this 'broken' widget component. Is there a way to replace the whole child's content when loading its model throws an Exception?
Note that LabelWidget is just one from many AbstractWidget childs so I need to solve this in the AbstractWidget and I also need to preserve all elements from the AbstractWidget component.
You can accomplish this by using a smarter model - a model that delegates to the original one and try/catches if it throws an exception. In case of an exception you will need to return an "empty" model object, where "empty" would mean different things for your different use cases.
Your smart model could implement IComponentAssignedModel so that it knows the Component it is used in. This way in the catch clause you can do component.error("..."). In AbstractWidget you should add a FeedbackPanel that will render the error message. The specialization widget, like LabelWidget, will render as "empty" (whatever this means for it) by using the fallback model.

Create repeatable custom form fields in web2py?

I want to create twitter bootstrap compliant form. According to the docs for Twitter Bootstrap v2.2.2 (the version included with web2py) the html should look like:
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="inputEmail">Email</label>
<div class="controls">
<input type="text" id="inputEmail" placeholder="Email">
</div>
</div>
...
I'm currently using SQLFORM which outputs html that doesn't really fit with this (even using formstyle='divs'). Besides I want my html output to be clean without web2py artifacts such as class="w2p_fl". So my thought is to use a custom form. However in doing this there would be a lot of repeated code. That is, the following would basically need to be repeated for each field.
{{=form.custom.begin}}
<div class="control-group">
{{=LABEL(form.custom.label['myfield'], _class='control-label',
_for='mytable_myfield')}}
<div class="controls">{{=form.custom.widget.myfield}}</div>
</div>
...
{{=form.custom.end}}
So how can I repeat the above unit of code so I could replace it with something like {{=bootstrap_field(db.mytable.myfield)}} or some other way to adhere to DRY?
What is the web2py way to do this? Create a view function? Pass a function in the dictionary returned by the controller? Create my own html helper? Create my own widget? Another way?
If you're using Bootstrap 2, you can just do:
form = SQLFORM(..., formstyle='bootstrap')
For Bootstrap 3 (or any other custom formstyle you'd like to create), the formstyle argument can be a function (or other callable) that produces the form DOM. The function will be passed the form and a fields object, which is a list of tuples, with each tuple containing a CSS id, label, input element, and (possibly empty) comment/help text. To get an idea of what such a function should look like, check out the one used for Bootstrap 2 forms.

Does wicket lose hold of the HTML components after a rearrangement through JavaScript?

I have a repeating component in wicked which needs to be added and deleted as per the user requirement. The maximum number of component is predefined. So I am adding the components at start up and hiding and showing based on need. I am required to change the arrangement of the components in the HTML markup when there is any deletion of the component. I use JavaScript for this. I want to know if wicket would lose hold of the components if I do this.
<div wicket:id="borrowerTabs" id="borrowerTabs">
<span wicket:id="borrowerTab1" id="borrowerTab1" ></span>
<span wicket:id="borrowerTab2" id="borrowerTab2" ></span>
<span wicket:id="borrowerTab3" id="borrowerTab3" ></span>
<span wicket:id="borrowerTab4" id="borrowerTab4" ></span>
<button wicket:id="addBorrower" id="addBorrower" type="button"></button>
<button wicket:id="deleteBorrower" id="deleteBorrower" onclick="updateUIForDeleteBorrower()" type="button"></button>
</div>
If delete the borrowerTab3, contents inside borrowerTab4 will be replacing the contents inside borrowerTab3 and the model objects too will be swapped though I do not do a target.add(borrowerTab3). Now while form submission, I am not getting the values of the fields inside borrowerTab3.
I'm not sure if it helps but try component.setVisible(false) in your java code to hide it.

Modify Wicket FormComponent markup without panel?

In Wicket, I'd like to subclass TextField form component to add additional markup around the tag.
Why I do not want to create a Panel:
1) I want the web page designer to use the input tag:
<input wicket:id="blah">
2) I don't want the subclass to lose the FormField semantics in Java, e.g.:
field.setRequired(true);, etc.
I'm fine with hard-coding the wrapping markup in Java. But I'd like this to behave like a FormField in Java.
Any ideas? Looked around for examples, but stumped on this one
Edit:
I'm aware of Borders, but my issue with them is you have to add them in both the markup and in Java. For example:
<div wicket:id="border">
<input type="text" wicket:id="field"/>
</div>
--
FormComponent<Integer> field = new TextField<Integer>("field", new Model(1));
field.setRequired(true);
Border border = new MyBorder("border");
border.add(field);
form.add(border);
This makes the web page designer have to be aware of special markup, and the Java can't be encapsulated (as a FormField subclass).
Ah, this is what I wanted via IBehavior:
My wrapper behavior (sorry for the Scala syntax):
class FieldWrapper extends AbstractTransformerBehavior {
def transform(component: Component, output: CharSequence): CharSequence = """
<div class="blah">
Blah blah blah
%s
</div>
""".format(output)
}
My subclass:
class MyField[T](id: String, model: IModel[T]) extends TextField[T](id, model) {
add(new FieldWrapper)
}
Original Markup:
<input type="text" wicket:id="foobar"/>
Generated markup:
<div class="blah">
Blah blah blah
<input type="text" value="" name="foobar" xmlns:wicket="http://wicket.apache.org">
</div>
Thanks S.O. for jumpstarting my mind :-)
You wouldn't even need to subclass TextField. although it might be easier to to so if you want to reuse it. If you just want to add markup outside of the original tag, it's the poster use case for a Border.
If digging into the rendering of a Component is needed
MarkupContainer#onRender()
is your friend.
An example might be:
AbstractTree#onRender()
mf

jquery selector for different instances of the same class

I don't know if the title is all apt...... but here is my situation....i have a class called dropper and another class drop_list...these two are sub-classes of the class drop_head, the drop_list has to drop down whenever the dropper is clicked...
<div class="drop_head">
<div class="dropper"> Content-1</divr>
<div class="drop_list"> List-1</div>
</div>
<div class="drop_head">
<div class="dropper"> Content-2</divr>
<div class="drop_list"> List-2</div>
</div>
when content-1 is clicked list-1 has to toggle and when content-2 is clicked list-2 has to drop down... how do i achieve this using single jquery..?? thanks in advance......
If i understand you correctly this should be pretty simple:
$('.drop_head').each(function(i,e){
$('.dropper', e).click(function(){
$('.drop_list', e).slideToggle();
});
});
by using the .drop_head as the context for the list and clickable element you dont need to use id's. additionally if you omit a list or dropper by accident it will only screw up that one "widget" and wont effect the others, which wouldnt be the case with closest.
you have two way (that I see =))
-just give two different ID names to your couples drop-list/dopper
<div class="dropper" id="id_1"> Content-1</divr>
<div class="drop_list" id="id_1"> List-1</div>
<div class="dropper" id="id_2"> Content-2</divr>
<div class="drop_list" id="id_2"> List-2</div>
and then say something like:
$(".dropper #id_1").click(function(){$("#id_1").slideToggle("slow")})
or shorter:
$(".dropper").click(function(){$(this).closest('drop_list').slideToggle()})
Hope it helps
Luca