Convert user input with function and ng-model in AngularJS - javascript

Im trying to implement in an app, a unit converter from mm to inches and viceversa. This is part of a larger design app and the idea is that the user can work in mm-inch and use a button to change the displayed values and also be able to edit the input (like xPosition or shapeWidth).
I made this simple fiddle to show my problem.
As you can see, the converter works fine, but the input stops working and i can't edit the input, so the value is fixed with the initial value of the directive. Since this values can be modified, i can't use ng-init since its for initialization only.
If I use ng-model="this.value" the input starts accepting changes but the conversion stops working. The value should be inside the input, I can't have another number displayed at the side with the converted number.
Is there a way to enable the user input and also use the getValue or something similar to make the conversion when the buttons are pressed? Don't usually work in AngularJS but got this task so theres probably a directive option.
Thanks!

You should convert the value only on change of units. I changed a little bit your example here: https://jsfiddle.net/avgustin/y1khr2j8/5/
I used this.value in ng-model:
ng-model="this.value"
and changed the functions setUnit and convertUnit to do the conversion in both directions.
$scope.convertUnit = function(value) {
let appUnit = $scope.unit;
if(appUnit == 'in') {
return parseFloat((value / 25.4).toPrecision(3));
}
return parseFloat((value * 25.4).toPrecision(3));
}

Related

How to copy the value of a yform to an other field

In our (hybris) shop some products have a yform to summarize the parts of the product. Is there an easy way to copy the value of the sum field into an other field (automaticly) like the productquantity (no yForm)?
I guess I need javascript, but the id of the sumfield is generatad, so I don't know how to get the sum. Also my Javascript abilities are quite limited...
UPDATE:
To get the value I use this part of code:
copyYFormValueToProductQuantity : function() {
var copyText = document.querySelector('input[id*="sum"]').value
if (copyText > 0 && copyText != null)
{
//do stuff
}
console.log("Copied value: " + copyText)
},
But this line
document.querySelector('input[id*="sum"]').value
returns null. If I use it in the browserconsole, it also returns null. But after I inspected the element it works and returns the value I want to. So I guess I am missing some JS-basics here and the object isn't ready before?
Btw.: I call this function with a keydown-eventlistener.
This can most likely be done from the jsp files. There you have all the data that is needed, so you most likely need to only copy that field where you need it.
We can also help you more if you add some code examples here (what exactly is that yform?). If you struggle to find where in code is that specific yform created/added, it's always worth giving a try to search for the applied classes of the html (search the entire project and see what you find).
As I understand your question, you are saying that you want to copy the value of a yForm field named sum into a non-yForm field named productquantity, and you are asking specifically about how to access the value of a yForm field from JavaScript. If I understand this correctly, you can do so by calling the following JavaScript API:
ORBEON.xforms.Document.getValue("sum");
You can find more about this and other related API on Client-side JavaScript API.

React.js controlled text cursor focus issue

I have a simple controlled input of type number like below.
<input type="number" value={+value} step={1} onChange={this.updateMyChange} />
My value often returns a decimal number like 123.123 . My problem is, when I try edit the value. The cursor loses focus and shifts to the beginning ignoring the whole numbers as soon as the decimal places are cleared. Like below:
How do I address this? Immediately after the decimal places are cleared, the cursor jumps to the beginning thereby making it impossible to edit the whole numbers. Any help would be appreciated.
Update
Below is the remaining code as requested by the user below.
render() {
const {value} = this.state;
return (
<input type="number" value={+value} step={1} onChange={this.updateMyChange} />
)
}
And my updateMyChange method is simply
updateMyChange(e) {
this.setState({ value: e.target.value });
}
It does nothing much simply sets the new value. The cursor position jumps to the end as soon as decimal places are cleared. It does not set cursor for whole numbers.
This is how React updates an input field's value:
node.setAttribute(attributeName, '' + value);
When you set value attribute using that method, the caret goes to the beginning of the field, regardless of using React. You can see what I am saying in this fiddle - https://jsfiddle.net/5v896g3q/
(Just try and position the cursor in the field, between changes).
According to MDN, setAttribute is unstable when dealing with value. The recommended way of changing value is by accessing the value property of the element, like element.value = newValue. If you use that approach, all seems to go as expected.
This is all I can tell for sure. Now let's speculate a little. When you type anything in that field, you are:
updating the value of the input
reading that value, and sending to React as state
React updates the value of the input, with the new state
When you are typing on the field, step 3 is likely to have no impact, because when the value comes back, the input already got it right. Except on the case with the float number. When your field reads 1., the actual value React updates the field with is 1. And React uses the evil method (setAttribute).
So, a workaround I found was setting the value of the field, using the proper method, before React touches it, on componentWillUpdate:
componentWillUpdate(nProps, nState){
this.refs.input.value = '0' + nState.value
}
The problem there, is that it is "numerizing" the value on every change, meaning I won't be able to have a point (1.). For that reason, I will only edit the input in case new value is 2 characters shorter than the old one (point + digit after point):
componentWillUpdate(nProps, nState){
if(this.state.value.length - nState.value.length === 2){
this.refs.input.value = '0' + nState.value
}
}
Working example - https://jsfiddle.net/bsoku268/3/
note: the fiddle is for demonstration purposes, and not supposed to be a bulletproof solution, as there are many ways of interacting with an input field, such as copy & paste, drag & drop, autofill, etc

Correct way to have calculated values in React.js

