How to get the default content slot sent to a Vue component? - javascript

In the following example, I would like a component that doubles a number. This number is passed not as a property, but as content. How is it possible to get the content value in Vue?
var twice = {
template: '<div>{{ value }}</div>',
computed: {
value() {
return parseInt(this.$slot) * 2;
}
}
};
new Vue({
el: '#app',
components: {
twice: twice
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="app">
<twice>21</twice>
</div>

You could access the default slot text by this.$slots.default[0].text :
var twice = {
template: `<div>
number : <slot></slot><br>
<div>double : {{ value }}</div>
</div>`,
computed: {
value() {
return parseInt(this.$slots.default[0].text) * 2;
}
},
mounted() {
console.log(this.$slots.default[0].text)
}
};
new Vue({
el: '#app',
components: {
twice: twice
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<twice>21</twice>
</div>

Related

Vue not reactive to nested data() changes?

My Vue 2 fails to react when an entry is added to an object returned by data(). I can make it work other way but would like to know the underlying reason. See also JSfiddle
var app = new Vue ({
el: "#app",
data() {
return {
addedRows: {
'section1': {}
}
}
},
methods: {
addToList(chapter) {
this.addedRows.section1[chapter] =
this.addedRows.section1[chapter] || []
this.addedRows.section1[chapter].push({'T': 'XXX'})
console.log(this.addedRows)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<span #click="addToList('chapter1')">{{ addedRows }}</span>
</div>

Vuejs how to use dynamical template in component?

const CustomComponent = {
props: ['index'],
template: `<span>I am a custom component: {{ index }}</span>`
};
const UserInputResult = {
components: {
CustomComponent
},
props: ['templateString'],
template: `<section v-html="templateString"></section>`
}
const app = new Vue({
el: '#app',
data(){
return {
userInput: 'user input example [:component-1]'
}
},
components: {
UserInputResult
},
methods: {
generateTemplate(){
let raw = this.userInput;
if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
let components = [...raw.match(/\[\:component\-\d+\]/g)];
components.forEach(component => {
raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
});
}
return raw;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<textarea v-model="userInput"></textarea>
<user-input-result :template-string="generateTemplate()">
</div>
I want to render a custom component which has a dynamical template base on user input.
when user input a specific string ([:component-1]), it will be render as a component (CustomComponent)
how to achieve this?
Thanks a lot for anyone help!
You should look into v-slot
https://v2.vuejs.org/v2/guide/components-slots.html
Example:
Parent:
<child-component v-html="myTemplate">
<span>From parent</span>
</child-component>
Child:
<div>
<v-slot></v-slot> //Will output "<span>From parent</span>"
</div>
**Added more explaination
You can then condition check and update myTemplate to your desired template. "<span>From parent</span>" is just there for explanation on how slot works.
updated by the questioner
const CustomComponent = {
props: ['index'],
template: `<span>I am a custom component: {{ index }}</span>`
};
const UserInputResult = {
template: `<section><slot></slot></section>`
}
const app = new Vue({
el: '#app',
data(){
return {
userInput: 'user input example [:component-1]'
}
},
components: {
UserInputResult,
CustomComponent
},
methods: {
generateTemplate(){
let raw = this.userInput;
if (!!raw && raw.match(/\[\:component\-\d+\]/g)) {
let components = [...raw.match(/\[\:component\-\d+\]/g)];
components.forEach(component => {
raw = raw.replace(component, `<custom-component :index="${component.match(/\d+/)[0]}"></custom-component>`);
});
}
return raw;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<textarea v-model="userInput"></textarea>
<user-input-result>
{{ generateTemplate() }}
</user-input-result>
</div>
I figured it out by using Vue.complie
according to dynamically-fetch-and-compile-a-template-with-nuxt
const UserInputResult = {
props: ['templateString'],
render(h){
return h({
components: {
CustomComponent
},
template: `<section>${this.templateString}</section>`
});
}
}

Why doesn't my component template show up in Vue?

I've just started learning Vue. Now I'm trying to build my first component, but the template didn't show up, and the console didn't give me any error.
Here's some of my code:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
and here's a Jsbin with my full code
Your Vue instance needs a mounting id specified in the el property:
var vm = new Vue({
el: '#app', // Specifying a DOM id "app"
data() {
// ...
}
})
And the app template needs to be wrapped with that same id:
<div id="app">
<button-counter></button-counter>
</div>
Demo:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
var vm = new Vue({
el: '#app',
data() {
return {
name:'yazid',
age:'20',
date:'press to known the date',
skills:['HTML','CSS','JS'],
ele:'<h1> elements from vue js</h1>',
completed_languages:[{
lang:'html',
percent:'90%'
},{
lang:'CSS',
percent:'70%'
},{
lang:'JS',
percent:'70%'
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button-counter></button-counter>
</div>

Call parent's method for Local-Registration component VueJs

I have Vue object:
var app = new Vue({
el: '#my-id',
data() {
return {
example: 1
}
},
methods: {
exampleMethos(data) {
console.log('data', data);
}
},
components: {
'my-component': {
methods: {
callMethod() {
console.log('I want call exampleMethos here');
}
},
template: `
<div>
<input type="checkbox" :change="callMethod()">
</div>`
}
}
});
<div id="my-id">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<script src="https://vuejs.org/js/vue.js "></script>
I know that i can use custom event in my-component:
with send event :
this.$emit('call', 'data');
but i just want call only exampleMethos and my-component is Local-Registration inside 'app'.
Can I call exampleMethos without use #call in html ?
Thank you so much.
here you are,But it's not the best practice, which can result in child components and parent component coupling.
var app = new Vue({
el: '#app',
components: {
child: {
template: `<div><button #click="btnClick">call parent method</button></div>`,
methods: {
btnClick () {
this.$parent.fn()
}
}
}
},
data () {
return {
}
},
methods: {
fn(){
alert('parent method called')
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<child></child>
</div>

vuejs - bind to component data

I've created a simple component:
https://jsfiddle.net/s08yhcda/1/
<div id="app">
<button-counter>My counter: <span v-text="count"></span></button-counter>
</div>
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++"><slot></slot></button>'
})
// boot up the demo
var demo = new Vue({
el: '#app'
})
Yet I cannot bind to the inner component data (counter). How can a component expose its data to the <slot> scope? I know the "events up, props down" idea. But still I thought it would be possible to bind component data inside its scope (inside the <button-counter> element)
I prefer not using event for something that simple. Any other way?
There are multiple ways to solve this problem:
Using events
This is usually the best method, as it is expected by other Vue developer
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
click() {
this.count++;
this.$emit('input', this.count);
},
},
template: '<button v-on:click="click"><slot></slot></button>'
})
// boot up the demo
var demo = new Vue({
data() {
return {
count: 0,
};
},
el: '#app'
});
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button-counter #input="count = $event">My counter: <span v-text="count"></span></button-counter>
</div>
Using refs:
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
click() {
this.count++;
},
},
template: '<button v-on:click="click"><slot></slot></button>'
})
// boot up the demo
var demo = new Vue({
data() {
return {
mounted: false,
};
},
mounted() {
this.mounted = true;
},
computed: {
count() {
return this.mounted ? this.$refs.counter.count : 0;
},
},
el: '#app'
});
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button-counter ref="counter">My counter: <span v-text="count"></span></button-counter>
</div>
Using slot-scope
Using slot scope, you can pass multiple arguments to the parent slot:
// Define a new component called button-counter
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
click() {
this.count++;
},
},
template: '<button v-on:click="click"><slot :count="count"></slot></button>'
})
// boot up the demo
var demo = new Vue({
el: '#app'
});
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button-counter>
<span slot-scope="prop">
My counter:
<span v-text="prop.count"></span>
</span>
</button-counter>
</div>
You can send data to the slot. Look at this example:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++"><slot :count="count" /></button>'
})
<div id="app">
<button-counter>
<template scope="props">
My counter: <span>{{ props.count }}</span>
</template>
</button-counter>
</div>
https://jsfiddle.net/s08yhcda/2/

Categories