In my Vaadin 7 application I have to add Delete button, but this button should be only accessible to an authorized person.
I have added the button with a following code:
if (canRemove()) {
layout.addComponent(createRemoveButton());
}
Also I have added a listener to this button:
button.addClickListener(e -> {
//some logic
});
Do I need to add one more condition inside of this listener:
button.addClickListener(e -> {
if (canRemove()) {
//some logic
}
});
or this condition is redundant and I can avoid it ?
Summarizing the comments on the question:
It's redundant, no button, no click event. Alternative is hiding the button like button.setVisible(isAuthorized(user)) if not authorized.
Related
I have a grid with several columns. For three columns i used the column renderer. Each of the columns contains one button.
If i click one of those buttons, i want to replace the three buttons in that specific row with two other buttons. All the other rows should not be affected. Is this possible in a Vaadin grid?
Components in different columns don't know each other, as they are all defined in a separate scope (in the componentRenderer of their own column. You cannot define the Button outside of the componentRenderer as you found out in another question today). So the "obvious" solution won't work, where you add a clickListener on the Button to directly change the other buttons.
If you had one column with 3 Buttons inside then this would be much easier.
There is a way, but I see this more as a hack than as a solution. Because you need some extra implementation in the item class for this to work.
In the ComponentRenderer, you can add an if-statement where you look at some value of the item. In one case, you'll render button 1, in the other case you'll render the other button. And in the click listeners of the button you change that value in the item and refresh the dataprovider, so the componentRenderer is invoked again. It will now see the value on the item has changed, therefore displaying some other Button.
Here is some code to show what I mean:
// grid item class
public class Foo {
private boolean buttonPressed = false;
public Foo(){
}
public isButtonPressed(){
return buttonPressed;
}
public setButtonPressed(boolean buttonPressed){
this.buttonPressed = buttonPressed;
}
}
// adding of button columns
// do this 3 times for a test of your scenario.
grid.addComponentColumn(item -> {
if(!item.isButtonPressed()){
return new Button("Before Button was Pressed", click -> {
item.setButtonPressed(true);
grid.getDataProvider().refresh(item);
});
} else {
return new Button("Button was Pressed", click -> {
item.setButtonPressed(false);
grid.getDataProvider().refresh(item);
})
}
})
How can I acheive this in Vaadin.
// inside myButton click event
myButton.setEnabled(false);
doMyActionThatTakeSomeTime();
myButton.setEnabled(true);
Inside the event, the button is never disabled because the UI is not refresh.
What would be the best practice to do this in Vaadin 11 (or 10) ?
force view to refresh ? (how?)
put my action inside a Thread ? (how ?)
Edit SOLUTION - How to make it work with Thread
So far, example with Thread (working):
#Push
#Route(value = "secured")
public class MainView extends VerticalLayout
[ ... ]
// inside click event
UI ui = UI.getCurrent();
new Thread(() -> {
ui.access(() -> {
goButton.setEnabled(false);
ui.push();
});
doMyActionThatTakeSomeTime();
ui.access(() -> {
goButton.setEnabled(true);
ui.push();
});
}).start();
Sounds like the "Asynchronous updates" chapter in the docs explains what you want: https://vaadin.com/docs/v11/flow/advanced/tutorial-push-access.html . Basically: run doMyActionThatTakeSomeTime() in a separate background thread, then re-enable the button once the thread completes and Server Push will make sure the UI state is correctly updated.
This is frequently asked topic, there is also another answer here: How to dismiss Vaadin 8 confirmation dialog while performing lengthy operation Doing asynchronous updates work in Vaadin 8 and Vaadin 10+ in similar manner.
In Vaadin 8, there’s a Button::setDisableOnClick() method for this exact purpose.
That should probably be reintroduced in the newer versions as well.
For me the simplest way is this:
Button btnAction = new Button("Action");
btnAction.setDisableOnClick(true);
btnAction.addClickListener(e -> {
try {
for (int i = 0; i < 900000; i++) {
System.out.println(i);
}
} finally {
btnAction.setEnabled(true);
}
});
A better way of doing it:
UI ui = UI.getCurrent();
ui.access( () -> {
// disable button
goButton.setEnabled(false);
ui.push();
doMyActionThatTakeSomeTime();
// enable
goButton.setEnabled(true);
ui.push();
});
I have a tabpanel and have many childs. Each are closable. I want to remove the tabpanel itself when there are no children.
listeners: {
close: function(element) {
var detailTabPanel = element.up('DetailTabPanel');
if(detailTabPanel.items.length <= 1)
{
detailTabPanel.destroy();
}
}
}
I have written code like above for close action. But i get error like
Uncaught TypeError: Cannot read property 'get' of null DetailTabPanel is the tabpanel.
Almost there! Try it like this:
listeners: {
remove: function(tabpanel, child, eOpts) {
if (tabpanel.items.length === 0) {
tabpanel.destroy();
}
}
}
See Fiddle here: https://fiddle.sencha.com/#fiddle/1fo2
You don't have to do callParent inside a listener.
You're using the wrong event. Rather than listening for the close event of the children (which is called after the tab is removed from the panel), you want to listen for the remove event on the tab panel itself.
I have a jquery mobile form with several radio inputs whit the options "DS", "NO" and "YES". I want when I click a button it simulates a click on the "YES" option of all radio buttons.
I use this code:
$("#btn-all-yes").click(function(){
$(".replay-yes").each(function(index, element){
$(element).trigger("click");
//$(element).click();
});
});
But I need to do click two times in the button to achieve the desired result. If I put the line '$(element).trigger("click")' two times it works, but I think it should work with a single call to the click event.
You can see all the code at http://jsfiddle.net/qwLPH/7/
You need to change its' status using .prop and then refresh it .checkboxradio('refresh').
Working demo
Update - Uncheck other buttons
$("#btn-all-yes").click(function () {
$('[data-role="controlgroup"]').find("[type=radio]").each(function () {
if ($(this).hasClass('replay-yes')) {
$(this).prop('checked', true).checkboxradio("refresh");
} else {
$(this).prop('checked', false).checkboxradio("refresh");
}
});
});
Old answer
$("#btn-all-yes").click(function(){
$(".replay-yes").each(function(index, element){
$(element).prop('checked', true).checkboxradio("refresh");
});
});
Reference
Similar issue
Try to initialize the click on page load:
$(".replay-yes").each(function (index, element) {
$(element).trigger("click");
//$(element).click();
}).click();
//-^^^^^^^----------this way
Tryout in fiddle here
It seems like this should be very easy, but I'm missing something. I have a custom Element:
public class PostSummaryElement:StyledMultilineElement,IElementSizing
When the element's accessory is clicked on, I want to push a view onto the stack. I.e. something like this:
this.AccessoryTapped += () => {
Console.WriteLine ("Tapped");
if (MyParent != null) {
MyParent.PresentViewController(new MyDemoController("Details"),false,null);
}
};
Where MyDemoController's gui is created with monotouch.dialog.
I'm just trying to break up the gui into Views and Controlls, where a control can push a view onto the stack, wiat for something to happen, and then the user navigates back to the previous view wich contains the control.
Any thought?
Thanks.
I'd recommend you not to hardcode behavior in AccessoryTapped method, because the day when you'll want to use that component in another place of your project is very close. And probably in nearest future you'll need some another behavior or for example it will be another project without MyDemoController at all.
So I propose you to create the following property:
public Action accessoryTapped;
in your element and its view, and then modify your AccessoryTapped is that way:
this.AccessoryTapped += () => {
Console.WriteLine ("Tapped");
if (accessoryTapped != null) {
accessoryTapped();
}
};
So you'll need to create PostSummaryElement objects in following way:
var myElement = new PostSummaryElement() {
accessoryTapped = someFunction,
}
...
void someFunction()
{
NavigationController.PushViewController (new MyDemoController("Details"), true);
}