wicke 6 AjaxLink within a Form - ajax

In an application written in Wicket 6, I (as a Wicket newbie) am trying to use an AjaxLink from within a form in order to be able to update the contents of the form.
My use case is the following : through ajax i want to be able to add/remove dynamically controls (file upload controls) to the form.
When using AjaxLink, I am not able to make an ajax call in order to add a new upload file control to the form. On the other hand, when I use AjaxFallbackLink the request gets submitted to the server and a new control is submitted. The only downside in this case is that the values previously selected on the form (the country from country dropdown) are lost.
Can someone explain me how can I cleanly add/remove controls to the form, with ajax, without affecting the other values selected on the form?
Bellow is a simplified version of the form class :
private final class MyForm extends BaseForm<MyFormBean> {
private static final long serialVersionUID = -9021809835323626044L;
private List<Image> sfImages = new ArrayList<>();
private MyForm(final String id, Sample sample) {
super(id, new CompoundPropertyModel<>(new MyFormBean(sample)));
setOutputMarkupId(true);
setMarkupId(id);
setMultiPart(true);
addWithFeedbackContainerAndLabel(new CountryDropDownChoice("country").setRequired(true));
final WebMarkupContainer ajaxContainer = new AjaxUpdatableContainer("ajaxContainer");
add(ajaxContainer);
ajaxContainer.add(new ListView<Image>("sfImages", sfImages) {
#Override
public void populateItem(final ListItem<Image> listItem) {
listItem.add(new UploadImagePanel("sfImage"));
}
});
add(new AjaxLink("addSFImage")
{
private static final long serialVersionUID = 974013580329804810L;
#Override
public void onClick(AjaxRequestTarget target) {
System.out.println("Ajax magic");
MyForm.this.sfImages.add(new DynamicImage("53a4c88f78306456988af612"));
if (target != null) {
target.add(ajaxContainer);
}
}
});
Button button = new SaveButton("saveButton");
add(button);
}

Related

Access form data in ModalWindow.WindowClosedCallback()

I'm new to wicket and working on Wicket 7.Having a Modelwindow with Page which contains a Form.
When form submitted am not able to access form data in side ModalWindow.WindowClosedCallback() method.
public SamplePage(ModalWindow window, FlowDTO flowDTO) {
super();
this.window = window;
this.flowDTO = flowDTO;
add(new SampleForm("flowForm"));
finished=false;
window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
private static final long serialVersionUID = 1L;
public void onClose(AjaxRequestTarget target) {
**//want to access flowDTO here**
}
});
Can some one help me on how do I access form values inside this method.
Thank you,
S

How and Where to tell if a ViewComponent has been invoked x times in a view?

