Short hand to pass boolean props to Vue component - javascript

In the Vue docs for components it says:
Including the prop with no value will imply true:
<blog-post favorited></blog-post>
However, when I try it on my component, it doesn't work (related fiddle):
<!-- html -->
<div id="app">
<test-component visible></test-component>
</div>
<template id="template">
<span>open: {{ open }}; visible: {{ visible }}</span>
</template>
<!-- JS -->
const TestComponent = Vue.extend({
template: '#template',
props: ['visible'],
data: function() {
return { 'open': true }
}
});
new Vue({
el: "#app",
components: {
'test-component': TestComponent
}
});
Is this a bug or am I doing something wrong?

I would also expect it to work as it is, but it seems you need to specify the type of field in the props declaration:
props: {
'visible': {
type: Boolean
}
}
This makes it work correctly

Related

Data from Blade File not rendering in Vue Component

I am working in Laravel Blade and trying to convert some blade files to vue components. I have a property in my blade file of pagetitle. I am trying to get the dynamically created page title to render on the screen from my vue component and not blade. But in my vue console, data comes back as "". Not sure why the data is carrying over.
Header.vue
<template>
<div>
<p title="page-title">{{pageTitle}}</p>
</div>
</template>
<script>
export default {
props: {
pageTitle: {
type: String
}
}
}
</script>
app.js
window.Vue = require('vue');
import Header from './components/Header';
Vue.component('header', Header);
const app = new Vue({
el: '#app',
});
main.blade.php
<div id="app">
<header :page-title="{{$pageTitle}}"></header>
</div>
header.blade.php //where page title is being pulled from
<title>
{{ $pageTitle ?? 'Default Page Title' }}
</title>
In your Header.vue file you are defining pageTitle as a data property, while it should be defined as a prop, since you are actually providing it as a property on the header component.
props: {
pageTitle: {
type: String
}
}
There already exists an HTML element called header, I suggest you rename your component. Your component is missing a props attribute to take input from blade:
Pagetitle.vue:
<template>
<div>
<p title="page-title">{{ this.pageTitle}}</p>
</div>
</template>
<script>
export default {
props: ['title'],
data() {
return {
pageTitle: '',
};
},
created() {
this.pageTitle = this.title
}
}
</script>
We created a title property. When the component is created, we set the component's pageTitle to the title given in main.blade.php.
app.js
window.Vue = require('vue');
import Pagetitle from './components/Pagetitle';
Vue.component('pagetitle', Pagetitle);
const app = new Vue({
el: '#app',
});
main.blade.php
<div id="app">
<pagetitle :title="foo bar"></pagetitle>
</div>
https://v2.vuejs.org/v2/guide/components-props.html

Unable to set VueJs Component data values from component prop

For some reason, the value for customer_data.customerReference is never available yet I can see using Chrome debugging tools that the data exists in the prop and is successfully passed from my app down to the component.
Vue.component("mycomponent", {
template: '#my-component-template',
props: ["customer_data"],
data() {
return {
myData: 'This works fine!',
form_data: {
customerRef: this.customer_data.customerReference
}
}
}
});
new Vue({
el: "#app",
data() {
return {
customer: {
customerReference: 007
}
};
}
});
Here is my markup including the template:
<div id="app">
<mycomponent customer_data="customer" />
</div>
<script type="x-template" id="my-component-template">
<div>
<p>{{form_data.customerRef}}</p>
<p>{{myData}}</p>
</div>
</script>
Please see the following JsFiddle with a simplified example:
https://jsfiddle.net/ProNotion/a8c6nqsg/20/
What is that I am missing here or implementing incorrectly?
You should bind it using v-bind: or just :
<div id="app">
<mycomponent :customer_data="customer" />
</div>
https://v2.vuejs.org/v2/guide/components-props.html
You're passing in a string that says 'customer' and not the actual customer object. All you need to do is change customer_data="customer" to v-bind:customer_data="customer"

How to pass data from Vue.js to Blade view?

