weex input number limit - vue.js

use component, when i input content,it has a limit condation,only input number length is 8,and only 2 radix point,for example,can input 123.45, 123.456 is not.
<input :type="type"
v-model="inputValue"
:max-length="maxInputLength"
:maxlength="maxInputLength"
:placeholder="rightPlaceholder"
:class="['input', disabled ? 'input-style-disabled' : '']"
:disabled="disabled"
#input="onTextChange"/>
and data is :
data () {
return {
inputValue:'', //input value
}
},
mounted(){
if(this.value) {
this.inputValue = this.value;
}
},
methods:{
formatAmount(value){
let result;
if (value.indexOf(".") > 0 && value.length - value.indexOf(".") >= 4){
result = value.substr(0,value.indexOf('.') + 3);
// fValue = value.toFixed(2);
Log.d("formatAmount",result);
}else {
result = value;
Log.d("formatAmount else",result);
}
return result;
},
onTextChange() {
setTimeout(() => {
this.inputValue = this.formatAmount(this.inputValue);
this.$emit("onTextChange",this.inputValue);
}, 10);
}
}
totally,this just work when two point change to three point,then still can input three point.
how does it work,need help.thx.

You can use array split on (.) and then check arr[1].length<=2 and arr[0].length <=6.or use regex /^\d+(.\d{1,2})?$/ for 2 radix point;

Related

How to convert a json response to match schema (not manually)?

