I want to create basic sample of single file component in vue. I have configured webpack to compile my code and it works fine. Now i want to pass props to component and i get error that props is undefined.
index file
<head>
<meta charset="UTF-8">
<title>Vue Webpack Demo</title>
<script type="text/javascript" src="/dist/vue.js"></script>
</head>
<body>
<div id="mainContent">
<main-content post-title="hello!"></main-content>
</div>
</body>
<script src="/dist/index.js"></script>
index.js file
import Vue from 'vue';
import MainContent from './views/main-content';
let MainComponent = Vue.extend(MainContent);
new MainComponent().$mount("#mainContent");
main-content.vue
<template src="./main-content.html"></template>
<style scoped lang="scss" src="./main-content.scss"></style>
<script>
export default {
name: "main-content",
props: {
postTitle:{
type:String,
required:true
}
},
data: () => ({
webpack: 'Powered by webpack!?',
name:'name'
}),
}
</script>
The way you are setting up the application is awkward. There is no wrapper for the application. Following the following example to see how it can be orchestrated to finally have your component with the required prop
The index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>CodeSandbox Vue</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
The main.js where the vue application is created:
import Vue from "vue";
import App from "./App";
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: "#app",
components: { App },
template: "<App/>"
});
Now the App uses your component MainContent and passes the prop:
<template>
<MainContent post-title="Hello!"/>
</template>
<script>
import MainContent from "./views/MainContent";
export default {
name: "App",
components: {
MainContent
}
};
</script>
Finally the component reads the prop:
<template>
<div class="hello">
post-title: {{ postTitle }}
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
postTitle: {
type: String,
required: true
}
},
};
</script>
You can see this example working here
Related
I am new to Vue, Vue Router, and Vuex.
Please advise the best practice to change/update values in the component nested in the Vue Router, using Vuex store.
I wrote a simple code to change the number in the component by hitting the button but seems not working properly.
The following is the code I made:
// Trying to change the value in the component,
// but not updating the DOM, only the value in the state
function incrementValueInComponent(){
store.commit('increment');
alert("number in the store is: " + store.state.testNumber);
}
// *** Vuex store ***
const store = new Vuex.Store({
state: {
testNumber: 0
},
mutations: {
increment (state) {
state.testNumber++
}
}
});
// *** Component and Vue router ***
const Foo = {
store:store,
data(){
return {
myNumber:this.$store.state.testNumber
}
},
template: '<div>{{myNumber}}</div>' ,
}
const routes = [
{ path: '/', component: Foo }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- Vue, Vuex, Vue router-->
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/">Top Page</router-link>
</p>
<router-view></router-view>
<button class="btn" onclick="incrementValueInComponent()">Increment Number</button>
</div>
<script src="javascript.js"></script>
</body>
</html>
Am I doing something wrong or is this approach something against the concept of the Vue?
Any advice would be appreciated. Thanks in advance.
use computed
const Foo = {
store:store,
computed: {
myNumber () {
return this.$store.state.testNumber
}
}
template: '<div>{{myNumber}}</div>' ,
}
Setup
I've initialized a new project using vite on an Arch based operating system.
When I try to create the simple counter from the vue docs, the elemet doesn't render.
Code
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="counter">
Counter: {{ counter }}
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
main.js
import { createApp } from 'vue'
var CounterApp = {
data() {
return {
counter: 0
}
},
mounted() {
setInterval(() => {
this.counter++
}, 1000)
}
}
createApp(CounterApp).mount('#counter')
When I inspect the element it is commented out:
Question
Why is that? And how to resolve the error?
Doing that replaces the normal mounting process, and treats the root element like a template string for the App component. Since template strings require the runtime compiler, you would need to use a full build. There should be a console warning about that.
To avoid increasing the size of your app (by ~30%) with the full build, it's recommended to leave the mounting point untouched, and give the App component its own proper template:
index.html
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
App.vue
<template>
<div id="counter">
Counter: {{ counter }}
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
counter: 0
}
},
mounted() {
setInterval(() => {
this.counter++
}, 1000)
}
}
</script>
By default the runtime compiler is not included in the Vue build.
To include it, add the following resolve.alias configuration:
vite.config.js
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
},
},
})
Docs https://vitejs.dev/config/#resolve-alias
I want Nuxtjs render Vue-Components dynamically. In Vuejs I get it working like that. But this does not work with nuxt, which I dont understand:
https://codesandbox.io/s/young-wood-lw0gl
<html>
<head>
<title>Vue Component Blog Post Example</title>
<script src="https://unpkg.com/vue"></script>
<link rel="stylesheet" type="text/css" href="/style.css" />
</head>
<body>
<div id="dynamic-component-demo">
<component v-bind:is="testcomp" class="tab"></component>
</div>
<script>
new Vue({
el: "#dynamic-component-demo",
data: {
text: "Text",
button: "<button>Save</button>",
currentTab: "Posts",
tabs: ["Posts", "Archive"]
},
computed: {
testcomp() {
Vue.component("testcomp", {
template: `<div>Archive components ${this.text}
${this.button}
</div>`
});
return "testcomp";
}
}
});
</script>
</body>
</html>
But in Nuxtjs, it doesnt show anything
<template>
<section>
test
<component v-bind:is="testcomp" class="tab"></component>
</section>
</template>
<script>
import Vue from 'vue'
export default {
data() {
return {
text: 'Test',
button: '<button>Save</button>'
}
},
computed: {
testcomp() {
Vue.component("testcomp", {
template: `<div>Archive components ${this.text}
${this.button}
</div>`
});
return "testcomp";
}
}
}
</script>
I guess I have to wrap it into Nuxt with vue.use() somewhere or so. But I am not sure exactly
I have a basic Example Component setup which is binded to a Vue Instance like so
<template>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Example Component</div>
<div class="panel-body">
{{ msg }}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data : function(){
return{
msg : "Hello"
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
And this is my app.js file
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('example-component', require('./components/ExampleComponent.vue'));
var firstComponent = new Vue({
el: '#app'
});
This is my HTML
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
</head>
<body>
<div id="app">
<example-component></example-component>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
How can I now change the value of msg? I don't have any reference to that component anywhere? How can I do that?
Is this possible?
var ex = Vue.component('example-component', require('./components/ExampleComponent.vue'));
ex.data = "new Value";
add props property to your component and set inside it the msg property :
<script>
export default {
props:{
msg:{
type:String,
default:"Hello"
}
},
data : function(){
},
mounted() {
console.log('Component mounted.')
}
}
</script>
and
<example-component msg="new Hello"></example-component>
UPDATE
after understanding your use case i recommend to use child component ref
const ExampleComponent = Vue.component('example-component', {
template: `
<div>
<h2>Example component</h2>
<div>{{msg}}</div>
</div>
`,
data() {
return {
msg: "Hello"
}
}
});
window.root = new Vue({
el: '#app',
components: {
ExampleComponent
}
});
root.$refs.example.msg = "new hello"
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<script src="https://unpkg.com/vue#2.5.17/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>Parent</h2>
<example-component ref="example"></example-component>
</div>
</body>
</html>
TL;DR Have a look at this example, it does what you want: https://codesandbox.io/s/88ojwpjq88
You need to distinguish between data (the components private data) and props (data passed to the child component). Read this section of the Vue.js guide: https://v2.vuejs.org/v2/guide/components.html
In your component, you'll need to declare the prop:
export default {
props : ['msg'],
mounted() {
console.log('Component mounted.')
}
}
Then you can bind a data to the child component like this:
<example-component :msg="myMessage"></example-component>, assuming the parent component has myMessage declared like this:
data : function(){
return {
myMessage : "Hello"
}
}
To change the value, you can bind it to some sort of input. Here's an example w/ a text field: <input v-model="myMessage">.
If you enter sth. into this field, you should see the bound value in your component update.
Do read the manual here: https://v2.vuejs.org/v2/guide/index.html. It's really good, your questions are covered entirely in there.
Add the property to your component, make it parent-to-child, that is, you will bind the property within the component, and you can pass data to that property.
Depending on the flow, you must identify how you will do this, whether it is from father to son or from child to father. To pass data to child, you pass through props, if you pass from child to parent, you will use $ emit.
https://v2.vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props
If you use parent to child you will do it the following way.
Pai.vue
<template>
<div> {{msg}} </div>
</template>
<script>
export default {
props: {
msg: {
type: String,
default: 'Hello'
}
}
}
</script>
Ai Inside the child component you call the parameter
<template>
<div>
<parent :msg="valueMsg"/>
</div>
</template>
enter code here
son.vue
<script>
import pai from './pai'
export default {components: {parent},
data: () => ({
valueMsg = 'Hello Test'
})
}
https://jsfiddle.net/hamiltongabriel/3zr8jb7r/
I am trying to figure out how to make one component inside of another one in VueJS. For instance, something like this, which unfortunately does not work (the child component appears to do nothing):
http://www.webpackbin.com/NyI0PzaL-
I am equally interested in doing this using inline-templates as much as by using the .vue file extension method as shown above.
Here is the code from the non-working example above:
main.js
import Vue from 'vue'
import App from './App.vue'
import Child from './Child.vue'
new Vue({
el: 'body',
components: { App, Child }
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<app></app>
<script src="main.js"></script>
</body>
</html>
App.vue
<template>
<div>
<h1>{{ parent_msg }}</h1>
<child></child>
</div>
</template>
<script>
export default {
data () {
return {
parent_msg: 'Hello From the Parent!'
}
}
}
</script>
Child.vue
<template>
<h1>{{ child_msg }}</h1>
</template>
<script>
export default {
data () {
return {
child_msg: 'Hello From the Child!'
}
}
}
</script>
Even though this above example is hosted on webpackbin.com, in the two projects where I would like to use this, I am using Laravel in one along with Laravel Spark in the other. In the plain Laravel app, I'm primarily using .vue files, and in the Laravel Spark app, I'm primarily using inline-templates. I'd be especially grateful for any working samples. Thanks!
UPDATE
Thanks to Linus for his answer below. It appears I need these changes to register the child component globally in my main.js file:
import Vue from 'vue'
import App from './App.vue'
import Child from './Child.vue'
Vue.component('child', Child);
new Vue({
el: 'body',
components: { App, Child }
})
Alternatively, in order to keep the child component local to be used within the parent, I could change the parent component (App.vue) as follows:
<template>
<h1>{{ parent_msg }}</h1>
<div>
<child></child>
</div>
</template>
<script>
import Child from './Child.vue';
export default {
components: {Child},
data () {
return {
parent_msg: 'Hello from the parent component!'
}
}
}
</script>
You registered the Child component locally in the main instance, so it is not available in App.vue
Remove it form the main instance and add it to App.vue:
App.vue
<template>
<div>
<h1>{{ parent_msg }}</h1>
<child></child>
</div>
</template>
<script>
import Child from './child.vue'
export default {
data () {
return {
parent_msg: 'Hello From the Parent!'
}
},
components: {child: Child}
}
</script>
..or register it globally with Vue.component('child', Child) in your main.js file. Then it's available everywhere.