Dwie różne walidacje na jednym formie

Dwie różne walidacje na jednym formie
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

Cześć,

Mam taki formularz, który może mieć dwa stany. Zanim dojdzie do pełnego wysłania dokumentu można go zapisać. Coś na wzór maili roboczych :)

I do zapisu dokumentu roboczego potrzebne są pola np.:
Imię
Nazwisko
PESEL

ale, zeby kliknac drugi przycisk i wyslac dokument trzeba juz miec wypełnione:
Imie
Nazwisko
PESEL,
dokument tożsamości
adres

Jak to rozwiązać za pomocą jsf, primefaces?

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
0

Spring boot używa JSR-303 do walidacji. Wystarczy zatem oznaczyć pola by były walidowane w ramach odpowiednich grup.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
D3X
Tak. Używam adnotacji na polach. Stworzyłem interfejs rozszerzający Default. Ale czegoś mi brakuje. A i ważna informacja. Mam dwa commandButtony. Jeden ZAPISZ i mialby podstawową walidację mieć, a zatwierdź tę rozszerzoną.
Koziołek
Te interfejsy nie muszą rozszerzać Default. Nawet nie powinny w pewnych przypadkach, bo mogą się dziać dziwne rzeczy np. odpalanie domyślnej walidacji nie tam gdzie trzeba, albo sprzeczne reguły walidacji domyślnej.
M9
  • Rejestracja:prawie 10 lat
  • Ostatnio:prawie 6 lat
0

To można zrobić na kilka sposobów. Jednym z nich jest if'ek walidujący w akcji (na początku metody). I wysłanie message do danego przycisku (musisz zrobić binding dla UIComponent, aby wiedzieć przy którym komponencie wyświetlić message) informujący, co poszło nie tak. Po wysłaniu message przerywasz akcje: nie są spełnione warunki. Jak walidacja może być przeprowadzona w czasie akcji (czyli po kliknięciu w przycisk) to może być najprostszy sposób. Poza tym taka metoda się przydaje jak czasem trzeba zawołać jakiś WebService albo zrobić zapytanie do bazy: standardowe walidatory słabo się tutaj sprawdzają.

Podany "walidator" zadziała dopiero, gdy standardowe walidatory (np. długości pól / Bean Validation) nie wykryją błędów (cykl życia JSF).

Po if'kach wypada dopisać unit-testy, ale to nie jest problem.

edytowany 7x, ostatnio: margor90
Zobacz pozostałe 2 komentarze
M9
Wiem. Moim zdaniem ma to sens jak planujemy pisać komponenty wielokrotnego użytku. Nie do wszystkiego się nadają (szczególnie jak jakaś walidacja ma dotyczyć czegoś co jest w systemie zenętrznym np. przez WebService). Nie bądźmy tacy dogmatyczni.
Koziołek
to nie jest kwestia dogmatów, a jedynie tworzenia dobrego kodu.
M9
IMO nie wszystkie problemy są tak proste / trywialne, że mogą być zapisane pięknym kodem: przykład paskudny kod algorytmiczny na podstawie niektórych metod numerycznych. Czasem robienie przesadnej liczby abstrakcji to też bywa antipattern. Czy kod jest dobry czy nie świadczy o tym jak łatwo może być rozwijany przez obcych programistów oraz jak szybko może być przeczytany przez nie autora. Oraz jak łatwo się go testuje. Czy łatwo wykryć regresję.
Koziołek
Akurat na metodach numerycznych można zaszaleć i pokazać jak należy pisać dobry, czysty kod. Co do czytania i rozumienia to zaręczam, że odpowiednio napisany i podzielony kod zawsze jest czytelniejszy niż zagmatwany. Fajnie to opisuje Kerievsky w swojej książce.
M9
Zapoznam się z tym autorem.
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

@margor90 ok pokombinuje.

jeszcze potrzebuje pomysłu jak zrobić walidację dwóch przycisków.

np. oba są wymagane, gdy drugie nie jest wypełnione.

Czyli jeśli A wypełnione to B niewymagane. I odwrotnie :)

D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

@margor90 @Koziołek
Fragment widoku (id forma i tabów)

Kopiuj
    <h:form id="wniosekForm">
            <p:tabView id="tabView">
                <p:tab title="Wniosek" id="wniosekTab">

Fragment widoku (blok messages)

Kopiuj
                        <p:messages showDetail="true" showSummary="true"/>
Kopiuj

