Vue3 - HTMLInputElement.target.value does not include decimal point? - vuejs3

I'm trying to create a numbered input with a max length.
However, when I try to type 1.2345, anything after the decimal doesn't get stored. Upon further inspection, target.value never includes the decimal point despite being a string. Why is that?
<script>
let props = defineProps({
hint: String,
min: Number,
max: Number,
maxLen: Number,
modelValue: Number,
})
let emits = defineEmits({
'update:modelValue': (it: number) => true
})
function onInput(event: Event) {
let target = event.target as HTMLInputElement
if (!target) return
console.log(typeof target.value, target.value) // <<< prints string, 1
target.value = target.value.slice(0, props.maxLen)
// let value = +target.value
// let oldValue = value
// value = Math.min(value, props.max ?? value)
// value = Math.max(value, props.min ?? value)
// u.log(oldValue, value)
// if (oldValue !== value) {
// u.log('update', value)
// target.value = '' + value
// emits('update:modelValue', value)
// }
}
</script>
<template>
<input class="form-control
block
w-full
px-3
py-1.5
text-base
font-normal
text-gray-700
bg-white disabled:bg-gray-100
bg-clip-padding
border border-solid border-gray-300
rounded
transition
ease-in-out
m-0
focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none
"
type="number"
#input="onInput"
:placeholder="hint" />
</template>

target.value never includes the decimal point despite being a string. Why is that?
When using <input type="number"/>, the input's value is converted from a string to a number, and then gets converted to a string again, at which point th decimal is removed. This is why when you enter 1.2 you get 21 (you can also use valueAsNumber which skips making it into a string, but doesn't really solve the problem)
type 1 => onInput target.value is 1
type . => onInput target.value is still 1 (not 1.)
onInput updates the value from 1. to 1 and because of the change, the caret is now at the beginning
type 2 => onInput target.value is 21
That's the problem, as to your solution, it depends on your expected behaviour.
you could try something like this to validate whether the value needs to be updated instead of just updating it
const max = 5;
const newVal = target.value.slice(0, max)
if(parseFloat(newVal)+"" !== newVal) {
target.value = parseFloat(newVal)
}
else if(newVal !== target.value) {
target.value = parseFloat(newVal)
}

Related

Styled Component prop inside a map

I'm trying to calculate the svg width based on a prop value.
It's an array of svg and each one should have a specific width.
It is perfectly calculating the width value but it's repeating the first value of the map for all others.
When I console.log the value inside the map it shows different values for each one.
Here's the map:
{example.map(v => (
<ComponentExample value={v.value} />
))}
Here's the styled component receiving prop:
const ComponentExample = styled(ExampleSVG)<{ value: number; }>`
width: ${props => (props.value * 100) / 5}%;`;

React Bootstrap - OverlayTrigger Tooltip dynamically change postion depends on view port

I'm using OverlayTrigger, Tooltip from react-bootstrap, and want to change tooltip position depending on viewport. I use a default placement right for now, but when I test it on iPhone X (375px), it's not working, I suppose because of not enough space to render. How to do this to automatically update on a small screen?
For LONGTextLon does not work:
const CustomTooltip = ({ placement = 'right', text = null }) => {
return (
<OverlayTrigger
placement={placement}
popperConfig={{
modifiers: {
// preventOverflow: {
// enabled: true
// // priority: ['top', 'right'],
// // boundariesElement: 'viewport'
// }
}
}}
overlay={
<Tooltip>
<div className="tc-text">{text}</div>
</Tooltip>
}
>
<Icon/>
</OverlayTrigger>
);
};
Current state: does not change position automativcaly when not enouph space
Expected: flip or change position to 'bottom' depends on viewport or space
Try the event resize.
window.addEventListener('resize', () => {
// Check for the size of the window and re render
});

Glass Mapper breaking standard values for image field

