VueJs: Using component inside another component - vuejs2

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>

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
}
}
},

VueJS - Can we prevent component rendering using Composition?

Until now I was using a computed property with a v-if in my component to avoid it to render if basic props was not given, for example :
<template>
<div v-if="basicPropsProvided">
Blabla
</div>
</template>
<script>
export default{
props: {
icon: { type: String, required: true },
title: { type: String, required: true },
url: { type: String, required: true }
},
computed: {
basicPropsProvided(): boolean {
return !!this.title && !!this.icon && !!this.url
}
}
}
</script>
I tried to move this logic to the setup method, without success. Do you think there is a way to do this with the composition api to reuse the logic on other components ?
Define a composable function called useCheckProvidedProps which takes props as parameter and returns the computed property :
<template>
<div v-if="basicPropsProvided">
Blabla
</div>
</template>
<script>
import {computed} from 'vue'
function useCheckProvidedProps (props){
return {
basicPropsProvided:computed(()=>!!props.title && !!props.icon && !!props.url)
}
}
export default{
props: {
icon: { type: String, required: true },
title: { type: String, required: true },
url: { type: String, required: true }
},
setup(props){
const {basicPropsProvided}=useCheckProvidedProps (props)
return {basicPropsProvided}
}
}
</script>

Catch Event from Dropdown component not working in Parent

I am using this wonderful https://www.creative-tim.com/product/vue-black-dashboard-pro and their component Base-Dropdown has the following code:
<template>
<component :is="tag"
class="dropdown"
:class="{show:isOpen}"
#click="toggleDropDown"
v-click-outside="closeDropDown">
<slot name="title-container" :is-open="isOpen">
<component
:is="titleTag"
class="dropdown-toggle btn-rotate"
:class="titleClasses"
:aria-expanded="isOpen"
:aria-label="title || ariaLabel"
data-toggle="dropdown">
<slot name="title" :is-open="isOpen">
<i :class="icon"></i>
{{title}}
</slot>
</component>
</slot>
<ul class="dropdown-menu" :class="[{show:isOpen}, {'dropdown-menu-right': menuOnRight}, menuClasses]">
<slot></slot>
</ul>
</component>
</template>
<script>
export default {
name: "base-dropdown",
props: {
tag: {
type: String,
default: "div",
description: "Dropdown html tag (e.g div, ul etc)"
},
titleTag: {
type: String,
default: "button",
description: "Dropdown title (toggle) html tag"
},
title: {
type: String,
description: "Dropdown title",
},
icon: {
type: String,
description: "Dropdown icon"
},
titleClasses: {
type: [String, Object, Array],
description: "Title css classes"
},
menuClasses: {
type: [String, Object],
description: "Menu css classes"
},
menuOnRight: {
type: Boolean,
description: "Whether menu should appear on the right"
},
ariaLabel: String
},
data() {
return {
isOpen: false
};
},
methods: {
toggleDropDown() {
this.isOpen = !this.isOpen;
this.$emit("change", this.isOpen);
},
closeDropDown() {
this.isOpen = false;
this.$emit('change', false);
}
}
};
</script>
Now in another component, let's call it, "AddAccount.vue" I am using that Base-Dropdown component, but I can't seem to catch the 'change' event. I have tried everything.
computed: {
listeners() {
return {
...this.$listeners,
change: this.onChange,
}
}
},
methods: {
onChange(evt) {
console.log(":P:")
},
or
computed: {
change(evt) {
console.log(":P:")
}
},
or
methods: {
change(evt) {
console.log(":P:")
},
Nothing gets ever caught in that component, but if I do a breakpoint in the Base-Dropdown.vue, it is being caught...!

Establishing initial value in a vue subcomponent

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?

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>