Wicket: How can I rerender the current form without losing existing input? - ajax

I have a form with a combobox/drop down to select the user language. If the user changes the language, I'd like to update all the labels but leave the input elements alone.
In jQuery, I'd request a list of label IDs and the new texts via JSON and then use a loop like this:
var texts = {[ {id:'nameLabel', text:'First Name'}, {id:'familyLabel', text:'Family Name'} ]};
for( var i=0; i<texts.length; i++) {
var item = texts[i];
$('#'+item.id).text(item.text);
}
That would update all the labels without modifying anything else. How do I do this in Wicket?
[EDIT] What I tried:
DropDownChoice<Locale> ddc = new DropDownChoice<Locale>(...);
ddc.add( new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate( AjaxRequestTarget target ) {
getSession().setLocale( language );
for( MarkupContainer label : labels ) {
target.addComponent( label );
}
}
});
This does change the labels but it also renders all the input fields again. I found no way to access the current values of the input fields.
[EDIT2] The list of labels is created like so:
StringResourceModel usernameLabel = new StringResourceModel("usernameLabel", this, new Model<ValueMap>(map));
labels.add(add(new Label("usernameLabel", usernameLabel)));

This is wrong:
labels.add(add(new Label("usernameLabel", usernameLabel)));
You're not adding Label instances to 'labels', it's repeatedly adding the container you are adding it to (probably the Page instance). The method 'add()' doesn't return the component being added, it returns the container you are adding the components into.
Try changing it to:
Label label = new Label("usernameLabel", usernameLabel);
add(label);
labels.add(label);

Related

iText 7 pdhHtml keep table rows together

I am new in iText 7, i am developing a spa project (asp.net, c#, and angularjs), where i need to implement a report for existing html page.I found iText 7 (.Net) has a easy way to implement it. Using below code of line, that's return me a byte array and i can easily show in browser as pdf also can download.
var memStream = new MemoryStream();
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.SetFontProvider(fontProvider); converterProperties.SetBaseUri(System.AppDomain.CurrentDomain.BaseDirectory);
HtmlConverter.ConvertToPdf(htmlText, memStream, converterProperties);
In my raw html there has some html tables (every table has some particular rows) and i want to keep them in a page (i mean if table rows not fit in a single page then start from next page). I got a solution like below
Paragraph p = new Paragraph("Test");
PdfPTable table = new PdfPTable(2);
for (int i = 1; i < 6; i++) {
table.addCell("key " + i);
table.addCell("value " + i);
}
for (int i = 0; i < 40; i++) {
document.add(p);
}
// Try to keep the table on 1 page
table.setKeepTogether(true);
document.add(table);
But in my case i cannot implement like that way because content already exist in html tables (in my existing html page).
Advance thanks, if anyone can help me.
This can easily be done using a custom TagWorkerFactory and TableTagWorker class.
Take a look at the code samples below.
The first thing we should do is create a custom TableTagWorker that tells iText to keep the table together. We do this using the code you've mentioned: table.setKeepTogether(true).
class CustomTableTagWorker extends TableTagWorker{
public CustomTableTagWorker(IElementNode element, ProcessorContext context) {
super(element, context);
}
#Override
public void processEnd(IElementNode element, ProcessorContext context) {
super.processEnd(element, context);
((com.itextpdf.layout.element.Table) getElementResult()).setKeepTogether(true);
}
}
As you can see the only thing we changed on our custom TableTagWorker is the fact that it has to keep the table together.
The next step would be to create a custom TagWorkerFactory that maps our CustomTableTagWorker to the table tag in HTML. We do this like so:
class CustomTagWorkerFactory extends DefaultTagWorkerFactory{
#Override
public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
if (tag.name().equalsIgnoreCase("table")) {
return new CustomTableTagWorker(tag, context); // implements ITagWorker
}
return super.getCustomTagWorker(tag, context);
}
}
All we do here is tell iText that if it finds a table tag it should pass the element to the CustomTableTagWorker, in order to be converted to a PDF object (where setKeepTogether == true).
The last step is registering this CustomTagWorkerFactory on our ConverterProperties.
ConverterProperties converterProperties = new ConverterProperties();
converterProperties.setTagWorkerFactory(new CustomTagWorkerFactory());
HtmlConverter.convertToPdf(HTML, new FileOutputStream(DEST), converterProperties);
Using these code samples I was able to generate an output PDF where tables, if small enough to render on an entire page, will never be split across multiple pages.
I had a similar issue of trying to keep together content within a div. I applied the following css property and this kept everything together. This worked with itext7 pdfhtml.
page-break-inside: avoid;

