Show value in template in VueJS - vue.js

I have some code below, I want show "header" in template and show or hide when header not null.
<div id="hung">
<cmx-test v-bind:header="${properties.header}"></cmx-test>
</div>
<script>
Vue.component('cmx-test', {
props: ['header'],
template: '<h1 class=\"fillColor\" data={{this.header}}></h1>'
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#hung'
});
</script>

There is some syntax mistake in your code, to insert text into tag you can achieve with v-text attribute not data={{this.header}}.
And if you wanna hide some tag or component based on data value, you can use v-if.
And the last thing is if you wanna pass value intro component you can achieve that with this way v-bind:header="value", and value is variable which hold value you wanna pass.
<div id="hung">
<cmx-test v-if="header" v-bind:header="value"></cmx-test>
<button #click="header = true">Display</button>
</div>
<script>
Vue.component('cmx-test', {
props: ['header'],
template: '<h1 class=\"fillColor\" v-text="header"></h1>'
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#hung',
data: {
header: null,
value: "Hello World!"
}
});
</script>

Your question is not totally clear. You have the component receiving the prop header but header is not defined on the main Vue instance. You need to be passing that prop from the main data object / Vue instance into the component to use it there.
<div id="hung">
<cmx-test v-if="header" :header="header"></cmx-test>
</div>
<script>
Vue.component('cmx-test', {
props: ['header'],
template: '<h1 class=\"fillColor\" :data="header">{{header}}</h1>'
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#hung'
data:{
header: null,
}
});
</script>
Also using the same data object header to control whether the component is rendered or not using v-if. So if header is null or false it wont be rendered. When it becomes true or contains a value it will be rendered and the value of header will be passed to component through binding it (e.g. :header="header")

Related

How to display stub component when component is not found in vue