Consider the template:
Company
Logo (Image field)
Company Name (Text field)
The Company template has standard values set on both fields. If we get a Company item and save it using Glass without making any changes, the Logo field no longer uses the standard value. (The Company Name field is untouched.)
The issue, it seems, is that the Glass.Mapper.Sc.DataMappers.SitecoreFieldImageMapper serializes the value of that field differently than Sitecore does. When it tries to save, it thinks it's a change to the field and no longer uses the standard value.
Standard Value:
<image mediaid="{GUID}" />
Glass-generated Value:
<image height="64" width="64" mediaid="{GUID}" alt="Alt text" />
Is there a way to make Glass generate the same output as Sitecore?
I think that problem is in a way how SitecoreFieldImageMapper map ImageField to Image. For getting Height, Width and Alt are used public properties. If we look on them via reflector we will see that values of it get not directly from field:
public string Alt
{
get
{
string text = base.GetAttribute("alt");
if (text.Length == 0)
{
Item item = this.MediaItem;
if (item != null)
{
MediaItem mediaItem = item;
text = mediaItem.Alt;
if (text.Length == 0)
{
text = item["Alt"];
}
}
}
return text;
}
set
{
base.SetAttribute("alt", value);
}
}
If field does not contain value(e.g. for "alt": if (text.Length == 0)) then value will be received from MediaItem that is linked. It cause adding Height, Width and Alt from media library item after saving of field.
To fix this problem you could try replace this code:
int height = 0;
int.TryParse(field.Height, out height);
int width = 0;
int.TryParse(field.Width, out width);
img.Alt = field.Alt;
img.Height = height;
img.Width = width;
with direct getting attributes rather than usage of properties:
int height = 0;
if(int.TryParse(field.GetAttribute("height"), out height))
{
img.Height = height;
}
int width = 0;
if(int.TryParse(field.GetAttribute("width"), out width))
{
img.Width = width;
}
img.Alt = field.GetAttribute("alt");
With Alt property everything should be ok. But there could be problems with Width and Height as they are not Nullable and I am not sure how GlassMapper will handle Image with Width and Height that you haven't set.

AngularJS C directive using ng-class