GWT image click handler that changes size of image

I would like to add a click handler to an image that changes the size of the image. The BlobStore allows one to easily change the size of an image by changing the suffix of the URL, as "=s128" will change the image to 128 pixels in the line below:
im.setUrl(thing.get(i)+"=s128");
I want to use this feature to change the size of an image after it is clicked; in this example to change back to its original size, like:
//-- when clicked, do this:
im.setUrl(thing.get(i));
and I thought the following code would do it for a group of images:
for (int i=0; i<thing.size(); i++){
final Image im = new Image();
im.setUrl(thing.get(i)+"=s128");
im.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event){
im.setUrl(response.get(i));
}
});
htmlpanel.add(im,"imageGrid");
}
But the second "setUrl" line gives me this error:
Multiple markers at this line
- Cannot refer to a non-final variable response inside an inner class defined in a different method
- Cannot refer to a non-final variable i inside an inner class defined in a different method
How can I do this? Thanks.
response and i variables should be final. That why compiler can't compile this code. But you can't make ifinal because you are incrementing it in in for cycle. So you'll have to copy it into some final variable:
for (int i = 0; i < thing.size(); i++){
final Image im = new Image();
final int index = i; //here
im.setUrl(thing.get(i) + "=s128");
im.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
im.setUrl(response.get(index ));
}
});
htmlpanel.add(im, "imageGrid");
}
But the best solution will be to create special click handler class, which will set a specific URL to specific Image.
UPDATE
This structure:
new ClickHandler() {
public void onClick(ClickEvent event) {
im.setUrl(response.get(index ));
}
}
is called an anonymous class. If it needs to access some variable/parameter in method which defines it, such variable/parameter have to be final.

Using LINQ, how do you get all label controls

I want to get a collection of all label controls that are part of a user control. I have the following code:
var labelControls = from Control ctl in this.Controls
where ctl.GetType() == typeof(Label)
select ctl;
but the result is zero results.
Please assist. Thanks.
Edit
I have also tried the following code without success.
this.Controls
.OfType<Label>()
.Where(ctl => ctl.ID.Contains("myPrefix"))
.ToList()
.ForEach(lbl => lbl.ForeColor = System.Drawing.Color.Black);
Again, without success.
Are you sure that the control whose child controls you are parsing actually directly contains Label controls? I suspect that it is a child of the main control that is hosting the labels, in which case, you need to recursively search through the UI tree to find the labels.
Something like:
public static IEnumerable<Label> DescendantLabels(this Control control)
{
return control.Controls.DescendantLabels();
}
public static IEnumerable<Label> DescendantLabels(this ControlCollection controls)
{
var childControls = controls.OfType<Label>();
foreach (Control control in controls)
{
childControls = childControls.Concat(control.DescendantLabels());
}
return childControls;
}
Controls.OfType<Label>() - thats all
For nested controls
public static class ext
{
public static List<Label> GetLabels(this Control control)
{
var chList = control.Controls.OfType<Label>().ToList();
chList.AddRange(((IEnumerable<Control>)control.Controls)
.SelectMany(c => c.GetLabels()));
return chList;
}
}
var labelControls = this.Controls.OfType<Label>();

Using DataObjectTypeName in DataObjectSource

