I have a big problem with css transitions and angular 4.
Actually, I use an external library which provides an input counter (that's my library, so I know no more style is applied to the wrapped input), but on the application I have the following style for the inputs:
input {
&[type="text"],
&[type="password"],
&[type="email"] {
border-radius: 4px;
border: 1px solid $grey-color;
padding: 0.5rem 1rem;
outline: none;
width: 100%;
transition-property: all;
transition-duration: 300ms;
font-size: inherit;
}
}
And in the html template:
<input-counter
type="text"
placeholder="Name"
[maxlength]="nameMaxLength"
[(ngModel)]="name">
</input-counter>
<input-counter> component template:
<style>
.input-counter-group {
display: block;
position: relative;
}
.input-counter-group span {
color: #b0b0b0;
font-size: 10px;
}
.input-counter-group .text-input-counter {
position: absolute;
line-height: 10px;
right: 0;
bottom: -13px;
}
</style>
<div class="input-counter-group">
<input
[id]="id"
[type]="type"
[ngClass]="className"
[name]="name"
[placeholder]="placeholder"
[maxlength]="maxlength"
[disabled]="disabled"
[pattern]="pattern"
[required]="required"
[readonly]="readonly"
[(ngModel)]="value"
(focus)="onFocus()"
(blur)="onBlur()">
<span *ngIf="enabled" class="text-input-counter">
<span *ngIf="displayMinLength()">{{ minlength }} characters at least required: </span>{{ counter }}<span *ngIf="displayMaxLength()">/{{ maxlength }}</span>
</span>
</div>
The problem is when component is loaded, a css transition is applied to the input, like if the input was "initialized" to the css properties I defined for inputs:
This animation appears when the component <input-counter> is displayed, whereas the only animation which should happens is the border color changes when the input is hovered.
Thanks!
EDIT: the origin of the problem was the plugin codemirror which was loaded with ngIf, and applied under the hood a style to my input (itself loaded from another component!), but with css transitions it did the rendering above, so I display it with [hidden] and all is ok.
You can use angular's animation system to get what you are looking for.
Create an animation trigger for your input-counter component, attach it to whichever tag you need to animate in your template and change the trigger's state when you need the transition to happen.
Related
I have the following code:
<div class="input-group want-outline">
<input class="form-control no-outline #(IsValid ? "" : "is-invalid")"
type="text"......
and this is my scss:
.no-outline:focus {
box-shadow: none;
&.want-outline {
border-radius: 2.5rem;
border-color: #80bdff;
border-width: 0.2rem;
}
}
when the input receives focus, it correctly sets box-shadow to none, but doesn't apply the border details to the parent. ive also tried:
& { border-radius.....
and
> & { border-radius.....
to reference the parent, these dont work either.
You can set the border on the focus-within style property which will apply styles to the parent element when the focus is within it (ie - when the input within it has focus.. The following uses straight css but can easily be converted to scss.
Note that IE does not support this style property at all (https://caniuse.com/?search=focus-within) but really who cares about ie? :)
Also - your border problem might be because you are not setting the border type (eg " solid / dashed / dotted) - i tend to set all the border styles in the shorthand version most of the time.
.no-outline:focus {
box-shadow: none;
}
.want-outline {
padding: 16px;
border-radius: 2.5rem;
display: inline-block;
border: solid 0.2rem transparent;
}
.want-outline:focus-within {
border-color: #80bdff;
}
<div class="input-group want-outline">
<input class="form-control no-outline" type="text" placeholde="enter txt"/>
<div>
I created a autocomplete child component that I am using in parent. In parent when try to apply the validation using Bootstrap form-control it's not getting applied to this child component - which is an input box with a list, although it's getting applied to other controls which are not child.
Child component HTML:
<div class="searching">
<input type="text" class="form-control" (input)="getFilteredData(inputBox.value);" class="form-control" [formControl]="inputBox">
<div id="search" tabindex="0" >
<ul class="suggestionList">
<li *ngFor="let result of filteredResults | async" (click)="onUserSelected(result)" >{{result[displayField1]}} | {{result[displayField2]}} {{result[displayField3]}}</li>
</ul>
</div>
</div>
Parent component:
<app-auto-complete formControlName="requestorId"
[ngClass]="{ 'is-invalid': submitted &&
requestorId.errors }"></app-auto-complete>
<div *ngIf="submitted && f.requestorId.errors" class="invalid-feedback">
<div *ngIf="f.requestorId.errors.required">Requestor ID is required</div>
</div>
Child CSS:
.searching {
width: inherit;
position: relative;
}
.searching input {
margin: 0;
padding: 0;
width: 100%;
height: 30px;
}
.suggestionList {
background-color: #fff;
width: 100%;
position: absolute;
padding: 0;
left: 0;
z-index: 1000;
}
.suggestionList li {
list-style-type: none;
border: 1px solid #c5c5c5;
cursor: pointer;
left: 0;
font-family: Arial,Helvetica,sans-serif;
font-size: 1em;
text-align: left;
}
I have several workaraounds in mind, so I hope any helps.
As mentioned in the comments, add in your parent component decorator the property 'encapsulation' (same level as 'selector' and such) with ViewEncapsulation.None.
Be aware that this approach makes styles of the parent component penetrate the whole app, so be wary with doing this unless you have the parent selector be really specific such as .my-specific-parent-selector-which-isnt-gonna-be-repeated
use #Input property on child component to pass the validation boolean, and apply the class directly according to the Input passed.
add a .parent-selector .is-invalid selector to parent, and then add behind it a ::ng-deep .parent-selector .is-invalid making that specific styling penetrate child classes. Be wary that this approach is deprecated though, so it might stop working in the future (although unlikely)
Note:
also note that you are applying the is-invalid class to a selector.. if you inspect with chrome web browser you will see that this selector usually is a different element that where you try to add your class... so maybe your best approach is using inputs
I have a button that I want to perform the action generated by a file_field in Rails. Here is the erb code I have right now:
<label for='file-input'>
<span class='btn btn-success' style='max-width: 300px;'>
<img src=<%= image_path('button-upload-white.svg')%>></img> Upload from computer
</span>
</label>
<%= f.file_field :files, multiple: true, name: 'attachment[file]', id: 'file-input'%>
I was following the pattern in this question with the associated CSS:
.file-input > input
{
display: none;
}
.file-input > label{
cursor: pointer;
}
but it does not seem to work and generates the following:
Desired output would be the same with the choose files input hidden or somehow connected to the button itself. Thanks, please let me know if I should post more code or I'm thinking about this in the wrong way.
Try this to 'hide' the input element
Width and height are set to 0.1px instead of just 0px. Setting the property values to zero ends up throwing the element out of tab party in some browsers. And position: absolute guarantees the element does not interfere with the sibling elements.
.file-input > input {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
Credit
I'm attempting to replicate the experience from the Shopify checkout in my WooCommerce checkout page by animating the labels when the user focuses on a certain input, just like this:
I've tried using input:focus ~ label, but it won't work because the default WooCommerce input is inside a span (.woocommerce-input-wrapper) like this:
<!-- The basic markup for each input -->
<p class="form-row form-row-first validate-required" id="billing_first_name_field" data-priority="10">
<label for="billing_first_name" class="">Nombre <abbr class="required" title="obligatorio">*</abbr></label>
<span class="woocommerce-input-wrapper">
<input type="text" class="input-text " name="billing_first_name" id="billing_first_name" placeholder="" value="" autocomplete="given-name">
</span>
</p>
<!-- CSS -->
<style>
.woocommerce-billing-fields__field-wrapper .form-row{
position: relative;
}
.woocommerce-billing-fields__field-wrapper .form-row label{
position: absolute;
top: 11px;
left: 11px;
padding: 0;
color: #808080;
transition: .35s;
}
.woocommerce-billing-fields__field-wrapper .form-row input:focus ~ label{
top: -8px;
font-size: 12px;
font-weight: 500;
}
</style>
Thanks!
I hope you find these codes useful
my css:
label {}
.woocommerce form .form-row label {
position: absolute;
left: 10px;
top: 15px;
}
.woocommerce form .form-row {
position: relative;
}
label.floatlabel {
top: -30px !important;
}
mu jQuery :
jQuery('.woocommerce form .form-row input').click(function(){
var label = jQuery("label[for='" + jQuery(this).attr('id') + "']");
if(jQuery('floatlabel').length ){
jQuery('label.floatlabel').removeClass('floatlabel');
}
jQuery(label).addClass('floatlabel');
})
The major issue with woocommerce checkout inputs is that labels are before inputs. For floating labels to work you need to place the labels after the inputs then it is all easy. (You can use any css method here: https://css-tricks.com/float-labels-css/).
I have tried finding a way to revert these elements in html but without success. I also tried using flexbox in css along with column-reverse but the animation didn't seem to work.
Basically the answer we are searching for is to the question: How to place labels after inputs in woocommerce checkout?
#Morteza Barati's answer could be good but it doesn't work properly. If inputs are autofilled then the label sits on top of them + once label moves up in case field is erased it won't come back down.
As already mentioned: There is no standardized way to change the input-label position on text input.
Off-topic: The design pattern in your screenshot comes from Googles material design (at least that's where it's commonly used and seen today). You can find more about that pattern here: https://material.io/components/text-fields
Solution with JS and CSS
You need some CSS and JS code to implement that design pattern. There are four different states you need to cover:
When a field receives the text-focus: Move the label up.
When a field loses focus and has no content: Move the label down.
When a field loses focus and has content: Leave the label up.
When a field has a value on page load: Move the label up.
Here's a short demo - the important part is the JS code which adds CSS classes to the field container on focus, blur and input.
jQuery('.form-row :input').each(function() {
var $input = jQuery(this);
var $row = $input.closest('.form-row');
// Is the field filled on page load?
if ($input.val()) {
$row.addClass('-filled');
}
// Enter or leave the "focus" state.
$input.on('focus', function() {
$row.addClass('-focus');
});
$input.on('blur', function() {
$row.removeClass('-focus');
});
// When the fields input value changes, add or remove the "-filled" state
$input.on('input', function() {
if ($input.val()) {
$row.addClass('-filled');
} else {
$row.removeClass('-filled');
}
});
})
.form-row {
position: relative;
padding-top: 20px; /* top padding adds space for the label */
margin: 10px 0;
}
.form-row label {
position: absolute;
top: 20px; /* initially, the label is down */
left: 0;
color: #aaa;
transition: all 0.3s;
}
/* Give both the label and input field the same padding/box-size */
.form-row input,
.form-row label {
font-size: 16px;
line-height: 22px;
padding: 8px 12px;
margin: 0;
}
/* When the field is focused or filled, move the label up */
.form-row.-focus label,
.form-row.-filled label {
color: #6200ee;
font-size: 12px;
top: 0;
padding: 0;
line-height: 20px; /* Set the line height to the top-padding */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="woocommerce-billing-fields__field-wrapper">
<p class="form-row">
<label for="field1">
Field 1 <abbr class="required">*</abbr>
</label>
<span class="woocommerce-input-wrapper">
<input type="text" id="field1">
</span>
</p>
<p class="form-row">
<label for="field2">
FIeld 2 <abbr class="required">*</abbr>
</label>
<span class="woocommerce-input-wrapper">
<input type="text" id="field2" value="Initial Value">
</span>
</p>
</div>
Pure CSS
TL;DR; this is not possible in WooCommerce out-of-the-box.
Note: A pure CSS solution is also possible when your comes after the field and could look like the below sample.
It works by using the input fields "placeholder" as the initial caption. The CSS selector :not(:placeholder-shown) matches every text field that has a value. The CSS selector :focus handles the input fields focus state.
However, this is just a sample and is not possible in WooCommerce without writing custom cart and checkout templates to produce the correct HTML elements.
.form-row {
position: relative;
padding-top: 20px;
margin: 10px 0;
}
.form-row label {
position: absolute;
color: #6200ee;
font-size: 12px;
top: 0;
left: 0;
padding: 0;
line-height: 20px;
opacity: 0;
transition: all 0.3s;
}
.form-row input {
font-size: 16px;
line-height: 22px;
padding: 8px 12px;
margin: 0;
}
/* Here's the logic: */
.form-row input:focus::placeholder {
opacity: 0;
}
.form-row input:focus + label,
.form-row input:not(:placeholder-shown) + label {
opacity: 1;
}
<p class="form-row">
<input type="text" id="field1" placeholder="My Field">
<label for="field1">
My Field
</label>
</p>
Is it possible to use normal CSS animations in angular?
I am trying just to show a div with a simple animation (the div is hide, then appears)
<div class="burguer-icon" (click)="onClick()">
<i class="fas fa-bars"></i>
</div>
<div
[ngClass]="showMenu ? 'shown' : 'hide'"
class="menu-content"
>
<div class="cross-icon" (click)="onClose()">
<i class="fas fa-times"></i>
</div>
// content
</div>
and I toggle the state, if clicked or not, in my component.ts
onClick() {
this.showMenu = !this.showMenu;
}
onClose() {
this.showMenu = !this.showMenu;
}
my css file for this component looks like this:
.burguer-icon {
background-color: orange;
}
.menu-content {
position: absolute;
top: 0px;
width: 100vw;
height: 100vh;
background-color: green;
transition: all 3s ease;
}
.show {
left: 0px;
}
.hide {
left: 90vw;
}
Why this simple animation does not work?
With angular, are you forced to use its animation strategy?
https://angular.io/guide/animations
Thanks in advance
Yes, you can use normal CSS animations. It's working fine on my end. Issue seems to be a typo in your class name show in css and shown in component html.
Update your html like:
[ngClass]="showMenu ? 'show' : 'hide'"