public void zatwierdz(WniosekDTO wniosekDTO) {
        Set<ConstraintViolation<WniosekDTO>> violations = validator.validate(wniosekDTO, ZatwierdzWniosekGroup.class);
        for (ConstraintViolation<WniosekDTO> violation : violations) {
            addErrorMessage(formIdPrefix + violation.getPropertyPath(), violation.getMessage());
            System.out.println(formIdPrefix + " " + violation.getPropertyPath() + " " + violation.getMessage());
        }
        if (violations.isEmpty()) {
            //save czegos tam
            addInfoMessage("", "success");
        } else {
            addErrorMessage("", violations.size() + " error(s)");
        }

    }

    private void addErrorMessage(String id, String msg) {
        addMessage(id, FacesMessage.SEVERITY_ERROR, "Error", msg);
    }

    private void addInfoMessage(String id, String msg) {
        addMessage(id, FacesMessage.SEVERITY_INFO, "Info", msg);
    }

    private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
        FacesMessage message = new FacesMessage(severity, summary, detail);
        FacesContext.getCurrentInstance().addMessage(clientId, message);
    }


Pola oznaczane mam mniej więcej tak:

Kopiuj
@NotNull(groups = ZatwierdzWniosekGroup.class)
    @NotBlank(groups = ZatwierdzWniosekGroup.class)
    private String nazwa= "Przykładowa wartość nazwy";

I wygląda to tak, że pojawia mi się wszystko w bloku messages, ale nie podświetla mi pól na czerwono i w bloku messages nie ma nazw pól tylko jest tak:

Kopiuj
    Errormay not be null
    Errormay not be null
    Errormust be true
    Errormust be true
    Errormust be true
    Errormay not be null
    ErrorMusi być zaznaczone
    Errormay not be empty
    Errormust be true
    Error9 error(s)

Co mam nie tak?

Jak zrobię tak:

Kopiuj
private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
        FacesMessage message = new FacesMessage(severity, summary, detail);
        FacesContext.getCurrentInstance().addMessage(clientId, message);
        UIViewRoot uiViewRoot = FacesContext.getCurrentInstance().getViewRoot();
        if (!clientId.isEmpty()) {

            UIComponent component = uiViewRoot.findComponent(clientId);
            if (component instanceof UIInput) {
                UIInput uiInput = (UIInput) component;
                uiInput.setValid(false);

            }
        }
    }

To nie działa mi potem button wyczyść :) I zostają errory.

edytowany 1x, ostatnio: D3X
M9
Wrzuć to na jakiś GitHub, bo czytanie tego w takiej formie to jest męka. W okrojonej formie to da radę to rozwiązać. Tak aby tylko zreplikować błąd.
D3X
Ok. Postaram się dzisiaj wrzucić :)
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

@margor90 może łatwiej będzie mi wytłumaczyć jaki efekt chcę uzyskać.

Otóż mam jeden formularz. I chcę zrobić dwa rodzaje walidacji:

  • podstawowy
  • rozszerzony

Jeśli kliknę commandButton "Zapisz" to sprawdza mi podstawową walidację.
Jeśli kliknę commandButton "Wyślij" to sprawdza mi walidację rozszerzoną.

Dodatkowo niektóre pola prócz wymagany/niewymagany mają takie dane jak:
PESEL, które ma być walidowany jak to PESEL :)

Jest jeszcze taka kwestia. Załóżmy, że w formularzu mamy nadawcę i odbiorcę.

Każdy z nich korzysta z modelu daneIdentyfikacyjne.
I w podstawowej walidacji wymagany jest pesel tylko dla nadawcy, a dla odbiorcy już nie. I wtedy jest lipa z adnotacjami na modelu, bo musiałbym rozdzielić modele na np. OdbiorcaDTO i NadawcaDTO i jednemu dać anotację, a drugiemu nie.

Każde odpalenie walidacji ma skutkować pojawieniem się zbiorczego podsumowania w <p:messages> i dodatkowo poszczególne pole ma być podświetlone na czerwono, ale już bez wiadomości przy polu.

Używam SpringBoot i JSF i Primefaces.

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
0

Rozdzielenie modelu jest w tym przypadku jak najbardziej OK. W swojej domenie masz byty:

  • Nadawca
  • Odbiorca

Warto zamodelować je oddzielnie ponieważ reprezentują dwie osobne rzeczy. Ma to dwie podstawowe zalety