I am trying to catch situation, when component is not found, ie:
{
template: '<some-unknown-component></some-unknown-component>'
}
At that moment, Vue warns us with unknown custom element: <some-unknown-component>...
I would like to step in when some-unknown-component is not found and then use another component instead, like stub-component:
{
name: 'stub-component',
props: ['componentName'],
template: '<p>component ${componentName} does not exists, click here to create...</p>'
}
UPDATE: I am looking for solution without changing the template itself, so no v-if and component added.
Vue exposes a global error and warning handler. I managed to get a working solution by using the global warnHandler. I don't know if it is exactly what you are looking for, but it may be a good starting point. See the working snippet (I think it is quite self explanatory).
Vue.config.warnHandler = function (err, vm, info) {
if (err.includes("Unknown custom element:")) {
let componentName = err.match(/<.*>/g)[0].slice(1, -1)
vm.$options.components[componentName] = Vue.component('stub-component', {
props: ['componentName'],
template: `<p>component "${componentName}" does not exists, click here to create...</p>`,
});
vm.$forceUpdate()
} else {
console.warn(err)
}
};
new Vue({
el: '#app',
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<unknown-component></unknown-component>
</div>
Vue stores the details of all the registered components in the $options.component property of the Vue instance.
So, you can check for the component availability using this.$options.component and if the component is present then load the component otherwise load the other component.
In the below example, suppose you have two different components and you want to load them on the availability, then you can create a computed property on the basis of it, load the component as needed.
var CustomComponent = Vue.extend({ template: '<h2>A custom Component</h2>' });
var AnotherComponent = Vue.extend({ template: '<h2>Custom component does not exist.</h2>' });
new Vue({
el: "#app",
components: {
CustomComponent,
AnotherComponent
},
computed: {
componentAvailable () {
return this.$options.components.CustomComponent
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-if="componentAvailable">
<custom-component />
</div>
<div v-else>
<another-component />
</div>
</div>

Vue data vue object variables from component

I am very new to Vue and I am having difficulty accessing data in main Vue instance from component. In the Vue instance I have:
var vm = new Vue({
computed: {},
data: {
show: true
},
and in the component, I want to do something like:
<button v-show="vm.show" #click="setDefaults(styleguide)">Set Default</button>
My goal is when 'show' value changes, I want to display/hide the button. It is little difficult/weird because I create template in the component, not in the html. When I try this code, it doesn't understand 'vm.show'. I feel like I need to create data in the component and tie the data to the 'show' variable, or create computed in the component or something (I believe computed is like watcher?). If there is easy way to handle this, please help.
I'm also new to VueJs, but I believe the issue is you haven't provided the el argument to the Vue instance, and in this case assigning the Vue instance to a variable doesn't do anything.
I think you want something like
<div id="app">
<button v-show="show" #click="setDefaults(styleguide)">Set Default</button>
</div>
<script>
new Vue({
el: '#app',
computed: {},
data: {
show: true
},
...
);
</script>
So I guess my question wasn't very clear, but I got it to figure it out. In the component code, I needed to add:
Vue.component('styleguide', {
computed: {
show: function () {
return vm.show
}
},
props: ['styleguide'],
template: `
<div>
<div>
<p>
<button v-show="show" #click="setDefaults(styleguide)">Set Default</button>
This allows me to access 'show' in the main Vue instance from the component template. Whenever other component modifies 'show' variable in the main Vue instance, the button disappears/reappears. I am not sure if this makes sense, but this is how I got it to work.
Two things, in the template all variables are already scoped from the component so you don't need the vm. in there. The second thing is that the data property of a component expects a function which returns an object.
var vm = new Vue({
computed: {},
data: () => ({
show: true
}),
<button v-show="show" #click="setDefaults(styleguide)">Set Default</button>
If you need to access data from a parent component you will need to pass it on using props. you can also try to do it using provide/inject if that suits your usecase better

Vue - Nesting components without separating into single page

I am new in Vue and try to learn how the component structure works in Vue.
below is my code in codepen.
Nesting Components
<div id="todolist">
<first-layer>
<second-layer></second-layer>
</first-layer>
</div>
<script>
var secondLayer = Vue.extend({
template: '<div>i am second layer.</div>'
});
var firstLayer = Vue.extend({
template: '<div>I am first layer.</div>',
components: secondLayer,
});
var todolist = new Vue({
el: "#todolist",
components: {
'first-layer': firstLayer,
}
});
<script>
What I try to do is to separate component out of its parent by declare an object then call it in components property.
It worked at first layer.
But, when I try to do same thing in a component ( like nesting them) with same moves, the second layer didn't show up as expected. Why is that?
And what is the recommended structure to handle these without .vue file sep
This is happening because Vue overrides any template you put inside <first-layer> with the component's template.
To prevent it, you can use slots:
var firstLayer = Vue.extend({
template: '<div>I am first layer1.<slot></slot></div>'
});
now every content you put between <first-layer> tag will go into this slot.
If you want a more complicated component with different slots, you can use named slots
Use second-layer inside first-layer template as
template: '<div>I am first layer1.<div><second-layer></second-layer></div></div>',
Working example
var secondLayer = Vue.extend({
template: '<div>i am second layer2.</div>'
});
var firstLayer = Vue.extend({
template: '<div>I am first layer1.<div><second-layer></second-layer></div></div>',
components: {
'second-layer': secondLayer,
}
});
var todolist = new Vue({
el: "#todolist",
components: {
'first-layer': firstLayer,
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.6/vue.js"></script>
<div id="todolist">
<first-layer>
</first-layer>
</div>
using <first-layer> tag means it will be replacef by template what ever you put inside this will be lost, to paas some param we can bind like <first-layer :name='name'> thats why your example is not working with nested tag

Vuejs modal component cannot reference method

I have a modal dialog which is trying to use a method on the Vue app instance but getting the error
app.js:32117 [Vue warn]: Property or method "calcFees" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
The app declaration
Vue.component('sale', require('./components/Sale.vue'));
const app = new Vue({
el: '#app',
data: {
showModal: false
},
methods: {
calcFees: function (event) {
alert('GOOD');
}
}
});
Sale.vue component minimised for now
<template name="sale">
<input type="text" placeholder="Sale Price" class="form-control" #blur="calcFees">
</template>
The sale component is simply included in the main page here
<sale v-if="showModal"></sale>
The modal dialog works fine, displays the above text input however the above error is shown in the console and the blur event doesn't call the method.
It seems it has something to do with the component template, because i tested the blur event successfully by putting a text input in the main blade page directly.
Any ideas why it doesn't work in this way? I saw a comment somewhere about something to do with it being a <template> but it didn't explain how to fix.
Components cannot access methods declared in other components or the root Vue directly.
The problem with this code is that the calcFees method is declared in the root Vue, but you are trying to call it from the Sale.vue component.
There are several ways to make this work. One is you can move calcFees to the component. Another is you can $emit an event to the parent with whatever it needs to use in calcFees.
Sale.vue
<template name="sale">
<input type="text" v-model="price" placeholder="Sale Price" class="form-control" #blur="onSale">
</template>
<script>
export default {
data(){
return {
price: null
}
},
methods: {
onSale(){
this.$emit('sale', this.price)
}
}
}
</script>
Vue
<sale v-if="showModal" #sale="calcFees"></sale>
const app = new Vue({
el: '#app',
data: {
showModal: false
},
methods: {
calcFees: function (price) {
alert(price);
}
}
});

What's the correct to modify VUE component via javascript?

javascript
(function(exports){
Vue.component('my-component',{
props: {
name: String
},
template: '<div>\
<h1>name: {{name}}</h1>\
</div>\
'
});
var myApp = new Vue({
el: '#myApp'
});
exports.app = myApp;
});
html
<div id="myApp">
<my-component name="yo!" ref="test"></my-component>
</div>
console or javascript to access component
app.$refs.test.name = "yo man";
Then console display Vue Warning as following.
What's the correct to modify VUE component via javascript?
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "name"
(found in component )
What you should be doing is binding the name directive to a variable in the parent app.
(function(exports){
Vue.component(
'my-component',
{
props: {
name: String
},
template: '<div><h1>name: {{name}}</h1></div>'
}
);
var myApp = new Vue(
{
el: '#myApp',
data: {
name: "Yo!"
}
}
);
exports.app = myApp;
}
))();
And your HTML
<div id="myApp">
<my-component v-bind:name="name" ref="test"></my-component>
<button v-on:click="name = 'Yo man'">Change</button>
</div>
JSFiddle