I have a ViewComponent that I need to invoke twice only! How and where can I tell the invokations count?
Currently I can use a session but I dislike using session in mvc apps! How may I achieve this?
namespace Partials.Components
{
public class MyComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
Session["invoked"]=(int)Session["invoked"]+1;
var model = new{
Website="Stack Overflow",
Url="www.http://stackoverflow.com"
};
return View("_MyComponent ", model);
}
}
}
and in my view
#Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>#Session["invoked"]</span> times</span>
You can use TempData. It persists only until the next request.
TempData["invoked"]=(int)TempData["invoked"]+1;
View:
<span>Invoked ViewComponent <span>#TempData["invoked"]</span> times</span>
Note: TempData uses session under the covers.
You can use HttpContext.Items which has the advantage of not using the session. These items are stored and shared per request, which would also fit your objective.
In your viewComponent you can add/retrieve an item as in this.Context.Items["MyComponentInvocationCount"]. Whenever the count is greater than 2 you can just return an empty content with return Content(String.Empty).
You can combine that with an extension method so you can get the count from outside that class:
[ViewComponent(Name = "MyComponent")]
public class MyViewComponent : ViewComponent
{
internal static readonly string ContextItemName = "InvocationCount";
public IViewComponentResult Invoke()
{
this.InvocationCount = this.InvocationCount + 1;
if (this.InvocationCount > 2) return Content(String.Empty);
//return your content here
return Content("Can be invoked");
}
private int InvocationCount
{
get
{
return this.Context.InvocationCount();
}
set
{
this.Context.Items[ContextItemName] = value;
}
}
}
public static class MyViewComponentExtensions
{
public static int InvocationCount(this HttpContext context)
{
var count = context.Items[MyViewComponent.ContextItemName];
return count == null ? 0 : (int)count;
}
}
Then you could use it in a view as follows:
#Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>#Context.InvocationCount()</span> times</span>
If you add the above lines 3 times in a view, you will see that the third one does not add any content.
EDIT - Using ViewComponentInvoker
I have been exploring how to implement this feature adding a custom ViewComponentInvoker.
I started by adding a new attribute that can be used to decorate ViewComponents so they are limited to a certain number of invocations per request:
public class PerRequestInvocationLimitAttribute: Attribute
{
public int PerRequestInvocationLimit { get; set; }
}
You would then create your view component as usual, the only change being adding this attribute:
[PerRequestInvocationLimit(PerRequestInvocationLimit = 2)]
public class MyViewComponent : ViewComponent
{
//implementation of view component
}
We can then create a custom IViewComponentInvoker that decorates the DefaultViewComponentInvoker.
This custom view component invoker will keep track of the number of
times a view component has been invoked in the current request.
When a view component that has the new attribute is invoked, it will only
really invoke it if the number of invocations is below the limit.
Implementing this view component invoker looks like:
public class LimitedPerRequestViewComponentInvoker : IViewComponentInvoker
{
private readonly IViewComponentInvoker _defaultViewComponentInvoker;
public LimitedPerRequestViewComponentInvoker(IViewComponentInvoker defaultViewComponentInvoker)
{
this._defaultViewComponentInvoker = defaultViewComponentInvoker;
}
public void Invoke(ViewComponentContext context)
{
if (!CanInvokeViewComponent(context)) return;
this._defaultViewComponentInvoker.Invoke(context);
}
public Task InvokeAsync(ViewComponentContext context)
{
if (!CanInvokeViewComponent(context)) return Task.WhenAll();
return this._defaultViewComponentInvoker.InvokeAsync(context);
}
private bool CanInvokeViewComponent(ViewComponentContext context)
{
// 1. Increase invocation count
var increasedCount = context.ViewContext.HttpContext.IncreaseInvocationCount(
context.ViewComponentDescriptor.ShortName);
// 2. check if there is any limit for this viewComponent, if over the limit then return false
var limitAttribute = context.ViewComponentDescriptor.Type
.GetCustomAttributes(true)
.OfType<PerRequestInvocationLimitAttribute>()
.FirstOrDefault();
if (limitAttribute != null && limitAttribute.PerRequestInvocationLimit < increasedCount)
{
return false;
}
// 3. There is no limit set or the limit has not been reached yet
return true;
}
}
It uses some extension methods to set/get the invocation count from HttpContext.Items (That you could also use in your view to get the number of times a view component was invoked)
public static class ViewComponentExtensions
{
public static int InvocationCount(this HttpContext context, string viewComponentName)
{
var count = context.Items[GetHttpContextItemsName(viewComponentName)];
return count == null ? 0 : (int)count;
}
internal static int IncreaseInvocationCount(this HttpContext context, string viewComponentName)
{
var count = context.InvocationCount(viewComponentName);
context.Items[GetHttpContextItemsName(viewComponentName)] = ++count;
return count;
}
private static string GetHttpContextItemsName(string viewComponentName)
{
return string.Format("InvocationCount-{0}", viewComponentName);
}
}
The final piece is to create a new IViewComponentInvokerFactory replacing the default one, so it creates an instance of the new custom view component invoker instead of the default one. You also need to register it on Startup.cs:
public class MyViewComponentInvokerFactory : IViewComponentInvokerFactory
{
private readonly IServiceProvider _serviceProvider;
private readonly ITypeActivatorCache _typeActivatorCache;
private readonly IViewComponentActivator _viewComponentActivator;
public MyViewComponentInvokerFactory(IServiceProvider serviceProvider, ITypeActivatorCache typeActivatorCache, IViewComponentActivator viewComponentActivator)
{
_serviceProvider = serviceProvider;
_typeActivatorCache = typeActivatorCache;
_viewComponentActivator = viewComponentActivator;
}
public IViewComponentInvoker CreateInstance(ViewComponentDescriptor viewComponentDescriptor, object[] args)
{
return new LimitedPerRequestViewComponentInvoker(
new DefaultViewComponentInvoker(_serviceProvider, _typeActivatorCache, _viewComponentActivator));
}
}
//Configure the ViewComponentInvokerFactory in Startup.ConfigureServices
services.AddTransient<IViewComponentInvokerFactory, MyViewComponentInvokerFactory>();
With all these pieces in place, you can use your view component 3 times and you will see how it will be rendered only twice:
#Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>#Context.InvocationCount("MyComponent")</span> times</span>
I prefer this solution for a few reasons:
It is based on the hooks provided by the new mvc framework.
Does not need changes to your view component, other than adding the attribute that sets the invocation limit.
It works when invoking view component asynchronously.

VAADIN 7: Navigating sub views