The title might not explain what I am trying to achieve, so I will elaborate here.
I have a directive that is restricted to a CSS class name (in this example flex-wrap).
But this class is not applied to the element until we actually have some data.
The HTML for that looks like this:
<div class="row" ng-class="{ 'loading': !controller.loadingRecent, 'flex flex-vertical flex-wrap': controller.recent.length }">
<div class="col-md-12 row-title">
<h1>Recent orders</h1>
</div>
<div class="col-xs-12" ng-if="!controller.recent.length">
<div alert type="danger">
No records have been found that match your search.
</div>
</div>
<div class="col-md-4 tile-lg" ng-repeat="order in controller.recent" tile>
<a class="box-shadow" id="{{ order.orderNumber }}" ui-sref="viewOrder({ orderNumber: order.orderNumber })" coloured-tile>
<div class="text">
<p>
<strong>{{ order.account.accountNumber }}</strong><br />
{{ order.account.name }}<br />
{{ order.raisedBy }}<br />
{{ order.orderNumber }}<br />
{{ controller.getDescription(order) }}<br />
</p>
</div>
</a>
</div>
As you can see, the flex classes are not applied until our recent.length is greater than 0. What I would like to happen is that when we have records, the CSS class is applied and so the angular directive that is associated with that class fires.
Instead, it doesn't do anything at the moment.
Does anyone know how I can get my directive to fire?
Here is my directive, just so you can see it.
.directive('flexWrap', ['$window', '$timeout', function ($window, $timeout) {
// Sets the height of the element
var setHeight = function (element) {
// Declare our variables
var row = element.parent().parent(),
height = 630;
// If our row is a row
if (row.hasClass('row')) {
// Get the height of the rest of the items
height = height - getHeight(row);
}
console.log('height = ' + height);
// Set our elements height
element.css('height', height + 'px');
console.log('we are about to set the width');
// After we set the height, set the width
setWidth(element);
}
// Gets the height to minus off the total
var getHeight = function (element) {
// Declare our variables
var height = 0,
children = element.children(),
loopChildren = element.hasClass('row');
// Loop through the element children
for (var i = 0; i < children.length; i++) {
// Get the child
var child = angular.element(children[i]);
// If the child is not a column
if (!child.hasClass('columns')) {
// If we need to loop the children
if (loopChildren) {
// Get the height of the children
height += getHeight(child);
// Otherwise
} else {
// Add the height of the child to
height += child[0].offsetHeight;
}
}
}
// Return our height
return height;
};
// Sets the width of the element
var setWidth = function (element) {
// After a short period
$timeout(function () {
// Get our last child
var children = element.children(),
length = children.length,
lastChild = children[length - 1];
// Work out the width of the container
var position = element[0].getBoundingClientRect(),
childPosition = lastChild.getBoundingClientRect(),
width = childPosition.left - position.left + childPosition.width;
var style = $window.getComputedStyle(lastChild, null);
console.log(style.getPropertyValue('width'));
console.log('--------------------------------');
console.log(lastChild);
console.log(position);
console.log(childPosition);
console.log(width);
console.log('--------------------------------');
console.log('width = ' + width);
// Apply the width to the element
element.css('width', width + 'px');
}, 500);
};
// Resize the container
var resize = function (element, width) {
// If our width > 992
if (width > 992) {
// Resize our element
setHeight(element);
// Otherwise
} else {
// Set our element width and height to auto
element.css('height', 'auto');
element.css('width', 'auto');
}
};
return {
restrict: 'C',
link: function (scope, element) {
// Get our window
var window = angular.element($window),
width = $window.innerWidth;
// Bind to the resize function
window.bind('resize', function () {
// After half a second
$timeout(function () {
// Get the window width
width = $window.innerWidth;
// Resize our element
resize(element, width);
}, 500);
});
// Initial resize
resize(element, width);
}
};
}]);
Directive declaration style (e.g. restrict: "C") and an ng-class directive are not related to each other at all.
ng-class just adds/removes CSS class - it does not trigger a compilation/link of a directive that might be associated with these classes. In other words, it does not provide a way to dynamically instantiate a directive.
Your directive should handle the situation where data is not yet available. There are a number of ways to achieve that, via $scope.$broadcast/$scope.$on or via a service, or even via $watch - depending on any particular situation.

parseInt(number) notwork

I want check if my div have a number and add class css.
I have try this :
<div class="test" style="">
<p class="book"> 24 books</p>
</div>
jQuery('.test').addClass('ok');
var number = parseInt(jQuery(this).find('.book').text(), 10);
var current = 26;
if (current > number)
{
jQuery('.test').addClass('its-ok');
}
My class "ok" is add but the class its-ok isn't add.
In jsfiddle : http://jsfiddle.net/8tg9exLw/2/
the result of
parseInt(jQuery(this).find('.book').text(), 10);
is NaN because $(this).find('book') is an empty selector (what should be the value of $(this) in your context ?)
write instead parseInt($('.book').text(), 10);
Try this,,,
Add "$(document).ready(function(){});"
$(document).ready(function(){
jQuery('.test').addClass('ok');
var number = parseInt(jQuery(this).find('.book').text(), 10);
var current = 26;
if (current > number)
{
jQuery('.test').addClass('its-ok');
}
});
Updated Working jsFiddle
In the following jQuery code:
parseInt(jQuery(this).find('.book').text(), 10);
it is not getting what this is.
Instead of this, I suppose you mean to use .test. Check the updated jsFiddle above.
Your if condition is not satisfied because current < number.
JS:
jQuery('.test').addClass('ok');
var number = parseInt(jQuery('.test').find('.book').text(), 10);
console.log(number);
var current = 2;
if (current > number)
{
jQuery('.test').addClass('its-ok');
}
else
{
console.log("If condition not satisfied.");
// do something here
}
EDIT: For the parsed integer less than current, check this working jsFiddle: http://jsfiddle.net/8tg9exLw/4/

Resources