StencilJS trying to set component's internal input tag state according to Prop input - stenciljs

I'm building a custom input tag with stenciljs and I dont understand how to set the inputs disabled or readonly state. I'm passing the property to the component from the parent as an enum with 3 properties as follows:
enum INPUT_STATE {
DISABLED = "disabled",
READONLY = "readonly",
DEFAULT = ""
}
And the component looks as follows:
export class InputFields {
#Prop() inputState: INPUT_STATE;
render() {
return (
<div class="status">
<input type="text" {...INPUT_STATE[this.inputState]}/>
</div>
);
}
}
So basically what I'm trying to do is to set the passed property on the input, be it disabled or readonly and an empty string for default state. How can I achieve this functionality?

INPUT_STATE is an enum. The INPUT_STATE values are strings, so INPUT_STATE[this.inputState] is a string not an object. Strings don't map directly to jsx attributes - you would have to set explicitly:
<input type="text" disabled={this.inputState === INPUT_STATE.DISABLED}/>
By using a watch , you can move the logic out of the JSX:
private inputStateAttr = {};
#Prop() inputState: INPUT_STATE;
#Watch('inputState')
handleInputStateChange(value: INPUT_STATE) {
this.inputStateAttr = {
disabled: INPUT_STATE.DISABLED === value,
readonly: INPUT_STATE.READONLY === value
};
}
render() {
return (
<div class="status">
<input type="text" {...this.inputStateAttr}/>
</div>
);
}

Related

vue.js use variable value as form model name on function to manipulate input field

I have a component with vue model , I want to set value from the component initialization function under mounted. I have some value over under mounted function in a variable. and I have the model name inside that variable. Now, how can I access that particular model? FYI the required form model name is inside the variable.
<template>
<a class='btn btn-sm btn-success' #click.prevent="openModule('sort__abc','asc')"><i class="fa fa-home" ></i> </a>
<select v-model="searchform['sort__abc']" class='btn-default' style='zoom:80%;' :name='"sort__abc"'>
<option value=''>Sort</option>
<option value='asc'>Asc</option>
<option value='desc'>Desc</option>
</select>
</template>
<script>
// Declare /user-management component
var cpage = 1;
export default {
name: 'user-management',
// Declare users (as object), form (as /vform instance) and /isFormCreateUserMode (as boolean
// defaulted to 'true') inside /data() { return {} }.
data() {
return {
//variables here
searchform: new Form()
}
},
methods: {
openModule(formModel, formData) {
//Now, I have model name on formModel and data on formData, how can i set the input value from here?
}
}
}
</script>
I have found a solution. Here is my solution
methods: {
openModule(formModel, formData) {
this.searchform[formModel]=formData
}
}

change data variable when passed into a method in vue

I have the following vue component where I am changing the class of the parent row based on whether or not an input is focused
<template>
<div class="form form--login">
<div class="form__row" :class="{entered: emailEntered}">
<label class="form__label" for="login-form-email">Email address</label>
<input type="text" class="form__control form__control--textbox" name="email-address" id="login-form-email" #focus="emailEntered = true" #blur="handleBlur($event, emailEntered)">
</div>
<div class="form__row" :class="{entered: passwordEntered}">
<label class="form__label" for="login-form-password">Password</label>
<input type="password" class="form__control form__control--textbox form__control--password" name="password" id="login-form-password" #focus="passwordEntered = true" #blur="handleBlur($event, passwordEntered)">
</div>
</div>
</template>
<script>
export default {
name: 'login-form',
data() {
return {
emailEntered: false,
passwordEntered: false,
}
},
methods: {
handleBlur(e, enteredBool) {
if (e.currentTarget.value.trim() === '') {
// this doesn't do anything - I can do an if else statement to change this.passwordEntered or this.emailEntered based on the name of the current target, but how do I change the value by passing it into the method?
enteredBool = false;
}
},
}
}
</script>
but it doesn't seem to change the variable that is passed into the method - how do I pass a data variable into the method and change it's value? Or should I be doing it in a different way? I don't really want to be doing an if else statement as I may have a form that has got a lot more inputs on and I think that would be really inefficient to maintain
I also thought that I could do something in the #bur as you can do #blur="passwordEntered = false", but I wasn't sure how to check if the field was empty or not
In order to change the variable, you need to refer it using this
handleBlur(e, enteredBool) {
if (e.currentTarget.value.trim() === '') {
this[enteredBool] = false; //Change added
}
},
and the way you pass it should be like
#blur="handleBlur($event, 'emailEntered')" //Added single quotes
and
#blur="handleBlur($event, 'passwordEntered')" //Added single quotes

Value of input not changed