I just can't find a way to pass my data from vue.js component to blade view in my Laravel project. I tried to use hidden inputfield but data binding returns [object Object].
Any help would be appreciated.
Create a variable in the root component data object and change it from the child component so assuming resources/js/components/ExampleComponent.vue like this
<template>
<div class="container">
<input v-model="field" type="text">
</div>
</template>
<script>
export default {
data() {
return {
field: ''
}
},
watch: {
field: function (val) {
this.$root.bladeValue = val;
}
}
}
</script>
and a resources/js/app.js like so
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
const app = new Vue({
el: '#app',
data() {
return {
bladeValue: ''
}
}
});
and a blade view like so resources/views/welcome.blade.php
<div id="app">
<example-component></example-component>
<h1>#{{ bladeValue }}</h1>
</div>
<script src="/js/app.js"></script>
Then bladeValue will be binded to field in ExampleComponent

VueJS 2 show some HTML if a Function prop was passed

Question
In VueJS 2 how do you show some HTML if a Function prop was passed to the component.
Example
<template>
<div v-if="backBtn" #click="$emit('backBtn')">Back Button</div>
</template>
<script>
export default {
props: {
backBtn: Function
}
}
</script>
I can do this by passing a separate prop to key the v-if off of but I'm trying to do this will the one prop.
I created a Fiddle for this issue here
that should work,
you can add more definition with !== undefined
<template>
<div v-if="backBtn !== undefined" #click="$emit('backBtn')">Back Button</div>
</template>
<script>
export default {
props: {
backBtn: {
type: Function,
},
}
}
</script>
but as mentioned, that should work already, so you error may be somewhere else.
after seeing your code, I see what the issue is. it's a case issue
use :back-btn instead of :backBtn
this happens only if you're using vue runtime only (without the compilation)
read more here:
https://v2.vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
you can solve it also by passing the function only
https://jsfiddle.net/rz6hyd7b/7/
Vue.component('my-btn', {
props: {
backbtn: {
type: Function
}
},
template: `
<div>
<div v-if="backbtn" #click="backbtn">Back Button</div>
</div>
`
})
var vm = new Vue({
el: '#app',
components: 'my-btn',
methods: {
btnClicked: function(){
console.log('adsf')
}
},
template: `
<div>
Show Btn => <my-btn :backbtn="btnClicked"></my-btn>
</br>
Hidden Btn => <my-btn></my-btn>
</div>
`
});

Vue instance inside Vue instance