I'm trying to validate a schema for complex JSON. We can easily compare a schema with API response by below command
And match response == response_SCHEMA
(where "response_SCHEMA" is json schema)
For small json we can manually create:
Actual API response:
{ "id": "123", "name": "abc", "type": "Mumbai", "owner": { "name": "Mr Singh", "type": "Business", "licenseNo": "ASL8989" }
Converted the response to below - manually
{ "id": "#number", "name": "#string", "type": "#string", "owner": { "name": "#string", "type": "#string", "licenseNo": "#string" }
How to create this kind of schema automatically for a complex big json having 300-400 lines? So, we can compare it with API response with Karate.
The point of the schema design is that you can easily cut and paste an actual JSON and either use it as it is (data match, recommended) or edit it to use #string etc (schema match).
When you say 300-400 lines, most likely you mean an array of JSON. All you need to do is specify the schema of the "repeating part" and then use match each: https://github.com/intuit/karate#match-each
* def actual = [{ a: 1, b: 'x' }, { a: 2, b: 'y' }]
* def schema = { a: '#number', b: '#string' }
* match each actual == schema
The short answer is there is no automatic way to do it. Typically you never need to do more than a few lines. Maybe you can write your own custom utility.
#Mayank I also faced this issue, Unfortunately I didn't find any options.
So I created my own small JS to convert the actual JSON into JSON Schema which is compatible with Karate Fuzzy Match.
The output may look like this
enter image description here
Hope This Helps!...
function main() {
var json;
if (document.getElementById('code').value) {
try {
json = JSON.parse(document.getElementById('code').value);
document.getElementById('code').value = JSON.stringify(inputTxt, null, 2);
document.getElementById('output').value = '';
} catch (e) {
document.getElementById('output').value = e;
}
}
let outArr = {};
let output = convertJson(json, 'response', true);
ouput = Object.assign(output, outArr);
Object.keys(ouput).forEach(key => ouput[key] === "#undefined" && delete ouput[key]);
document.getElementById('output').value = JSON.stringify(output, null, 2);
function convertJson(json, keyName, isParent) {
let outA = {};
let x = {};
let y = {};
Object.keys(json).forEach(function(key) {
if (!(getJSType(json[key]) === "object") && !(getJSType(json[key]) === "array")) {
x[key] = '#' + getJSType(json[key]);
}
if (getJSType(json[key]) === "object") {
x[key] = convertJson(json[key], key, false);
}
if (getJSType(json[key]) === "array") {
x[key] = '#' + getJSType(json[key]);
// y[key + 'arr'] = getArray(json[key][0], key, false);
getArray(json[key][0], key, false);
}
})
if (isParent) {
if (Object.keys(x).length > 0) {
outA[keyName] = x;
}
if (Object.keys(y).length > 0) {
outA[keyName + 'Arr'] = y;
}
return outA;
} else {
if (Object.keys(y).length > 0 && isParent) {
return y;
}
if (Object.keys(x).length > 0) {
return x;
}
}
}
function getArray(json, keyName, isParent) {
let z = {};
if (!(getJSType(json) === "object") && !(getJSType(json) === "array")) {
z[keyName + 'Arr'] = '#' + getJSType(json);
} else {
z[keyName + 'Arr'] = convertJson(json, keyName, false);
}
outArr = Object.assign(outArr, z);
}
function getJSType(valToChk) {
function isUndefined(valToChk) {
return valToChk === undefined;
}
function isNull(valToChk) {
return valToChk === null;
}
function isArray(valToChk) {
return valToChk.constructor == Array;
}
function isBoolean(valToChk) {
return valToChk.constructor == Boolean;
}
function isFunction(valToChk) {
return valToChk.constructor == Function;
}
function isNumber(valToChk) {
return valToChk.constructor == Number;
}
function isString(valToChk) {
return valToChk.constructor == String;
}
function isObject(valToChk) {
return valToChk.constructor == Object;
}
if (isUndefined(valToChk)) {
return "undefined";
}
if (isNull(valToChk)) {
return "null";
}
if (isArray(valToChk)) {
return "array";
}
if (isBoolean(valToChk)) {
return "boolean";
}
if (isFunction(valToChk)) {
return "function";
}
if (isNumber(valToChk)) {
return "number";
}
if (isString(valToChk)) {
return "string";
}
if (isObject(valToChk)) {
return "object";
}
}
}
function formatJson() {
if (document.getElementById('code').value) {
try {
var inputTxt = JSON.parse(document.getElementById('code').value);
document.getElementById('code').value = JSON.stringify(inputTxt, null, 2);
document.getElementById('output').value = '';
} catch (e) {
document.getElementById('output').value = e;
}
}
}
function minifyJson() {
if (document.getElementById('code').value) {
try {
var inputTxt = JSON.parse(document.getElementById('code').value);
document.getElementById('code').value = JSON.stringify(inputTxt, null, null);
document.getElementById('output').value = '';
} catch (e) {
document.getElementById('output').value = e;
}
}
}
<html>
<head>
<title>JavaScript Code Runner</title>
</head>
<body>
<h3>Generate the Json Schema for Response</h3>
<div style="display: flex;">
<textarea id="code" style="flex: 1; height: 80vh;" spellcheck="false"></textarea>
<textarea id="output" style="flex: 1; height: 80vh; overflow: auto;" spellcheck="false"></textarea>
</div>
<div style="display: flex;height: 12;"></div>
<button onclick="runCode()">Generate Schema</button>
<button onclick="formatJson()">Format JSON</button>
<button onclick="minifyJson()">Minify JSON</button>
<script src="src/jsonconverter.js"></script>
<script>
function runCode() {
main();
}
</script>
</body>
</html>

Change value after confirmation in input VUE-JS

I have a table with an input column. This input column will have value if it has been saved in ddbb before.
If this value changes, handled with an event '#blur', I show a modal to confirm the change.
My problem is that if you want to keep the old value it will always change...
I tried to change this value with javascript, but it doesn't work... Any suggestions?
This is my code:
<b-tbody>
<b-tr
v-for="(driver, index) in drivers"
:key="driver.clientId">
<b-td
data-label="Client"
:title="driver.clientName">{{ driver.clientName }}</b-td>
<b-td data-label="Numerator">
<b-input
:id="'numeratorDriver_'+index"
class="driver-numerator text-right"
type="text"
:value="(driver.driverNumerator === undefined) ? 0 : $utils.formatNumber(driver.driverNumerator)"
#blur="calculatePricingDriver($event, index)" /></b-td>
<b-td
class="text-right"
data-label="Pricing"
:title="driver.pricingDriver"><span>{{ driver.pricingDriver }}</span></b-td>
</b-tr>
</b-tbody>
<script>
function calculatePricingCustomDriver (event, index) {
let lastValue = this.drivers[index].driverNumerator
if (this.$store.getters.price !== undefined) {
let title = 'Modify numerator'
let message = 'If you modify numerator driver, the calculated pricing will be deleted'
this.$bvModal.msgBoxConfirm(message, {
title: title,
size: 'sm',
buttonSize: 'sm',
okTitle: 'Yes',
okVariant: 'primary',
cancelTitle: 'No',
cancelVariant: 'primary',
hideHeaderClose: false,
centered: true
})
.then(confirmed => {
if (confirmed) {
this.$http.get('delete-price', { params: { id: this.$store.getters.id } })
.then((response) => {
if (response.status === this.$constants.RESPONSE_STATUS_OK) {
this.price = ''
let newNumerator = event.target.value
this.drivers[index].driverNumerator = Number(newNumerator)
let sumTotal = _.sumBy(this.drivers, 'driverNumerator')
for (let i = 0; i < this.drivers.length; i++) {
this.drivers[i].pricingDriver = (this.drivers[i].driverNumerator / sumTotal).toFixed(2)
}
} else {
this.drivers[index].driverNumerator = lastValue
// this is that I want change because it doesn't work fine
document.getElementById('numeratorDriver_' + index).value = lastValue
}
})
} else {
this.drivers[index].driverNumerator = lastValue
document.getElementById('numeratorDriver_' + index).value = lastValue
}
})
.catch(() => {
/* Reset the value in case of an error */
this.$utils.showModalError()
})
} else {
let newNumerator = event.target.value
this.drivers[index].driverNumerator = Number(newNumerator)
let sumTotal = _.sumBy(this.drivers, 'driverNumerator')
for (let i = 0; i < this.drivers.length; i++) {
this.drivers[i].pricingDriver = (this.drivers[i].driverNumerator / sumTotal).toFixed(2)
}
}
}
</script>
how is calculatePricingCustomDriver being loaded into your Vue component? For it to be called like that from #blur you would need to define it as a method:
<template>
<!-- your table-->
</template>
<script>
export default {
name: "MyComponent",
methods : {
calculatePricingCustomDriver () {
// your code
}
}
}
</script>
Or it could be installed as a global mixin

how to force user input number only in <vue-numeric>

In my <vue-numeric>
<vue-numeric
currency="RMB"
separator=","
v-bind:minus="false"
v-model="amount"
v-bind:precision="2"
class="form-control form-control-lg bg-secondary border-0 text-white"
></vue-numeric>
By using this code it can convert the user input to number type even the input contains string inside, but what I want is user only can insert numberand when alphabet pressed, it will display nothing
You could try adding a keydown event listener and test the keycode to see if it's a number:
#keydown="testNumber"
methods: {
testNumber({ keyCode }) {
if(keyCode < 48 || keyCode > 57) {
event.preventDefault()
}
}
}
What you can do is extend/ overwrite the component options - e.g.:
import VueNumeric from "vue-numeric";
const inputHanlder = VueNumeric.methods["onInputHandler"];
VueNumeric.methods["onInputHandler"] = function(val) {
// here the sanitizer
this.amount = this.amountNumber;
inputHanlder.bind(this)();
};
VueNumeric.watch["valueNumber"] = function(newValue) {
console.log(newValue);
if (this.$refs.numeric !== document.activeElement) {
this.amount = this.format(newValue);
} else {
this.amount = newValue;
}
};
export default VueNumeric;

Vue.js list not updating when data changes

i'm trying re-organised a list of data. I have given each li a unique key, but still, no luck!
I have had this working before exactly like below, think i'm cracking up!
let app = new Vue({
el: '#app',
data: {
list: [
{ value: 'item 1', id: '43234r' },
{ value: 'item 2', id: '32rsdf' },
{ value: 'item 3', id: 'fdsfsdf' },
{ value: 'item 4', id: 'sdfg543' }
]
},
methods: {
randomise: function() {
let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
this.list = input;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in list" :key="item.id">{{ item.value }}</li>
</ul>
Randomize
</div>
Edit:
Thanks for the answers, to be honest the example I provided may not have been the best for my actual issue I was trying to solve. I think I may have found the cause of my issue.
I'm basically using a similar logic as above, except i'm moving an array of objects around based on drag and drop, this works fine with normal HTML.
However, i'm using my drag and drop component somewhere else, which contains ANOTHER component and this is where things seem to fall apart...
Would having a component within another component stop Vue from re-rendering when an item is moved within it's data?
Below is my DraggableBase component, which I extend from:
<script>
export default {
data: function() {
return {
dragStartClass: 'drag-start',
dragEnterClass: 'drag-enter',
activeIndex: null
}
},
methods: {
setClass: function(dragStatus) {
switch (dragStatus) {
case 0:
return null;
case 1:
return this.dragStartClass;
case 2:
return this.dragEnterClass;
case 3:
return this.dragStartClass + ' ' + this.dragEnterClass;
}
},
onDragStart: function(event, index) {
event.stopPropagation();
this.activeIndex = index;
this.data.data[index].dragCurrent = true;
this.data.data[index].dragStatus = 3;
},
onDragLeave: function(event, index) {
this.data.data[index].counter--;
if (this.data.data[index].counter !== 0) return;
if (this.data.data[index].dragStatus === 3) {
this.data.data[index].dragStatus = 1;
return;
}
this.data.data[index].dragStatus = 0;
},
onDragEnter: function(event, index) {
this.data.data[index].counter++;
if (this.data.data[index].dragCurrent) {
this.data.data[index].dragStatus = 3;
return;
}
this.data.data[index].dragStatus = 2;
},
onDragOver: function(event, index) {
if (event.preventDefault) {
event.preventDefault();
}
event.dataTransfer.dropEffect = 'move';
return false;
},
onDragEnd: function(event, index) {
this.data.data[index].dragStatus = 0;
this.data.data[index].dragCurrent = false;
},
onDrop: function(event, index) {
if (event.stopPropagation) {
event.stopPropagation();
}
if (this.activeIndex !== index) {
this.data.data = this.array_move(this.data.data, this.activeIndex, index);
}
for (let index in this.data.data) {
if (!this.data.data.hasOwnProperty(index)) continue;
this.data.data[index].dragStatus = 0;
this.data.data[index].counter = 0;
this.data.data[index].dragCurrent = false;
}
return false;
},
array_move: function(arr, old_index, new_index) {
if (new_index >= arr.length) {
let k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing
}
}
}
</script>
Edit 2
Figured it out! Using the loop index worked fine before, however this doesn't appear to be the case this time!
I changed the v-bind:key to use the database ID and this solved the issue!
There are some Caveats with arrays
Due to limitations in JavaScript, Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
To overcome caveat 1, both of the following will accomplish the same as vm.items[indexOfItem] = newValue, but will also trigger state updates in the reactivity system:
Vue.set(vm.items, indexOfItem, newValue)
Or in your case
randomise: function() {
let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
Vue.set(input, randomIndex, input[i]);
Vue.set(input, i, itemAtIndex);
}
this.list = input;
}
Here is an working example: Randomize items fiddle
Basically I changed the logic of your randomize function to this:
randomize() {
let new_list = []
const old_list = [...this.list] //we don't need to copy, but just to be sure for any future update
while (new_list.length < 4) {
const new_item = old_list[this.get_random_number()]
const exists = new_list.findIndex(item => item.id === new_item.id)
if (!~exists) { //if the new item does not exists in the new randomize list add it
new_list.push(new_item)
}
}
this.list = new_list //update the old list with the new one
},
get_random_number() { //returns a random number from 0 to 3
return Math.floor(Math.random() * 4)
}
randomise: function() { let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = this.list[randomIndex];
Vue.set(this.list,randomIndex,this.list[i])
this.list[randomIndex] = this.list[i];
this.list[i] = itemAtIndex;
} this.list = input;
}
Array change detection is a bit tricky in Vue. Most of the in place
array methods are working as expected (i.e. doing a splice in your
$data.names array would work), but assigining values directly (i.e.
$data.names[0] = 'Joe') would not update the reactively rendered
components. Depending on how you process the server side results you
might need to think about these options described in the in vue
documentation: Array Change Detection.
Some ideas to explore:
using the v-bind:key="some_id" to have better using the push to add
new elements using Vue.set(example1.items, indexOfItem, newValue)
(also mentioned by Artokun)
Source
Note that it works but im busy so i cant optimize it, but its a little bit too complicted, i Edit it further tomorrow.
Since Vue.js has some caveats detecting array modification as other answers to this question highlight, you can just make a shallow copy of array before randomazing it:
randomise: function() {
// make shallow copy
let input = this.list.map(function(item) {
return item;
});
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
this.list = input;
}

Vue.js - Input, v-model and computed property

I'm using vue-2.4 and element-ui 1.4.1.
Situation
I have a basic input which is linked with v-model to a computed property. When blur I check if the value input is greater or lower than min and max and I do what I have to do ... Nothing fancy here.
Problem
The value displayed in the input does not always equal enteredValue
Steps to reproduce
1) Input 60 --> Value displayed is the max so 50 and enteredValue is 50 (which is ok)
2) Click outside
3) Input 80 --> Value displayed is 80 and enteredValue is 50
Questions
How can I fix that so the value displayed is always the same as the enteredValue ?
Here is the minimal code to reproduce what I'm facing JSFIDDLE
<div id="app">
The variable enteredValue is {{enteredValue}}
<el-input v-model="measurementValueDisplay" #blur="formatInput($event)"></el-input>
</div>
var Main = {
data() {
return {
enteredValue: '',
max: 50,
min: 10
}
},
computed: {
measurementValueDisplay: {
get: function () {
return this.enteredValue + ' inchs'
},
set: function (newValue) {
}
},
},
methods: {
formatInput($event) {
let inputValue = $event.currentTarget.value;
if (inputValue > this.max) { this.enteredValue = this.max}
else if (inputValue < this.min) { this.enteredValue = this.min}
else this.enteredValue = inputValue
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
Reading this vuejs, will understand what happens
"computed properties are cached based on their dependencies. A computed property will only re-evaluate when some of its dependencies have changed."
Changed some comportament of the code. Made run:
computed() method not works properly for update value in window. But if looks at console the value yes updated.
So, i remove computed (getter and setter), and put into data, without setter and getter( i dont like this in javascript).
var Main = {
data() {
return {
measurementValueDisplay:'fff',
enteredValue: '',
max: 50,
min: 10
}
},
computed: {
/*measurementValueDisplay: {
get: function () {
console.log('Computed was triggered so I assume enteredValue changed',this.enteredValue);
return this.enteredValue + ' inchs'
},
set: function (newValue) {
console.log('setter de qye', this.enteredValue);
}
},*/
},
methods: {
formatInput($event) {
this.enteredValue = 0;
let inputValue = $event.currentTarget.value;
console.log(inputValue);
if (inputValue > this.max) { this.enteredValue = this.max}
else if (inputValue < this.min) { this.enteredValue = this.min}
else this.enteredValue = inputValue
this.measurementValueDisplay = this.enteredValue + ' inchs'
console.log(this.enteredValue, 'oioioioio0');
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
Your problem is that the values used in the computed property was not updated with the validation capping at 50 (Was 50, is now updated to 50, no need to recalculate), therefore v-model did not update the input.
I've edited your jsfiddle to use two computed properties:
One with an accessor to validate the entered value, one which returns the value with " inch" appended.
Here is the interesting part:
computed: {
measurementValueDisplay: {
get: function () {
return this.enteredValue
},
set: function (newValue) {
this.enteredValue = 0;
let inputValue = parseInt(newValue);
if(Number.isNaN(inputValue)){this.enteredValue = this.min}
else if (inputValue > this.max) { this.enteredValue = this.max}
else if (inputValue < this.min) { this.enteredValue = this.min}
else this.enteredValue = inputValue
}
},
valueWithInch(){
return this.enteredValue + " inch";
}
},
In case anybody still needs a hack for this one, you can use a value that will always change ( for example a timestamp )
var Main = {
data() {
return {
enteredValue: '',
max: 50,
min: 10,
now: 1 //line added
}
},
computed: {
measurementValueDisplay: {
get: function () {
return (this.now - this.now + 1 ) * this.enteredValue + ' inchs'; //line changed
},
set: function (newValue) {
this.now = Date.now(); //line added
}
},
},
methods: {
formatInput($event) {
let inputValue = $event.currentTarget.value;
if (inputValue > this.max) { this.enteredValue = this.max}
else if (inputValue < this.min) { this.enteredValue = this.min}
else this.enteredValue = inputValue
}
}
}