Po pierwsze możesz traktować takie klasy jako zupełnie niezwiązane ze sobą, bo takimi są, dzięki czemu możesz swobodnie zmieniać np. walidację w jednej bez wpływu na drugą.
Po drugie otrzymujesz możliwość pisania kodu w oparciu o typy. W ten sposób już na etapie kompilacji sprawdzana jest poprawność całych przepływów i można bardzo łatwo uniknąć sytuacji gdzie np. pod adres zamieszkania wstawiasz adres zameldowania (patrz http://niebezpiecznik.pl/post/pko-wyslalo-karty-platnicze-na-zle-adresy/ )

Oczywiście pojawia się problem powtarzanego kodu. Tu z pomocą przychodzi dziedziczenie, które pozwala wynieść do nadklasy części wspólne, a w podklasach przechowywać znaczenie (nadawca, odbiorca) oraz meta konfigurację .


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

@Koziołek
To może tylko rozjaśnię o co chodzi z tym rozdzieleniem.

Załóżmy, że Odbiorca nie musi mieć wymaganego peselu. I teraz, moje modele wygladaja mniej więcej tak:

OdbiorcaDTO:

Kopiuj
private String nazwaFirmy;
private DaneTozsamosciDTO daneTozsamosciDTO;

NadwacaDTO:

Kopiuj
private String nazwaFirmy;
private DaneTozsamosciDTO daneTozsamosciDTO;

I załóżmy, że DaneTozsamoscieDTO zawieraja pole: PESEL, nrDokumentToz, Imie, Nazwisko i jeśli jeden z nich ma mieć pole PESEL wymagane a drugi nie. To muszę to rozdzielić też na dwa modele DaneTozsamosciNadawcyDTO i DaneTozsamosciOdbiorcyDTO i w jednym dam adnotację @NotNull a w drugim nie.

No i pozostaje reszta pytań. Jak zrobić takie walidację JSR303 - dwie różne na jednym formularzu. Tak by podsuowanie wyświetlało się w <p:messages/> a pola na formularzu podświetliły się na czerwono tak jak w <p:message> ale bez labelki.

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
0

Użyj grup.

Kopiuj
class DaneTozsamosciDTO {

    @NotNull(groups=Required.class)
    Pesel pieseł;
}
Kopiuj
class NadwacaDTO{

    private String nazwaFirmy;

    @Valid(groups=Required.class)
     private DaneTozsamosciDTO daneTozsamosciDTO;
}

i następnie uruchamiasz walidator z odpowiednią grupą.

W ten sposób, warunek zostanie sprawdzony tylko w ramach grupy do której jest przypisany.


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

@Koziołek
Właśnie uruchamiałem w ten sposób i nie do końca mi to działało. Przede wszystkim pola nie podświetlają się na czerwono i w <p:messages> traci kontakt z jakie pole pod jaką walidacją jest.

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
0

To tu się poddam, bo za słabo u mnie z JSyFami...


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
0

Czy ten print:

Kopiuj
System.out.println(formIdPrefix + " " + violation.getPropertyPath() + " " + violation.getMessage());

w metodzie

Kopiuj
sprawdź

wyświetla Ci poprawne ścieżki?
Pokaż jeszcze kod formularza (szablon JSF).

0
student pro napisał(a):

(...)
w metodzie

Kopiuj
sprawdź

</del> (...)

sorry, w metodzie

Kopiuj
zatwierdź
D3X
Postaram się w wolnej chwili podrzucić
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

Poradziłem sobie, ale pozostał mi jeden problem:

Mam na tym formularzu listę i używam ui:repeat i nie może mi znaleźć komponentu na stronie.

Przykład na działającym polu:
9d5ab3b7ee.png
i w kodzie:

Kopiuj
            UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
            LOG.debug("PATH: " + formIdPrefix + constraintViolation.getPropertyPath());
            String path = formIdPrefix + constraintViolation.getPropertyPath();
            path = path.replace(".", ":").replace("[",":").replace("]","");
            LOG.debug(path);
            UIComponent component = viewRoot.findComponent(path);

i findComponent z tym pathem co zaznaczyłem na obrazku znajduje, ale dla listy to już nie działa:

0f5c06d333.png

Jakieś pomysły?!

D3X
@Koziołek jakiś pomysł masz może? :)
D3X
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:187
0

Pomógł stackoverflow:
http://stackoverflow.com/questions/18358604/how-to-use-el-with-uirepeat-var-in-id-attribute-of-a-jsf-component

You can use EL in the id attribute of a JSF component, but the EL variable has to be available during view build time, while the JSF component tree is to be built. However, the ui:repeat runs during view render time, while the HTML output is to be generated based on JSF component tree. The <ui:repeat var> is not available during view build time and #{class2.name} evaluates to null which totally explains the error you got. That it works in <h:outputText> is because it runs during view render time.

Zamieniłem ui:repeat na c:forEach ponieważ mają inny cykl życia.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)