How would I navigate between sub-views in Vaadin UI. I want my header on the website to stay static like a master page and the content view to change using navigation. How can I do that in Vaadin.
Well you could simply design your UI with a header (and other stuff if needed) and a component that will act as a placeholder for the changing content.
Then I add a method that receives the new content to display and puts it inside the place holder.
Here is some code:
public class MyUI extends UI implements ErrorHandler {
// I usually use a layout as a place holder
private VerticalLayout content;
...
#Override
public void init(VaadinRequest request) {
...
content = new VerticalLayout();
content.setSizeFull();
final VerticalLayout layout = new VerticalLayout(header, menu, content, footer);
layout.setMargin(true);
setContent(layout);
}
public void changeContent(Component view) {
content.removeAllComponents();
content.addComponent(view);
content.setComponentAlignment(view, Alignment.MIDDLE_CENTER);
}
}
If in you application you need to support browser's bookmarks and navigation (backward and forward buttons) you'll need to use URIFragments, described on the book of vaadin.
A common way of using it is with a Navigator:
public class NavigatorUI extends UI {
Navigator navigator;
protected static final String MAINVIEW = "main";
#Override
protected void init(VaadinRequest request) {
getPage().setTitle("Navigation Example");
// Create a navigator to control the views
navigator = new Navigator(this, this);
// Create and register the views
navigator.addView("", new StartView());
navigator.addView(MAINVIEW, new MainView());
} }
Your views will need to implemente the View interface as described in the book of vaadin
And if you use Spring, you could also use an addon, like SpringVaadinIntegration or vaadin4spring to make this easier and each of them have several other advantages.

JavaFX - Get CheckBox properties from outside GUIController

In JavaFX I want to check if a checkbox is selected and I want to do this using the lookup(#id) method. However this method returns a Node, which doesn't have the isSelected() method.
The code below shows the GUIController and a class Visualize it calls, where the status of the checkbox is read. I added a solution (reading the checkbox properties in GUIController and passing them to Visualize), but this is not how I want to proceed. I whish that the checkbox status is read in Visualize, because there will be many other GUI elements that I need to read so it is more compact to pass on a single object to Visualize instead of a list precomputed in GUIController.
Thank you for suggestions!
GUI Controller:
public class GUIController implements Initializable {
#FXML private AnchorPane RootPane;
#FXML private CheckBox TextCheckBox;
#Override
public void initialize(URL url, ResourceBundle rb) {
Boolean TextCheckBoxSelected = TextCheckBox.isSelected();
Visualize visualizeInstance = new Visualize();
root3D = visualizeInstance.draw(RootPane, TextCheckBoxSelected);
/* ... */
Class called by GUIController:
public class Visualize {
public Visualize() {
//
}
public Group draw(AnchorPane RootPane, Boolean TextCheckBoxSelected) {
System.out.println(RootPane.lookup("#TextCheckBox"));
System.out.println(TextCheckBoxSelected);
/* ... */
Output:
CheckBox[id=TextCheckBox, styleClass=check-box]'Text'
true
If you really want to do it this way, just downcast the result of the lookup:
public class Visualize {
// ...
public Group draw(AnchorPane rootPane) {
CheckBox textCheckBox = (CheckBox) rootPane.lookup("#TextCheckBox");
boolean selected = textCheckBox.isSelected();
// ...
}
}
If you are doing this because you need your Visualize object to respond to changes in the CheckBox's selected state, then consider passing a BooleanProperty instead, which you can observe if you need:
public class Visualize {
private BooleanProperty selectedProperty ;
public Visualize(BooleanProperty selectedProperty) {
this.selectedProperty = selectedProperty ;
// ...
}
// ...
public Group draw() {
boolean selected = selectedProperty.get();
// ...
}
}
and
Visualize visualizeInstance = new Visualize(textCheckBox.selectedProperty());
root3D = visualizeInstance.draw();

How do I persist the value of a property across page-refreshes?

I have created a property in app.xaml ( Public Static List id {get set} )
Can i add Data (Eg: App.id.Add(user.id)) to it.
So that i can take the added data from the page and use it any navigated page (Eg: App.id[3]).
Initializing is the problem when page refreshed the data goes back to App.id[0]
Alternativ you could use the Singleton pattern here, this will ensure that the list is created and only one instance exsist.
In your App.cs file write the following:
private static List<string> _id;
public static List<string> id
{
get
{
if (_id == null)
_id = new List<string>();
return _id;
}
set
{
_id = value;
}
}
Yes you can, public properties defined in app.cs can be reached from all your pages in your app.
in your App.cs
public List<String> id = new List<string>();
// Call this method somewhere so you create some data to use...
// eg in your App() contructor
public void CreateData()
{
id.Add("ID1");
id.Add("ID2");
id.Add("ID3");
id.Add("ID4");
id.Add("ID5");
}
When you need to use it your can get the data from eg. the OnNavigateTo event handler
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Sets the data context for the page to have a list of strings
this.DataContext = ((App)Application.Current).id;
// Or you can index to the data directly
var a = ((App)Application.Current).id[2];
}

Resources