Setup
So basically I have 3 dimension fields (length, width and height) that are backed by state. I want to keep the state in inches but allow the user to switch the units on the display at will. Currently I'm only supporting inches and feet so I have a "dimension_unit" state that stores the currently displayed units and display_dimensions_multiplier that stores 1.0 for inches and 1.0/12.0 for feet (both are in state). I have everything working exactly as I want except for one thing.
Problem
All values I've tried have worked except when you try to use a decimal. Basically, in the background it's running throw the multiplier to get saved in state on change and then multiplies back in the value for the field which basically erases the trailing "." as you type so say you were trying to type 4.5, what you would actually get in the field as you typed is 45. But if you type 45 and then move the cursor between the 4 and 5 add the . you'll end up with 4.5...
My idea
The way I was thinking about solving it was basically have a state variable for the display_length and then have the regular length state as well then have the display_length stay the same unless they change units and have the length calculated and stored on change and then just persist that... and the same for height and width... but that seems very un-react-ive so what is the react-ive way of doing this? Or is that it?
Happy to post example code if needed, but there is a good bit of code for any component so... yeah... hopefully just the explanation is enough.
Edit1
Basic before fiddle: before
This is my idea I'm curious about: after
The main difference being:
_handleChange: function(ev){
ev.stopPropagation()
ev.preventDefault()
var key = ev.target.name;
var value = ev.target.value;
var indims = this.state.input_dimensions;
indims[key] = value;
this.setState({input_dimensions: indims});
value = (value / this.state.display_dimensions_multiplier);
var dims = this.state.dimensions;
dims[key] = value;
this.setState({dimensions: dims});
},
I think your solution is the right idea. A few similar ideas:
Only update your stored value when the input is committed (for example onBlur instead of onChange). You can apply generic realtime input validation to make sure it's a valid number.
Like you say use a separate "display" state (I would consider this an "input state") and when the component updates with the new stored value, only update the input state if it differs (when converted to the same units). This way you don't need to persist or worry about the "input state" outside the input components.
When the input has focus, don't update the input state when the stored value changes. When the input does not have focus or blurs, update the input state to the stored value.
I don't know that any of these solutions or the one you proposed is more "Reacty" than the others. I think it's really up to you.

Adding '+' to the end of Algolia instantsearch rangeslider's max value

I'm using Algolia's rangeslider from instantsearch.js with tooltips set to false. When the slider's maximum value is displayed (the value to the right side of the slider) (e.g: 2,000), I want it to display as (e.g: 2,000+) (with a "+").
I've tried accessing/resetting the value with jquery like this:
var $sliderMax = $('#my_slider_identifier .ais-range-slider--value').last();
And I've succeeded in getting a handle on the variable, but when I try resetting the maximum value from a custom widget's render() function (so it updates with each new set of results coming in) with the equivalent of $sliderMax.text('2,000' + '+'), nothing happens - I assume because the DOM is being re-written after my call..
If the rangeSlider is showing the maximum value (e.g: 2000), Is there a recommended way to put a '+' on the end?
EDIT:
To give more background: Though I have a range of values from 0-10,000+, the vast majority of the data is in the 0-2000 range, and I thus, truncated my data so that if it's >2000, it shows as 2000.
Also, incidentally and oddly, As a hack, I found that I can write to the DOM if I use a setTimeout of 0 ms (yes, there are stackoverflows on this) and re-do a JQuery selection:
setTimeout(function(){
$('#index_price_eur_day_i .ais-range-slider--value').last()
.text(MAX_PRICE_SLIDER + '+');}, 0);
I'd love to find a more-efficient solution.
I heard from Tim Carry of Algolia and he suggested that I try the :after pseudo element of CSS to fix this.
Indeed, I added this CSS and it always adds a + -- unfortunately even when the slider is not at the max value :/
#my_slider_identifier .ais-range-slider--value:last-of-type::after {
content: "+";
}
So it's not a perfect solution, but it may be "good-enough" - and it's not as ugly/inefficient as using jquery. If anyone has a better solution, please post it!

Change an input when you change another one in javascript

Hard to define the title ^^
I want to have to input fields. For example: one where you type in a color (string) and another for the code of the color (varchar).
Like this: |Green| |#657EC9| (just random color-code)
I do not want to learn how to find the color-code but how to match a value or variable with another. It was just an example.
What i wanna know is how I in the best way auto generate one of the fields when I fill in the second. When I type 'green' in the first field I want the code to automatically appear in the second and vice versa. I just want to do it for a few colors.
I am very new to PHP, HTML and Javascript and could need some good advice about how I should handle the problem.
Thank you
I would tend to just map values to an object literal, so:
var colors = {
Green:'#657EC9',
Red:'#00ffff'
}
Now you could get your value with colors[fieldInputVal] where fieldInputVal might be 'Green' or 'Red' although of course you'd have to test if there actually was a property there. Object literals are the main reason I rarely find a use for switch statements in JS.
As for the event JS, I'm going to be lazy and go with JQuery rather than explain attachEvent vs. addEventListener which would be necessary if you're supporting IE8 or below. If you want to normalize for that yourself and skip JQuery, look up 'addEvent contest' on quirksmode.org
$('.input_one').change( function(){
//note: only fires after the field loses focus - you tab out or focus another field
var inputVal = $(this).val();
if(colors[inputVal] !== undefined){
$('.input_two').val(colors[inputVal]);
}
} );
note: I did not test this code for syntax goofs.
If you want to be more flexible and accept 'green' or 'Green', I would just capitalize the first character before you use it for the lookup. To do the lookup on every character add, you'd have to look up the keyup or keydown events (I prefer keyup to avoid breaking the browsers back when somebody holds a key down).

Categories

Resources