Establishing initial value in a vue subcomponent - vue.js

I have created a vue subcomponent to select an element from a list:
Vue.component('select-value-from-list', {
template: `
<select v-model="currentValue">
<option v-for='op in options' :value='op.value'>
{{op.label}}
</option>
</select>
`,
props: {
initialValue: {
type: String
},
options: {
type: Array,
required: true
}
},
data: function() {
return {
currentValue: "Indefinido"
}
},
watch: {
currentValue: function () {
this.$emit('value-change', this.currentValue);
}
},
created: function() {
if(this.initialValue)
this.currentValue = this.initialValue;
}
})
And I want the menu with options to appear with the option corresponding to the initialValue selected. How should I do this?

Related

How do I check if the Multi-select component in Vue js is empty?

I am trying to check if the Multi-select component is empty. But upon checking it kept telling me it's not null. Do I need to use a v-model for this?
Here's the code for the Multi-select component:
<template>
<div>
<Multiselect
v-model="value"
mode="tags"
:close-on-select="false"
:searchable="false"
:create-option="true"
:options="multi_options"
class="multiselect-orange multiselect"
/>
</div>
</template>
<script>
import Multiselect from "#vueform/multiselect";
export default {
components: {
Multiselect,
},
props: {
multi_options: {
type: Array,
required: true,
},
inputSelected:{
required:true,
},
method: { type: Function },
// default: {
// type: String,
// required: false,
// default: null,
// },
},
data() {
return {
value: this.inputSelected,
};
},
mounted() {
this.$emit("set-input", this.value);
},
watch: {
value: function () {
this.$emit("set-input", this.value);
},
},
};
</script>
Here's the code where I used the component:
<div class="inputHolder">
<label class="body"> Skills:</label>
<MultiSelect :multi_options="this.skills" #set-input="setSkillSet" :inputSelected="staffSkills"/>
</div>
Here's the code when I tried to check if the Multi-select is empty:
checkForm(){
this.errors = []
if (this.staffSkills) {
return true;
}
if(this.staffSkills === []){
this.errors.push('Select at least one.');
}
if(this.errors.length){
return this.errors
}
}
},

Unable to validate a child component from a parent component

