After implementing nested layouts i faced the problem with rendering component containing grid. The analysis shows that is present in html but it has display-block attributes and the grid is never visible.
I read the similar question (Vaadin 14 - Grid not Displaying/Populating When Used in Nested Layout) but the suggestions listed there brought me no result.
Here comes my code:
MainLayout.kt:
#Theme(value = Material::class, variant = Material.DARK)
class MainLayout : Composite<Div>(), RouterLayout {
//Component to delegate content through.
private val mainContent: Div = Div()
private val layout = VerticalLayout(
Span("from MainLayout top"),
mainContent,
Span("from MainLayout bottom"))
override fun showRouterLayoutContent(hasElement: HasElement) {
Objects.requireNonNull(hasElement)
Objects.requireNonNull(hasElement.element)
mainContent.removeAll()
mainContent.element.appendChild(hasElement.element)
}
init {
content.add(layout)
}
}
LayoutWithMenuBar.kt:
#ParentLayout(value = MainLayout::class)
class LayoutWithMenuBar : Composite<Div>(), RouterLayout {
private val mainContent: Div = Div()
private val menuBar = HorizontalLayout(
RouterLink("Home", MainView::class.java),
RouterLink("Tprojects", TProjectDashboard::class.java),
RouterLink("ViewA", ViewA::class.java),
RouterLink("ViewB", ViewB::class.java))
private val root = VerticalLayout(menuBar, mainContent)
override fun showRouterLayoutContent(hasElement: HasElement) {
Objects.requireNonNull(hasElement)
Objects.requireNonNull(hasElement.element)
mainContent.removeAll()
mainContent.element.appendChild(hasElement.element)
}
init {
content.add(root)
}
}
and a component containing grid - TProjectDashboard:
#Route("dashboard/tproject", layout = LayoutWithMenuBar::class)
class TProjectDashboard(#Autowired val tprojectService: TProjectService): VerticalLayout() {
var tprojectGrid = Grid<TProject>(TProject::class.java)
init {
//tprojectGrid
tprojectGrid.setColumns(
TProject::tprojectUuid.name,
TProject::tprojectClass.name,
TProject::tprojectState.name,
TProject::tentityState.name,
TProject::size.name)
tprojectGrid.setItems(tprojectService.findAll())
tprojectGrid.setSizeFull()
tprojectGrid.setWidthFull()
tprojectGrid.setHeightFull()
add(tprojectGrid)
setSizeFull()
setHeightFull()
setWidthFull()
}
}
The same result i have when changing TProjectDashboard parent from VerticalLayout to Composite.
The nested layouts approach works well for simple components like Span and if i remove layout reference from #Route annotation i will see my grid.
Here is the screen how it looks like now:
enter image description here
Would appreciate for any hints or solutions.
Thanks in advance.
It's probably a sizing issue that unfortunately happens too often. I would start with calling setSizeFull() on the mainContent div. If that doesn't help, go through the elements in the browser devtools and try to see where the size disappears, e.g. what is the first element that has 0 width or height.
Edit: Setting setSizeFull() on all components works. I would simplify your layouts slightly, though, by changing the composites to be of type VerticalLayout. Then you can get rid of a lot of the setSizeFull() calls.
The code below is in Java as I don't have Kotlin set up, you can call getContent().setSizeFull() in MainLayout if you want it to take the full height of the page.
MainLayout
#Theme(value = Material.class, variant = Material.DARK)
public class MainLayout extends Composite<VerticalLayout> implements RouterLayout {
//Component to delegate content through.
private Div mainContent = new Div();
public MainLayout() {
getContent().add(
new Span("from MainLayout top"),
mainContent,
new Span("from MainLayout bottom"));
mainContent.setSizeFull();
}
#Override
public void showRouterLayoutContent(HasElement hasElement) {
Objects.requireNonNull(hasElement);
Objects.requireNonNull(hasElement.getElement());
mainContent.removeAll();
mainContent.getElement().appendChild(hasElement.getElement());
}
}
LayoutWithMenuBar
#ParentLayout(value = MainLayout.class)
public class LayoutWithMenuBar extends Composite<VerticalLayout> implements RouterLayout {
private Div mainContent = new Div();
private HorizontalLayout menuBar = new HorizontalLayout(
new RouterLink("Tprojects", TProjectDashboard.class));
public LayoutWithMenuBar() {
getContent().add(menuBar, mainContent);
mainContent.setSizeFull();
}
#Override
public void showRouterLayoutContent(HasElement hasElement) {
Objects.requireNonNull(hasElement);
Objects.requireNonNull(hasElement.getElement());
mainContent.removeAll();
mainContent.getElement().appendChild(hasElement.getElement());
}
}
TProjectDashboard
#Route(value = "dashboard/tproject", layout = LayoutWithMenuBar.class)
public class TProjectDashboard extends VerticalLayout {
private Grid<TProject> tprojectGrid = new Grid<>(TProject.class);
public TProjectDashboard() {
tprojectGrid.setItems(
new TProject("Erik", "Software Engineer"),
new TProject("Fia", "Kindergarden teacher"),
new TProject("Jack", "All trades")
);
add(tprojectGrid);
}
}
Related
I am trying to scroll to bottom of layout. I've got this piece of code, but it's not working
ScrollView scrollView = view.FindViewById<ScrollView>(Resource.Id.scrollViewHelper);
scrollView.FullScroll(FocusSearchDirection.Down);
A simple way is to create an Action-based runnable, passing the Action as a parameter to the runnable .
You can refer to the following code:
scrollView = FindViewById<ScrollView>(Resource.Id.scrollView1);
var runnable = new MyRunnable(async () =>
{
// Do whatever you need to do, including capturing of local vars, app/activity context, etc.
await Task.Delay(500);
scrollView.FullScroll(FocusSearchDirection.Down);
});
runnable.Run();
Code of class MyRunnable
public class MyRunnable : Java.Lang.Object, Java.Lang.IRunnable
{
readonly WeakReference<Action> actionRef;
public MyRunnable(Action action)
{
actionRef = new WeakReference<Action>(action);
}
public void Run()
{
actionRef.TryGetTarget(out Action action);
action?.Invoke();
}
}
here is a good thread about DataProvider.refreshAll() on Vaadin 8.5.1, but it doesn't seem to work this way in Vaadin 11.
I used this starter app to play around. It displays some imaginary product data in a grid.
At first, I added a refresh command to SampleCrudView:
public HorizontalLayout createTopBar() {
...
HorizontalLayout topLayout = new HorizontalLayout();
Button btn = new Button("refresh");
btn.addClickListener(event -> dataProvider.refreshAll());
topLayout.add(btn);
...
return topLayout;
}
The folks from vaadin override getId() in their ProductDataProvider like this to use it as an object identifier:
#Override
public Integer getId(Product product) {
Objects.requireNonNull(product,
"Cannot provide an id for a null product.");
return product.getId();
}
That ProductDataProvider extends ListDataProvider, which is initialized on startup with data from MockDataService, so that we always deal with the same objects. I changed that:
public class MockDataService extends DataService {
...
#Override
public synchronized List<Product> getAllProducts() {
//added ->
MockDataGenerator.resetProductCounter(); //this one sets nextProductId = 1
products = MockDataGenerator.createProducts(categories);
products.stream().forEach(p -> System.out.println(p.getId() + ", " + p.getProductName()));
//<- added
return products;
}
So now you will get new Product instances within the same ID range every time you call getAllProducts():
public class ProductDataProvider extends ListDataProvider<Product> {
...
#Override
public Stream<Product> fetch(Query<Product, SerializablePredicate<Product>> query) {
//added ->
this.getItems().clear();
this.getItems().addAll(DataService.get().getAllProducts());
//<- added
return super.fetch(query);
}
So the point is, this doesn't work - the data in the grid is still the same after "refresh" has been clicked.
Any suggestions?
Regards,
m_OO_m
This is caused by a bug that was fixed a couple a days ago. The fix will be included in the next maintenance release.
Am using Vaadin 7.3.10.
I have added a layout component inside a panel in order that
the layouts shall be scrolled if required.
However when I try to replace the layout component, the new
component adds to (is shown below) rather than replaces the
existing component - see below for code sample.
How/Can this be done?
n.b. if the layout is not contained inside the panel, the
replacement occurs correctly.
Also, I do not require to use the Navigator for this.
Thank you,
Steve...
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;
public class NewComponent extends VerticalLayout {
private VerticalLayout mainLayout = new VerticalLayout();
private Panel panel = new Panel();
public NewComponent() {
mainLayout.addComponent(new Label("Main"));
mainLayout.setSizeFull();
addComponent(mainLayout);
panel.setWidth("1000px");
panel.setHeight("500px");
panel.setContent(mainLayout);
Button button = new Button("Click Me");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
replaceComponent(mainLayout, new Label("what's wrong?"));
}
});
mainLayout.addComponent(button);
addComponent(panel);
}
}
public class TestUI extends UI {
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = TestUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
setContent(new NewComponent());
}
You have to call replaceComponent on the mainLayout and not with.
right now it looks like this:
<newComponent>
<panel>
<mainLayout>
<labelMain/>
<clickMeButton/>
</mainLayout>
</panel>
</newComponent>
then you call replaceComponent on newComponent, which will add the label like this
<newComponent>
<panel>
<mainLayout>
<labelMain/>
<clickMeButton/>
</mainLayout>
</panel>
<whatsWrongLabel/>
</newComponent>
It should look like this:
<newComponent>
<panel>
<mainLayout>
<labelMain/>
</mainLayout>
</panel>
<clickMeButton/>
</newComponent>
and then mainLayout.replaceComponent(labelMain, whatsWrongLabel).
mainLayout is not in the VerticalLayout, that's why the new component is simply added to it. You have to replace the panel's content.
Change
replaceComponent(mainLayout, new Label("what's wrong?"));
To
panel.setContent(new Label("what's wrong?"));
I would like to know if there is a binding mechanism from a viewmodel property that provides focus (the cursor to blink or something to indicate that the textedit has focus) in a specific edittext of my choice.
This is a general Mvvm question - like MVVM Focus To Textbox
Just as in the general question, in MvvmCross you could do this in some code behind in your View. For example, you could create a helper class like:
public class Helper
{
private Activity _a;
public Helper(Activity a)
{
_a = a;
}
// TODO - this should probably be a ViewModel-specific enum rather than a string
private string _focussedName;
public string FocussedName
{
get { return _focussedName; }
set
{
_focussedName = value;
var mapped = MapFocussedNameToControlName(_focussedName);
var res = _a.Resources.GetIdentifier(mapped, "id", _a.PackageName);
var view = _a.FindViewById(res);
view.RequestFocus();
}
}
private string MapFocussedNameToControlName(string value)
{
// TODO - your mapping here...
return value;
}
}
This could then be bound in the View and in OnCreate as:
private Helper _helper;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.main);
_helper = new Helper(this);
this.CreateBinding(_helper)
.For(h => h.FocussedName)
.To<MyViewModel>(x => x.FocusName)
.OneWay()
.Apply();
}
This code not tested - but should roughly work.
Do you know any components in smartgwt in order to do some like this?
I´ve done it using several componets, Labels, Camva, Img, Layouts....
Thanks
Well, I have found this option SC.showPrompt and SC.clearPrompt but I think that it´s not possible add images into of panel.
I did this in the past you can have a try
public class Attente extends Window{
private Label message = new Label();
public String getMessage() {
return message.getTitle();
}
public void setMessage(String message) {
this.message.setContents(message) ;
}
private Img image = new Img("64/Wait-icon.png",64,64);
/**
* Instantie un nouveau attente.
*/
public Attente(){
this.setTitle("Opération en cours, veuillez patienter");
this.setShowHeader(true);
this.centerInPage();
this.setAutoCenter(true);
this.setWidth(300);
this.setHeight(140);
this.setShowCloseButton(false);
this.setShowMinimizeButton(false);
this.setShowMaximizeButton(false);
VLayout layout = new VLayout();
HLayout hLayout = new HLayout();
message.setHeight(15);
message.setAlign(Alignment.CENTER);
message.setStyleName("plVersionCatalogue");
hLayout.addMember(new LayoutSpacer());
hLayout.addMember(image);
hLayout.addMember(new LayoutSpacer());
layout.addMember(new LayoutSpacer());
layout.addMember(hLayout);
layout.addMember(new LayoutSpacer());
layout.addMember(message);
this.addItem(layout);
}
}
And in the code I had a singleton instance of this class which I can use like this when I need:
MyContext.getAttente().show();
or
MyContext.getAttente().hide();