The functionality I am trying to use is:
- Create a ObjectDataSource for selection and updating controls on a web page (User Control).
- Use the DataObjectTypeName to have an object created that would send the data to an UpdateMethod.
- Before the values are populated in the DataObjectTypeName’s object, I would like to pre-populate the object so the unused items in the class are not defaulted to zeros and empty strings without me knowing whether the zero or default string was set by the user or by the application.
I cannot find a way to pre-populate the values (this was an issue back in 2006 with framework 2.0). One might ask “Why would anyone need to pre-populate the object?”. The simple answer is: I want to be able to randomly place controls on different User Controls and not have to be concerned with which UpdateMethod needs to handle which fields of an object.
For Example, let’s say I have a class (that reflects a SQL Table) that includes the fields: FirstName, LastName, Address, City, State, Zip. I may want to give the user the option to change the FirstName and LastName and not even see the Address, City, State, Zip (or vice-versa). I do not want to create two UpdateMethods where one handled FirstName and LastName and the other method handles the other fields. I am working with a Class of some 40+ columns from multiple tables and I may want some fields on one screen and not another and decide later to change those fields from one screen to another (which breaks my UpdateMethods without me knowing).
I hope I explained my issue well enough.
Thanks
This is hardly a solution to the problem, but it's my best stab at it.
I have a GridView with its DataSourceID set to an ObjectDataSource.
Whenever a row is updated, I want the property values in the object to be selectively updated - that is - only updated if they appear as columns in the GridView.
I've created the following extension:
public static class GridViewExtensions
{
public static void EnableLimitUpdateToGridViewColumns(this GridView gridView)
{
_gridView = gridView;
if (_gridView.DataSourceObject != null)
{
((ObjectDataSource)_gridView.DataSourceObject)
.Updating += new ObjectDataSourceMethodEventHandler(objectDataSource_Updating);
}
}
private static GridView _gridView;
private static void objectDataSource_Updating(object sender, ObjectDataSourceMethodEventArgs e)
{
var newObject = ((object)e.InputParameters[0]);
var oldObjects = ((ObjectDataSource)_gridView.DataSourceObject).Select().Cast<object>();
Type type = oldObjects.First().GetType();
object oldObject = null;
foreach (var obj in oldObjects)
{
if (type.GetProperty(_gridView.DataKeyNames.First()).GetValue(obj, null).ToString() ==
type.GetProperty(_gridView.DataKeyNames.First()).GetValue(newObject, null).ToString())
{
oldObject = obj;
break;
}
}
if (oldObject == null) return;
var dynamicColumns = _gridView.Columns.OfType<DynamicField>();
foreach (var property in type.GetProperties())
{
if (dynamicColumns.Where(c => c.DataField == property.Name).Count() == 0)
{
property.SetValue(newObject, property.GetValue(oldObject, null), null);
}
}
}
}
And in the Page_Init event of my page, I apply it to the GridView, like so:
protected void Page_Init()
{
GridView1.EnableLimitUpdateToGridViewColumns();
}
This is working well for me at the moment.
You could probably apply similar logic to other controls, e.g. ListView or DetailsView.
I'm currently scratching my head to think of a way this can be done in a rendering-agnostic manner - i.e. without having to know about the rendering control being used.
I hope this ends up as a normal feature of the GridView or ObjectDataSource control rather than having to hack it.

Cascading to a auto completing text box

I have a web page where the user will enter their address. They will select their country and region in cascading drop down lists. I would like to provide an auto completing textbox for their city, but I want to be context sensitive to the country and region selections. I would have just used another cascading drop down list, however the number of cities exceeds the maximum number of list items.
Any suggestions or cool code spinets out there that may help me out?
I just found the following blog post that looks at least close to what you want.
They manage it using the following javascript functions:
function initCascadingAutoComplete() {
var moviesAutoComplete = $find('autoCompleteBehavior1');
var actorsAutoComplete = $find('autoCompleteBehavior2');
actorsAutoComplete.set_contextKey(moviesAutoComplete.get_element().value);
moviesAutoComplete.add_itemSelected(cascade);
// setup initial state of second flyout
if (moviesAutoComplete.get_element().value) {
actorsAutoComplete.get_element().disabled = false;
} else {
actorsAutoComplete.get_element().disabled = true;
actorsAutoComplete.get_element().value = "";
}
}
function cascade(sender, ev) {
var actorsAutoComplete = $find('autoCompleteBehavior2');
actorsAutoComplete.set_contextKey(ev.get_text());
actorsAutoComplete.get_element().value = '';
if (actorsAutoComplete.get_element().disabled) {
actorsAutoComplete.get_element().disabled = false;
}
}
Sys.Application.add_load(initCascadingAutoComplete);
Calling the cascade function on the add_itemSelected method of the parent control for the cascading behaviour.
They cascade the contents of one auto complete extender into another, rather than taking a cascading drop down list, but hopefully you can reuse some of the ideas.

Resources