Using Components
Componenten zijn de bouwstenen van webforJ-toepassingen. Of je nu gebruikmaakt van ingebouwde componenten zoals Button en TextField, of werkt met aangepaste componenten die door jouw team worden geleverd, de manier waarop je met hen interactie hebt, volgt hetzelfde consistente model: je configureert eigenschappen, beheert de status en stelt componenten samen in lay-outs.
Deze gids richt zich op die dagelijkse activiteiten: niet op de interne werking van componenten, maar op hoe je in de praktijk dingen gedaan krijgt met ze.
Component eigenschappen
Elke component exposeert eigenschappen die de inhoud, uitstraling en het gedrag ervan beheersen. De meeste hiervan hebben specifieke, getypte Java-methoden (setText(), setTheme(), setExpanse(), enzovoort), wat de primaire manier is waarop je componenten in webforJ configureert. De onderstaande secties behandelen de eigenschappen en methoden die breed van toepassing zijn op componenttypen.
Tekstinhoud
De setText()-methode stelt de zichtbare tekst van een component in als letterlijke tekens, zoals het bijschrift op een Button of de inhoud van een Label. Voor invoercomponenten zoals TextField, gebruik in plaats daarvan setValue() om de huidige waarde van het veld in te stellen.
Button button = new Button();
button.setText("Klik Hier");
Label label = new Label();
label.setText("Status: gereed");
TextField field = new TextField();
field.setValue("Initiële waarde");
Markup geschreven met setText() verschijnt als die tekens en wordt nooit uitgevoerd, wat voorkomt dat tekst die afkomstig is van gebruikersinvoer of externe gegevens wordt geïnterpreteerd als live markup.
// Wordt weergegeven als de letterlijke tekens "<b>Status: gereed</b>"
component.setText("<b>Status: gereed</b>");
<html>-tagEerdere versies van webforJ behandelden een waarde die in <html> is gewrapt en naar setText() wordt gestuurd als HTML. Dit gedrag is verouderd en zal worden verwijderd in webforJ 27.00.
De eerste keer dat een waarde die in <html> is gewrapt setText() bereikt, wordt er een waarschuwing gelogd die de component en de aanroepplaats benoemt, zodat de aanroep kan worden verplaatst naar setHtml().
Om vooraf de standaard van webforJ 27.00 aan te nemen, stel webforj.legacyHtmlInText in op false. In een Spring-app wordt dezelfde waarde ingesteld via webforj.legacy-html-in-text.
// webforj.legacyHtmlInText = true (standaard)
component.setText("<html><b>Status: gereed</b></html>"); // rendert vetgedrukt
// webforj.legacyHtmlInText = false
component.setText("<html><b>Status: gereed</b></html>"); // toont de tekens <b>Status: gereed</b>
HTML renderen
Sommige componenten ondersteunen ook setHtml() voor gevallen waarin je inline HTML-markup in de inhoud moet weergeven:
Div container = new Div();
container.setHtml("<strong>Vetgedrukte tekst</strong> en <em>cursieve tekst</em>");
Als voorzorgsmaatregel tegen cross-site scripting (XSS)-aanvallen, gebruik alleen setHtml() met inhoud die je direct beheert.
HTML-attributen
De meeste configuratie in webforJ gebeurt via getypte Java-methoden in plaats van ruwe HTML-attributen. setAttribute() is echter handig voor het doorgeven van toegankelijkheidsattributen die geen specifieke API hebben:
Button button = new Button("Verzenden");
button.setAttribute("aria-label", "Verzend het formulier");
button.setAttribute("aria-describedby", "form-hint");
Niet alle componenten ondersteunen willekeurige attributen. Dit hangt af van de onderliggende implementatie van de component.
Component-ID's
Je kunt een ID toewijzen aan het HTML-element van een component met setAttribute():
Button submitButton = new Button("Verzenden");
submitButton.setAttribute("id", "submit-btn");
TextField emailField = new TextField("E-mail");
emailField.setAttribute("id", "email-input");
DOM-ID's worden vaak gebruikt voor testselectoren en CSS-doelstellingen in je stijlen.
In tegenstelling tot CSS-klassen moeten ID's uniek zijn binnen je app. Als je meerdere componenten wilt targeten, gebruik dan addClassName() in plaats daarvan.
webforJ kent ook automatisch identificerende nummers toe aan componenten intern. De serverzijde ID (toegankelijk via getComponentId()) wordt gebruikt voor framework tracking, terwijl de clientzijde ID (toegankelijk via getClientComponentId()) wordt gebruikt voor communicatie tussen client en server. Deze zijn apart van het DOM id attribuut dat je instelt met setAttribute().
Styling
Drie methoden dekken de meeste stylingbehoeften: setStyle() voor individuele CSS-eigenschap waarden, en addClassName() en removeClassName() om CSS-klassen toe te passen of te verwijderen die in je stijlen zijn gedefinieerd. Gebruik setStyle() voor kleine of eenmalige stylingaanpassingen, en gebruik CSS-klassen om grotere of herbruikbare styling toe te passen.
Div container = new Div();
container.setStyle("padding", "20px");
if (isHighPriority) {
container.setStyle("border-left", "4px solid red");
}
Button button = new Button("Toggle");
button.addClassName("primary", "large");
if (isLoading) {
button.addClassName("loading");
}
Componentstatus
Naast inhoud en uiterlijk hebben componenten status eigenschappen die bepalen of ze zichtbaar zijn en of ze reageren op gebruikersinteractie. De twee meest gebruikte zijn setVisible() en setEnabled().
setVisible() beheert of de component al dan niet in de UI wordt weergegeven. setEnabled() beheert of het input of interactie accepteert terwijl het zichtbaar blijft. In de meeste gevallen is uitschakelen te verkiezen boven verbergen: een uitgeschakelde knop communiceert nog steeds dat een actie bestaat, maar nog niet beschikbaar is, wat minder verwarrend is dan wanneer deze verschijnt en verdwijnt.
// Toon een extra veld wanneer een selectievakje is aangevinkt
TextField advancedField = new TextField("Geavanceerde instelling");
advancedField.setVisible(false);
CheckBox enableAdvanced = new CheckBox("Toon geavanceerde instellingen");
enableAdvanced.addValueChangeListener(e -> advancedField.setVisible(e.getValue()));
// Schakel een knop alleen in wanneer het vereiste veld een waarde heeft
Button submitButton = new Button("Verzenden");
submitButton.setEnabled(false);
TextField nameField = new TextField("Naam");
nameField.addValueChangeListener(e -> submitButton.setEnabled(!e.getValue().isBlank()));
setVisible(false) en setEnabled(false) beïnvloeden alleen de UI. Ze voorkomen niet dat een vastberaden gebruiker de onderliggende actie via de browser of een gemaakte aanvraag aanroept, dus reken nooit op hen om gevoelige bewerkingen te beschermen. Handhaaf altijd toegangscontrole op de server. Zie Uitgeschakeld en verborgen zijn geen beveiliging voor meer details.
Het volgende aanmeldformulier demonstreert setEnabled() in de praktijk. De inlogknop blijft uitgeschakeld totdat beide velden inhoud hebben, waardoor het duidelijk is voor de gebruiker dat invoer vereist is voordat hij verder kan:
Toon Code
- ConditionalStateView.java
- conditionalstate.css
Werken met containers
In webforJ wordt de lay-out beheerd door containers, die componenten bevatten en bepalen hoe ze zijn gerangschikt. Je plaatst kindercomponenten niet handmatig; in plaats daarvan voeg je ze toe aan een container en configureer je de lay-out eigenschappen van die container.
Componenten toevoegen
Alle containers bieden een add()-methode. Je kunt componenten één voor één of allemaal tegelijk doorgeven:
FlexLayout container = new FlexLayout();
container.add(new Button("Klik Hier"));
TextField nameField = new TextField("Naam");
TextField emailField = new TextField("E-mail");
Button submitButton = new Button("Verzenden");
container.add(nameField, emailField, submitButton);
Lay-out opties
FlexLayout is de primaire lay-outcontainer in webforJ en dekt de meeste gebruiksscenario's: rijen, kolommen, uitlijning, ruimte, en wikkeling. Voor complexere arrangementen zoals CSS Grid of aangepaste positionering kun je CSS rechtstreeks toepassen via setStyle() of addClassName() op elke containercomponent. Zie de FlexLayout documentatie voor het volledige scala aan lay-out opties.
Secties tonen en verbergen
Een veel voorkomende toepassing van setVisible() in containers is het onthullen van extra UI alleen wanneer het relevant is. Dit houdt de interface gefocust en vermindert visuele rommel. In plaats van naar een nieuwe weergave te navigeren, kun je een sectie van de huidige lay-out tonen als directe reactie op gebruikersinvoer.
Het volgende instellingenpaneel demonstreert dit: basis notificatievoorkeuren zijn altijd zichtbaar, en een sectie met geavanceerde opties verschijnt alleen wanneer de gebruiker hierom vraagt. De knop opslaan wordt geactiveerd zodra een instelling wordt gewijzigd:
Toon Code
- ProgressiveDisclosureView.java
- progressivedisclosure.css
Containerbeheer
Gebruik remove() en removeAll() om componenten uit een container te halen tijdens runtime:
FlexLayout container = new FlexLayout();
Button tempButton = new Button("Tijdelijk");
container.add(tempButton);
container.remove(tempButton);
container.removeAll();
Dit is handig wanneer je de inhoud volledig moet vervangen, zoals het wisselen van een laadindicator voor de geladen gegevens.
Formuliervalidatie
Het coördineren van meerdere componenten om een verzendactie te blokkeren is een veelvoorkomend pattern in webforJ UI's. Het basisidee is dat elk invoerveld een luisteraar registreert, en telkens wanneer een waarde verandert, evalueert het formulier opnieuw of aan alle criteria is voldaan en werkt de verzendknop dienovereenkomstig bij.
Het onderstaande voorbeeld laat dit handmatig inrichten, zodat je kunt zien hoe componentstatus en evenementluisteraars samenwerken. Het is niet de aanbevolen aanpak voor echte formulieren: handmatige luisterlogica wordt moeilijk te onderhouden naarmate formulieren groeien, en het verbindt je componenten niet met een onderliggend datamodel.
Voor productieformulieren gebruik je databinding. Dit dekt validatie, tweezijdige synchronisatie tussen componenten en je model, en waarde transformatie via BindingContext. Het handmatige patroon dat hier wordt getoond, is alleen ter illustratie.
In dit contactformulier mag het naamveld niet leeg zijn, moet de e-mail een @-symbool bevatten en moet het bericht minstens 10 tekens lang zijn:
Toon Code
- FormValidationView.java
- formvalidation.css
Dynamische inhoudsupdates
Componenten hoeven niet in een vaste staat te blijven nadat ze zijn gemaakt. Je kunt tekst bijwerken, CSS-klassen verwisselen en de ingeschakelde status op elk moment in reactie op app-gebeurtenissen wijzigen. Een veelvoorkomend voorbeeld is het geven van feedback tijdens een langdurige taak:
Label statusLabel = new Label("Gereed");
Button startButton = new Button("Start Proces");
startButton.onClick(event -> {
startButton.setEnabled(false);
statusLabel.setText("Verwerken...");
statusLabel.addClassName("processing");
performTask(() -> {
statusLabel.setText("Voltooid");
statusLabel.removeClassName("processing");
statusLabel.addClassName("success");
startButton.setEnabled(true);
});
});
Het uitschakelen van de knop terwijl de taak wordt uitgevoerd voorkomt dubbele indieningen, en het bijwerken van het label houdt de gebruiker op de hoogte van wat er gebeurt.
ComponentLifecycleObserver
De ComponentLifecycleObserver-interface stelt je in staat om componentlevenscyclus gebeurtenissen van buiten de component zelf te observeren. Dit is nuttig wanneer je moet reageren op een component die wordt gemaakt of vernietigd zonder de implementatie ervan te wijzigen. Je kunt het bijvoorbeeld gebruiken om een register van actieve componenten bij te houden of externe middelen vrij te geven wanneer een component wordt verwijderd.
Basisgebruik
Roep addLifecycleObserver() aan op een component om een callback te registreren. De callback ontvangt de component en de levenscyclus gebeurtenis:
Button button = new Button("Kijk Naar Mij");
button.addLifecycleObserver((component, event) -> {
switch (event) {
case CREATE:
System.out.println("Button is gemaakt");
break;
case DESTROY:
System.out.println("Button is vernietigd");
break;
}
});
Patroon: Hulpbronregister
De DESTROY-gebeurtenis is bijzonder nuttig voor het automatisch synchroniseren van een register. In plaats van componenten handmatig te verwijderen wanneer ze niet langer nodig zijn, laat je de component zelf het register op de hoogte stellen:
public class ResourceRegistry {
private final Map<String, Component> activeComponents = new ConcurrentHashMap<>();
public void track(Component component, String name) {
activeComponents.put(name, component);
component.addLifecycleObserver((comp, event) -> {
if (event == ComponentLifecycleObserver.LifecycleEvent.DESTROY) {
activeComponents.remove(name);
}
});
}
}
Patroon: Coördinatie van componenten
Een coördinatorklasse die een set gerelateerde componenten beheert, kan dezelfde aanpak gebruiken om zijn interne lijst nauwkeurig te houden:
public class FormCoordinator {
private final List<DwcComponent<?>> managedComponents = new ArrayList<>();
public void manage(DwcComponent<?> component) {
managedComponents.add(component);
component.addLifecycleObserver((comp, event) -> {
if (event == ComponentLifecycleObserver.LifecycleEvent.DESTROY) {
managedComponents.remove(comp);
}
});
}
public void disableAll() {
managedComponents.forEach(c -> c.setEnabled(false));
}
}
Wanneer te gebruiken
Gebruik ComponentLifecycleObserver voor:
- Het bouwen van componentregisters
- Het implementeren van logging of monitoring
- Het coördineren van meerdere componenten
- Het opruimen van externe middelen
Voor het uitvoeren van code nadat een component aan de DOM is toegevoegd, zie whenAttached() in de Composing Components gids.
Gebruikersgegevens
Componenten kunnen willekeurige serverzijde gegevens dragen via setUserData() en getUserData(). Beide methoden nemen een sleutel om de gegevens te identificeren. Dit is nuttig wanneer je domeinobjecten of context met een component wilt associëren zonder een aparte lookup-structuur te beheren.
Button button = new Button("Verwerken");
button.setUserData("context", new ProcessingContext(userId, taskId));
button.onClick(event -> {
ProcessingContext context = (ProcessingContext) button.getUserData("context");
processTask(context.getUserId(), context.getTaskId());
});
Aangezien gebruikersgegevens nooit naar de client worden verzonden, kun je gevoelige informatie of grote objecten veilig opslaan zonder de netwerkverkeer te beïnvloeden.