I have a selectbox component. I want to reused it in other components.I'm able to reused the selectbox component in other components by adding v-model directive on custom input component but unable to validate selectbox component from other components by using vuetify validation rules.
Test.vue
<v-form ref="form" class="mx-4" v-model="valid">
<Selectbox :name="ward_no" :validationRule="required()" v-model="test.ward_no"/>
<v-btn primary v-on:click="save" class="primary">Submit</v-btn>
export default {
data() {
return {
test: {
ward_no: ''
},
valid: false,
required(propertyType) {
return v => (v && v.length > 0) || `${propertyType} is required`;
},
};
}
Selectbox.vue
<select #change="$emit('input', $event.target.value)" >
<option
v-for="opt in options"
:key="opt.value"
:value="opt.value"
:selected="value === opt.value"
>
{{errorMessage}}
{{ opt.label || "No label" }}
</option>
</select>
export default {
props: {
label: {
type: String,
required: true
},
validationRule: {
type: String,
default: 'text',
validate: (val) => {
// we only cover these types in our input components.
return['requred'].indexOf(val) !== -1;
}
},
name: {
type: String
},
value: {
type: String,
required: true
}
},
data() {
return {
errorMessage: '',
option: "lorem",
options: [
{ label: "lorem", value: "lorem" },
{ label: "ipsum", value: "ipsum" }
]
};
},
methods:{
checkValidationRule(){
if(this.validationRule!="")
{
return this.validationRule.split('|').filter(function(item) {
return item();
})
// this.errorMessage!= ""?this.errorMessage + " | ":"";
}
},
required() {
this.errorMessage!= ""?this.errorMessage + " | ":"";
this.errorMessage += name+" is required";
},
}
};

Vuejs Reactivity on Set Value

I have a custom table with actions via a modal popup that set values on Rows. Things are mostly working great (Updates to Foo and Bar get sent to the backend and are set in a database, reload of the page pulls the data from the database and shows foo/bar were correctly set). The only not-great part is on setting of Foo, the value in the table does not get updated. Bar gets updated/is reactive. (the template uses foo.name and bar.id). Does anyone have any ideas on how to get Foo to update in the table? I've changed the moustache template to use {{ foo.id }} and it updates, but I need foo.name.
<template>
<div>
<c-dialog
v-if="foo_modal"
title="Set Foo"
:actions="foo_modal_options.actions"
#cancel="foo_modal = null">
<slot>
<div class="form-group">
<label>Foo:</label>
<select class="form-control" v-model="foo_modal.thing.foo.id">
<option v-for="foo in foos" :key="foo.id" :value="foo.id">{{ foo.name }}</option>
</select>
</div>
</slot>
</c-dialog>
<c-dialog
v-if="bar_modal"
title="Set Rod/Stick"
:actions="bar_modal_options.actions"
#cancel="bar_modal = null">
<slot>
<div class="form-group">
<label>Rod:</label>
<select class="form-control" v-model="bar_modal.thing.rod.id">
<option v-for="bar in bars" :key="bar.id" :value="bar.id" v-if="bar.type === 'rod'">{{ bar.id }}</option>
</select>
</div>
<div class="form-group">
<label>Stick:</label>
<select class="form-control" v-model="bar_modal.thing.stick.id">
<option v-for="bar in bars" :key="bar.id" :value="bar.id" v-if="bar.type === 'stick'">{{ bar.id }}</option>
</select>
</div>
</slot>
</c-dialog>
<c-table-paginated
class="c-table-clickable"
:rows="grid.data"
:columns="grid.columns"
:actions="grid.actions"
:key="componentKey">
</c-table-paginated>
</div>
</template>
<script>
import fooModal from '../../components/fooModal.vue';
import barModal from '../../components/barModal.vue';
import CTablePaginated from "../../components/custom/cTable/cTablePaginated";
import cTooltip from '../../components/custom/cTooltip/cTooltip.vue';
import cDialog from '../../components/custom/cDialog/cDialog.vue';
import moment from 'moment';
export default {
components: { CTablePaginated, cTooltip, cDialog },
methods: {
loadData() {
let that = this;
that.$http.get('/things', { params: that.param || {} })
.then(function (things) {
that.things = things.data;
that.grid.data = that.things;
});
},
setBar(thing_id, options, cb) {
let that = this;
this.$http.patch(`/things/${thing_id}`, { rod_id: options.rod, stick_id: options.stick })
.then(function () {
cb();
});
},
setFoo(thing_id, options, cb) {
let that = this;
this.$http.patch(`/things/${thing_id}`, { foo_id: options.foo_id })
.then(function () {
cb();
})
},
},
data() {
return {
componentKey: 0,
things: null,
foos: [],
bars: [],
foo_modal: null,
foo_modal_options: {
actions: [
{
label: "Save",
class: "btn-primary",
action: (function (ctx) {
return function () {
const thing = ctx.foo_modal.thing;
const options = {
foo_id: thing.foo.id,
};
ctx.setFoo(thing.id, options, function () {
ctx.foo_modal = null;
});
}
})(this)
},
{
label: "Cancel",
action: (function (ctx) {
return function () {
ctx.foo_modal = null;
}
})(this)
}
]
},
bar_modal: null,
bar_modal_options: {
actions: [
{
label: "Save",
class: "btn-primary",
action: (function (ctx) {
return function () {
const thing = ctx.bar_modal.thing;
const options = {
rod: thing.rod.id,
stick: thing.stick.id
};
ctx.setBar(thing.id, options, function () {
ctx.bar_modal = null;
});
}
})(this)
},
{
label: "Cancel",
action: (function (ctx) {
return function () {
ctx.bar_modal = null;
}
})(this)
}
]
},
grid: {
data: [],
columns: [
{
label: "Foo",
value: function (row) {
if (!row.foo) return "No foo set";
return `${row.foo.name }`;
}
},
{
label: "Rod/Stick",
value: function (row) {
if (!row.rod && !row.stick) return "No rod/stick set";
if (!row.rod) return `No rod set/${row.stick.id}`;
if (!row.stick) return `${row.rod.id}/no stick set`;
return `${row.rod.id}/${row.stick.id}`;
}
}
],
actions: [
{
label: "Set Foo",
visible: function (thing) {
return !thing.active;
},
action: (function (ctx) {
return function (thing) {
if (!thing.foo) thing.foo = {};
ctx.foo_modal = {
thing: thing
};
}
})(this)
},
{
label: "Set Bar",
visible: function (thing) {
return !thing.active;
},
action: (function (ctx) {
return function (thing) {
if (!thing.rod) thing.rod = {};
if (!thing.stick) thing.stick = {};
ctx.bar_modal = {
thing: thing
};
}
})(this)
},
],
}
};
},
props: {
title: {
type: String
},
param: {
type: Object,
required: true
},
events: {
type: Object,
required: true
}
},
created() {
let that = this;
this.loadData();
this.$http.get('/bars')
.then(function (bars) {
that.bars = bars.data;
});
this.$http.get('/foos')
.then(function (foos) {
that.foos = foos.data;
});
},
}
</script>
There are two possibilities you can try both if any one of them can help you.
You can set value by using Vuejs this.$set method for deep reactivity. Click here.
You can use this.$nextTick(()=>{ // set your variable here }). Click here.

VueJs watcher vs multiple event listeners on the instance of the model

I'm trying to figure out which approach is more appropriate / less resource intense. Both examples below will do the same job, but my understanding is that there might be situations where both events #keyup and #change might be triggered unnecessarily - hence my question, whether watch method would be a better option here?
The reason why I also need to check for a #change event is when someone simply selects saved input value rather than type it.
<template>
<input
type="text"
:name="name"
#keyup="update()"
#change="update()"
v-model="field"
>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true
},
initialValue: {
type: String,
required: false,
default: ''
}
},
data() {
return {
field: this.initialValue
}
},
mounted() {
this.update();
},
methods: {
update() {
this.$emit('input', this.field);
}
}
}
</script>
vs
<template>
<input
type="text"
:name="name"
v-model="field"
>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true
},
initialValue: {
type: String,
required: false,
default: ''
}
},
data() {
return {
field: this.initialValue
}
},
mounted() {
this.update();
},
watch: {
field() {
this.update();
}
},
methods: {
update() {
this.$emit('input', this.field);
}
}
}
</script>

VueJs: Using component inside another component

I'm trying to make use of the main component inside another with pre-defined properties.
Here's what I'm trying to achieve, but I'm just getting an empty div as a result.
<template>
<call-dialog-link
:id="id"
:url=url"
message="Are you sure you wish to remove this record?"
label="Remove"
css-classes="alert"
></call-dialog-link>
</template>
<script>
import CallDialogLink from './CallDialogLink.vue';
export default {
props: {
id: {
type: String,
required: true
},
url: {
type: String,
required: true
}
},
components: {
'call-dialog-link': CallDialogLink
}
};
</script>
Here's the CallDialogLink component
<template>
<span class="clickAble" :class="cssClasses" v-text="label" #click="clicked()"></span>
</template>
<script>
export default {
props: {
id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
message: {
type: String,
required: true
},
label: {
type: String,
required: true
},
cssClasses: {
type: String,
required: false
}
},
mounted() {
window.EventHandler.listen('remove-dialog-' + this.id + '-called', (data) => {
window.location.reload(true);
});
},
methods: {
clicked() {
window.EventHandler.fire('top-confirm', {
id: 'remove-dialog-' + this.id,
message: this.message,
url: this.url
});
}
}
};
</script>
Any idea what I'm doing wrong?
I believe there is typo in your code.
<template>
<call-dialog-link
:id="id"
:url="url" // didn't open the double quote here
message="Are you sure you wish to remove this record?"
label="Remove"
css-classes="alert"
></call-dialog-link>
</template>