How to style successful input fields in Thymeleaf - spring-boot

I would like to use Bootstrap's has-success and has-failure classes with Thymeleaf.
So far I have
<div th:class="${#fields.hasErrors('field')}? 'form-group has-error' : 'form-group'"></div>
This displays the failure style correctly, when the form is posted and the field is invalid.
However if I change the second part of the ternary to 'form-group has-success', then on the initial form GET request, then, of course, it styles it as a success, even though the form hasn't been posted yet.
My question: is there a way in Thymeleaf to handle the following
Displays a form without any styling on GET.
On POST apply has-error or has-success classes.

I think you'll need to add attributes to your Model in the back-end for this.
In you GET request, change nothing. In your POST request, add an attribute: ["hasErrors", true] if the form data you send via the post is incorrect, false otherwise.
Now in your html you can add the following:
<th:block th:if="${hasErrors != null}">
<div th:class="${hasErrors ? 'form-group has-error' : 'form-group has success'"></div>
</th:block>
<th:block th:unless="${hasErrors != null}">
<div class="form-group"></div>
</th:block>
You check if the hasErrors model attribute isn't null, if it is, it means you're in the GET method and you should display a simple form-group. If the hasErrors is not null, you can create the ternary expression based on the boolean value hasErrors. The th:block is non-html. You can replace it with a div, but then you neen an extra div just to check a boolean.

I'm not going into GET/POST problem but I think that this can help you:
New th:errorclass for adding CSS class to form fields in error
Until now, whenever we wanted to apply a specific CSS class to an input field in a form when there were errors for that field, we needed to use the th:class or th:classappend attributes.
In Thymeleaf 2.1, in order to simplify this structure, a new th:errorclass attribute processor has been introduced. This processor will read the name of the field from the name or th:field attribute in the same tag, and apply the specified class if such field has errors.
Note the 'error' literal is in fact a token, so no single quotes are really needed.
The result is much more concise. Note also that th:errorclass works like th:classappend, not th:class. So the specified class will in fact be appended to any existing ones.
http://www.thymeleaf.org/whatsnew21.html#errcl

I found that Thymeleaf as a hasAnyErrors function.
<div class="form-group row"
th:attrappend="class=${#fields.hasAnyErrors()
? #fields.hasErrors('field') ? ' has-error' : ' has-success'
: '' }">
This now works.
When the user GETs the form, hasAnyErrors is false, so the empty string is appended and the input and label receive the default style.
When the user POSTs the form, if there are any errors then the first part of the ternary is evaluated. This adds the has-error or has-success styles.
This was inspired by Roel Strolenberg's answer below.

Related

Passing conditional disabled attribute to blade component with ternary operator

Is there a way to conditionally pass a disabled attribute to a blade component? For example this question and answer mention how to use the ternary operator to pass in the value of the attribute but the attribute name will be there regardless.
I am specifically trying to use the ternary operator in the blade component tag to add (or not add) the disabled attribute
template code:
<x-button {{!$aircraftType->canIslandBuild($island) ? 'disabled' : ''}}>
Build
</x-button>
button component code:
<button {{ $attributes->merge(['class' => 'inline-flex']) }}>
{{ $slot }}
</button>
The error involves adding {{!$aircraftType->canIslandBuild($island) ? 'disabled' : ''}} to the x-button tag.
The error that I'm getting is: syntax error, unexpected token "endif", expecting end of file
Also if I change this {{!$aircraftType->canIslandBuild($island) ? 'disabled' : ''}} to {{''}} the same error happens so I'm curious if you can render strings from php code inside of the component tag header like you can anywhere else in a blade template. I know there are other ways to pass in data and conditionally add the disabled attribute by modifying the button component code but I would like to know if there is an easy solution here.
Went with matiaslauriti's comment and decided to replace
{{!$aircraftType->canIslandBuild($island) ? 'disabled' : ''}}
with
:disabled="!$aircraftType->canIslandBuild($island)"
without changing anything else. It seems disabled="disabled" is included in the $attributes variable only when the value is true. This means that the button renders a disabled="disabled" only when !$aircraftType->canIslandBuild($island) is true and when it is false, no disabled is rendered on the final html for the button.

How can I add c# code within HTML tags in ASP.Net Core

I'm migrating my site from ASP.net Framework (4.7.2) to Asp.net Core (5). One issue that I can't seem to figure out is that in my original site I had c# in a few of my HTML tags to set the css class(es). For instance:
<div class="carousel-item propertyCarousel #if (firstImage) { <text>active</text> } #if (slideNumber > 2) { <text>bonus-image</text> } " data-slide-number="#slideNumber.ToString("D2")">
Because of tag helpers, asp complains about the code. So I disabled tag helpers in the _ViewImports.cshtml and it no longer complains, but then sometimes the code just doesn't work. For instance in the above example I never get a div with the 'active' class despite verifying the conditions are correct (i.e. that 'firstImage' is true for the first image).
Since the previous commenter did not really answered the question, I'm going to go ahead and say that you need to use brackets for it to work.
This works because it's in a variable:
<div class="#htmlClass"></div>
But when you need the result of an expression from within your HTML attribute like:
<div class="#myvar == true ? "active" : string.Empty"></div>, does not work. What you should do is wrap it in brackets like this :
<div class="#(myvar == true ? "active" : string.Empty)"
This will output: <div class="active"> if the result of the expression was true.

Angular 2 form valid by default

Having issue with form validation .
i want to submit the form only when form is valid.
but with the empty inputs and clicking on submit button is submitting the form although the inputs are empty.
<form name="equipmentForm" #f="ngForm" (ngSubmit)="f.form.valid && addEquipment()" validate>
Inputs be like this.
<input name="equimentId" class="text-input form-control" type="text" [(ngModel)]="model.equipmentNumber" pattern="^[0-9][0-9]{1,19}$" title="Equipment ID. can be upto 20 digits only.">
I cant post the whole code although.
this
f.form.valid is true from form initialization
wanted to acheive something like this
<div *ngIf="!model.equipmentModel && f.submitted" class="text-danger">
Please enter Equipment Model
</div>
So on submit i want to show this message instead of default browser's.
but this f.form.valid is goddamn true from default.
You should add required attribute to your input tags to, then as #Cobus Kruger mentioned, form will not be submitted untill it is filled.
However you can also give a try to pristine, dirty options, which allow you to check if the user did any changes to the form so in this case your condition may look like this:
<form name="equipmentForm" #f="ngForm" (ngSubmit)="f.form.valid && f.form.dirty ? addEquipment() : ''" validate>
and the input:
<input name="equimentId" class="text-input form-control" type="text" [(ngModel)]="model.equipmentNumber" pattern="^[0-9][0-9]{1,19}$" title="Equipment ID. can be upto 20 digits only." required />
In this case it will check if any changes were applied to the input, and submit the form if both conditions are met.
If you specify the required attribute on the input, then the form will not be submitted unless a value is filled in. But that only covers values that were not supplied and you may want to check for invalid values as well.
The usual way is to disable the submit button unless the form is valid. Like this:
<button type="submit" [disabled]="!f.form.valid">Submit</button>
The Angular documentation about form validation also shows this. Look near the bottom of the "Simple template driven forms" section
In function which you call on submit you can pass form as parameter and then check. In html you will need to pass form instance:
<form name="equipmentForm" #f="ngForm" (ngSubmit)="addEquipment(f)" validate>
In typescript:
addEquipment(form){
if(form.invalid){
return;
}
//If it is valid it will continue to here...
}

Set visibility of form input in thymleaf using th:if

I am new to thymeleaf and I have this problem.
I have a form to add and edit products.
From the controller I set request mapping to access this form view using
#RequestMapping("/products/add")
and
#RequestMapping("/products/edit/{id}")
I have a field in products ,Date endPromotion.
I want this input block that has endPromotion field to be shown only in edit mode.
How can I do that using thymleaf condition?
i tried somthing like
<div th:if="${|/products/{action}(action='edit')|}"> .. valid html code ... </div>
but it doesn't work
This should do the trick
<div th:if="${#strings.contains(#httpServletRequest.requestURI, '/products/edit/')}">
some content
</div>

MVC3 Razor View Optimization

Is there any better way as compared to #if #else Just to changes few attributes (like disabled, value, class etc) of html element in cshtml page built with Razor view?
you can use inline conditional statements as well:
<input type="text" value="#(true == true ? "one value" : "another value")" />
MVC 4/Razor V2 will have some improvements:
Conditional attribute rendering
If you have an attribute that might be null, in the past you've needed to do a null check to avoid writing out an empty attribute, like this:
<div #{if (myClass != null) { <text>class="#myClass"</text> } }>Content</div>
Now Razor is able to handle that automatically, so you can just write out the attribute. If it's null, the attribute isn't written:
<div class="#myClass">Content</div>
So if #myClass is null, the output is just this:
<div>Content</div>
From Jon Galloway's blog.
You can pass them in the ViewModel as true/false values or string values.
For example -
anything that needs to be dynamically set to be enabled or disabled - you can create a bool
any html class that is a string set on runtime, can be passed as a string variable in your view model.
etc.
That would clean up your razor views of all the #if else statements
I don't know why you think there is any performance flaw with razor #if but you can use Your ViewModel or ViewBag for this:
<input type="text" value="#(ViewBag.TheValue)" />
But for best practice, Don't mix server side logic with the presentation. "Separate of concerns"
Update(What did I mean by "separate of concerns"):
It mean the View should contains as much as it can, HTML markups and HTML helpers(which just help you write markup) only. Don't put logic inside the View. don't reuse the same view if it makes you put code inside of it.

Resources