Sup people!
I got this HTML code here:
// index.html
<div data-init="component-one">
<...>
<div data-init="component-two">
<button #click="doSomething($event)">
</div>
</div>
This basically references a Vue instance inside another Vue instance if I understood everything correctly. The respective JS code is split up in two files and looks like this:
// componentOne.js
new Vue(
el: '[data-init="component-one"]',
data: {...},
methods: {...}
);
// componentTwo.js
new Vue(
el: '[data-init="component-two"]'
data: {...}
methods: {
doSomething: function(event) {...}
}
);
Now, the problem with this is, that doSomething from componentTwo never gets called.
But when I do some inline stuff, like {{ 3 + 3 }}, it gets computed like it should. So Vue knows there is something. And it also removes the #click element on page load.
I tried fiddling around with inline-template as well, but it doesn't really work as I'd expect it to in this situation. And I figured it isn't meant for this case anyway, so I dropped it again.
What would the correct approach be here? And how can I make this work the easiest way possible with how it's set up right now?
The Vue version we use is 2.1.8.
Cheers!
The problem is that you have two vue instances nested to each other.
If the elements are nested, then you should use the same instance or try components
https://jsfiddle.net/p16y2g16/1/
// componentTwo.js
var item = Vue.component('item',({
name:'item',
template:'<button #click="doSomething($event)">{{ message2 }</button>',
data: function(){
return{
message2: 'ddddddddddd!'
}},
methods: {
doSomething: function(event) {alert('s')}
}
}));
var app = new Vue({
el: '[data-init="component-one"]',
data: {
message: 'Hello Vue!'
}
});
<div data-init="component-one">
<button >{{ message }}</button>
<item></item>
</div>
Separate instances work if they are independant of each other.
as follows:
https://jsfiddle.net/p16y2g16/
var app = new Vue({
el: '[data-init="component-one"]',
data: {
message: 'Hello Vue!'
}
});
// componentTwo.js
var ddd = new Vue({
el: '[data-init="component-two"]',
data: {
message: 'ddddddddddd!'
},
methods: {
doSomething: function(event) {alert('s')}
}
});
But when I do some inline stuff, like {{ 3 + 3 }}, it gets computed like it should. So Vue knows there is something.
Because you have parent instance 'componentOne'. It activated Vue for this template. If you need to set another instance inside, you have to separate part of template. Example (it can lag in snippet!) .
Alternative
https://jsfiddle.net/qh8a8ebg/2/
// componentOne.js
new Vue({
el: '[data-init="component-one"]',
data: {
text: 'first'
},
methods: {}
});
// componentTwo.js
new Vue({
el: '[data-init="component-two"]',
data: {
text: 'second'
},
template: `<button #click="doSomething($event)">{{text}}</button>`,
methods: {
doSomething: function(event) {
console.log(event);
}
}
});
<script src="https://vuejs.org/js/vue.min.js"></script>
<div data-init="component-one">
{{text}}
</div>
<div data-init="component-two">
</div>
The button element inside component-two is referenced as a slot in Vue.
The evaluation of the #click directive value happens in the parent component (component-one, which host component-two). Therefor, you need to declare the click handler over there (over component-one).
If you want the handler to be handled inside component-two, you should declare a click directive for the slot element in it's (component-two) template, and pass the handler function, for instance, as a pop.
good luck.
You're doing everything right except you've nested the 2nd Vue instance inside the 1st. Just put it to the side and it will work as expected.
Vue ignores binding more than once to the same element to avoid infinite loops, which is the only reason it doesn't work nested.
Use vue-cli to create a webpack starter app. vue init app --webpack
Then, try to structure your components this way. Read more: https://v2.vuejs.org/v2/guide/components.html#What-are-Components
This is main.js
import Vue from 'vue'
import ComponentOne from './ComponentOne.vue'
import ComponentTwo from './ComponentTwo.vue'
new Vue({
el: '#app',
template: '<App/>',
components: {
ComponentOne,
ComponentTwo
}
})
This is ComponentOne.vue
<template>
<div class="user">
<div v-for="user in users">
<p>Username: {{ user.username }}</p>
</div>
</div>
</template>
<script>
export default {
data () {
return {
users: [
{username: 'Bryan'},
{username: 'Gwen'},
{username: 'Gabriel'}
]
}
}
}
</script>
This is ComponentTwo.vue
<template>
<div class="two">
Hello World
</div>
</template>
<script>
export default {
}
</script>
<div th:if="${msg.replyFloor}">
<div class="msg-lists-item-left">
<span class="msg-left-edit"
th:classappend=" ${msg.unreadCount == 0} ? 'msg-all-read' ">您在</span>
<span th:text="${msg.topic.title}"
class="msg-left-edit-res"
th:classappend=" ${msg.unreadCount == 0} ? 'msg-all-read' ">问题回答</span>
<span th:text="${msg.type.name}"
class="msg-left-edit "
th:classappend=" ${msg.unreadCount == 0} ? 'msg-all-read' ">帖子相关</span>
<span class="msg-left-edit-number" >
产生了<span th:text="${msg.unreadCount} ? : ${msg.unreadCount} + '条新' : ${msg.unreadCount} + '条' "
th:class="${msg.unreadCount} ? : 'number-inner':''">2132条</span>回复
</span>
</div>
<div class="msg-lists-item-right">
<span th:text="${msg.lastShowTime}">2017-8-10</span>
</div>
</div>

Categories