Using Vue3 and Vuex4
I got an input field:
<input :class="invalid.includes(item.attribute) ? 'invalidInput' : 'validInput'" type="text" :id="item.attribute" :name="item.attribute" :placeholder="item.default_value" min="0" step="any" :value="item.value" #input="validate(item.attribute, $event)" class="p-1">
I change the value of "invalid" like this. Just checking for the validity of a regex and adding/removing the attribute to the array.
VALIDATE_INPUT: (state, data) => {
var regex = /(?=.*\d)^\$?(([1-9]\d{0,2}(,\d{3})*)|0)?(\.\d{1,2})?$/;
switch (data.attribute) {
case 'invoice_amount_f':
if (!regex.test(data.value)) {
state.validations.push(data.attribute)
} else {
let index = state.validations.findIndex(el => el === data.attribute);
if (index > -1) {
state.validations.splice(index, 1);
}
}
break;
default:
break;
}
}
The action calling the mutation is called like:
const validate = (attribute, event) => {
store.dispatch('validate', {
attribute: attribute,
value: event.target.value
});
}
Computed:
var invalid = computed({
get() {
return store.getters.getValidationState;
}
});
When now typing something into the input field the text in the field ain't chaning. This seems to happen cause I use the value of invalid inside the template. Why is that?
EDIT: It seems to have something to do with the scope I am using it in.
<h3>{{ invalid }}</h3>
<div v-if="nestedListItems && Object.keys(nestedListItems).length !== 0">
<draggable v-model='nestedListItems' item-key="id" class=" w-12/12 bg-white m-auto border" animation="150">
When rendering it outside of draggable it's absolutely fine. Inside it crashes my store.
You need to provide an object to the :class, see here:
https://v3.vuejs.org/guide/class-and-style.html#binding-html-classes
I suggest you create a variable in the script containing the boolean e.g. isValid and then apply it like this:
:class="{invalidInput : !isValid, validInput: isValid }"

Using computed with dynamic objects in Vue JS

Hey gang
Since I'm kind of new to Vue JS, I've managed to almost complete a simple staged form project, I'm having trouble with a dynamic object
Assuming that this is the last stage of the form:
<template v-if="currentStage === 3">
<h2>Step 3 - Additional Params</h2>
<h3>Please fill all the parameters needed</h3>
<div v-for="(param, key, index) in params" :key="key">
<label class="inputLabel" :for="key">Please fill in {{ key }} param</label> <span class="redStar">*</span>
<input v-model="params[key]" :id="key">
<span v-if="submitted && $v.params[key] && !$v.params[key].required" class="invalid-feedback">It's a required field, please fill it</span>
<!-- <span v-if="v$.params[key].$errors[0]" class="invalid-feedback"> {{ v$.params[key].$errors[0].$message }} </span>-->
</div>
<button #click="updateStage(0)">Previous</button>
<button #click="handleLastSubmit">Create</button>
</template>
Inside Data() I created an empty object destined to be fulfilled based on user input from certain field in the form, as suggested in the comment below:
params() {
if (this.jsonS.hasOwnProperty(this.tDetails.platform)) {
for (const [key, value] of Object.entries(this.jsonS[this.tDetails.platform])) {
this.params[key] = value;
}
}
return this.params;
},
I tried to add { required } based on vue forums suggestions like this(inside computed):
addRequiredValidation() {
//Here I need somehow to add validations to params Object.
for (const key in this.integrationParams) {
this.$options.validations().integrationParams[key].required = required
}
}
And implement it in the validations as follows:
validations() {
return {
integrationParams: this.addRequiredValidation,
trafficDetails: {
brand: {required, minLength: minLength(3)},
platform: {required, minLength: minLength(3)},
whitelabel: {required, minLength: minLength(3)},
country: {required, minLength: minLength(2)},
campaignName: {required, minLength: minLength(2)}
}
}
},
Ending up getting this error:
TypeError: Cannot convert undefined or null to object
at Function.keys ()
You could use another computed field to get your params.
computed: {
params() {
const params = {};
if (this.jsonS.hasOwnProperty(this.tDetails.platform)) {
for (const [key, value] of Object.entries(this.jsonS[this.tDetails.platform])) {
params[key] = value;
}
}
return params;
}
}
The params should be recalculated whenever this.tDetails.platform changes (i.e., a user inputs another platform) and your addRequired property should update correctly.

Is there anyway to set a different value for the "input" than the vue variable?

I need to change the display of a input depending on the value returned from the db for this variable: paragraph.RCBulletinNumber
I have tried the computed method, but I think this is not what I need
computed: {
formatRCBulletinNumber: {
set (val){
return this.paragraph.RCBulletinNumber;
}
}
},
This is my input declaration using v-model='paragraph.RCBulletinNumber':
<div class="form-group">
<div v-if='typeof paragraph != undefined /*/<!--&& parseInt(paragraph.RCBulletinNumber)>0 -->/*/'>
<input type="text" style="width: 40%;" class='form-control' id="RCNumber" placeholder="RC Number" v-model='paragraph.RCBulletinNumber'>
</div>
</div>
What I expect is that if the value of paragraph.RCBulletinNumber is less than or equal to 0 the input remains empty. Right now if the variable equals 0 the input is 0
But if the paragraph.RCBulletinNumber is equal to 0, the value must go to the database again, my goal is just to change the value of the input to be more userfriendly.
Simply define the getter and setter of the computed property:
computed: {
formatRCBulletinNumber: {
// getter
get: function () {
return this.paragraph.RCBulletinNumber || '';
},
// setter
set: function (newValue) {
this.paragraph.RCBulletinNumber = newValue;
}
}
}
And then reference the computed property on the input:
<input type="text" style="width: 40%;" class='form-control' id="RCNumber" placeholder="RC Number" v-model='formatRCBulletinNumber'>
reference: https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter