what's wrong with this vuejs "prop down" example - javascript

i am new to vuejs, when i go over its document, I can't get this sample code from its "component" section work:
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="example">
<input type="text" v-model="parentMsg">
<br>
<child v-bind:message="parentMsg"></child>
</div>
Javascript:
Vue.component('child', {
props: ['message'],
template: '<span>testing: {{ message }}</span>'
})
new Vue({
el: '#example'
})
my understand: the value of the model can be passed on to the message properties of the child component, a string of the same content will be shown after "testing: " as soon as I key in anything in the input textbox. It didn't happen.
I tested the code from jsfiddle

The Vue instance of #example should have data parentMsg. Then, child and parent can use it. So, you need to add data at Vue instance.
new Vue({
el: '#example',
data: function() {
return { parentMsg: "Hi" };
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://unpkg.com/vue"></script>
</head>
<script type="text/javascript">
Vue.component('child', {
props: ['myMessage'],
template: '<div>{{ myMessage }}</div>'
});
Vue.component('two-items-child', {
props: ['firstName', 'lastName'],
template: '<div><div>{{ firstName }}</div><div>{{ lastName }}</div></div>'
});
</script>
<body>
<div id="app">
<input id="inputParent" type="text" placeholder="parent" v-model="parentMsg">
<br>
<child my-message="Hi Vue."></child>
<two-items-child v-bind="wholeObj"></two-items-child>
<child :my-message="parentMsg"></child>
</div>
<script type="text/javascript">
// root instance
var vm = new Vue({
el: '#app',
data: {
parentMsg: "first msg",
wholeObj: {
firstName: "Hong",
lastName: "Gil-dong"
}
}
});
</script>
</body>
</html>
Check above example at example.
The example has data as an object but it is not a good way. Also check it data must be a Function

The parent component needs to have parentMsg as a data attribute, otherwise it won't be reactive.
new Vue({
el: '#example',
data() {
return {
parentMsg: ''
}
}
})

Related

Passing values to vue

I can pass a value from a main to my vue instance (another script) but won't work :(
<script>
let data = [{id:'1'}] //JUST SAMPLE
function pass_to_vue(data){
return data
}
</script>
<script>
var app = new Vue({
el: '#app',
data: {
external_value: pass_to_vue // HERE RECEIVE EXTERNAL VALUE
}
})
</script>
Thanks!
Please take a look at snippet below:
let ext = [{id:'1'}]
function pass_to_vue(data){
return data
}
document.querySelector('#ext').innerText = JSON.stringify(ext)
var app = new Vue({
el: '#demo',
data() {
return {
external_value: ''
}
},
mounted() {
this.external_value = pass_to_vue(ext)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
vue value
{{ external_value }}
<p>change id</p>
<input v-model="external_value[0].id" />
<hr />
</div>
<p>external value</p>
<p id="ext"></p>

Clear vue input fields after emitting event

I have a Vue component with an input and a button.
I would like the button to send off the input elsewhere and then clear the input. The latter part, is not happening.
Here is a rough runnable version of what I have:
new Vue({
el: '#root',
template: `
<div>
<input type='text' v-model='name'/>
<button #click='onClickMe'>Click me</button>
</div>
`,
methods: {
onClickMe () {
this.$emit('set-this-elsewhere', { name: this.name })
this.name = ''
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="root">
</div>
You see the error in the console?
Property or method "name" is not defined on the instance but referenced during render
You need to add
data() {
return {
name:''
};
},
new Vue({
el: '#root',
template: `
<div>
<input type='text' v-model='name'/>
<button #click='onClickMe'>Click me</button>
</div>
`,
data() {
return {
name: ''
};
},
methods: {
onClickMe() {
this.$emit('set-this-elsewhere', {
name: this.name
})
this.name = ''
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="root">
</div>

Bind a vue input that doesn't exist yet to a data property

We are using Vex in our application for all the dialog messages. I have an input in one of the dialogs that is used to filter a list of items.
In my Vue instance, I want to listen for the changes on a data property.
The problem is that Vue doesn't get the changes as I type them in the input box. I am thinking this is due to the fact that the input is added to the DOM after the Vue initialization.
How would I approach this so my Vue instance can listen to the input changes? I've done my best to recreate the scenario in it's most simple form in the snippet below.
new Vue({
el: '#app',
data: {
filter: ''
},
methods: {
openModal: function() {
vex.dialog.open({
input: [
'<h2>Filter</h2>',
'<input v-model="filter" />',
'<p>{{filter}}</p>'
].join('')
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vex-js/4.0.0/js/vex.combined.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vex-js/4.0.0/css/vex.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button v-on:click="openModal">Open Modal</button>
</div>
The issue is that you are providing plain html in strings to the vex.dialog.open method. Vue won't have any idea that you have done this and so none of the Vue syntax that you've included in those strings will be interpreted as it would in a Vue component definition.
What you should do is make a Vue component for that input, and then pass that input's element via a ref to the vex.dialog.open method. That way, Vue will have compiled the template before it's used in the dialog.
Here's a simple example:
Vue.component('my-input', {
template: `
<div>
<h2>Filter</h2>
<input v-model="filter"/>
<p>{{filter}}</p>
</div>
`,
data() {
return {
filter: ''
}
}
});
new Vue({
el: '#app',
data() {
return {
modalOpened: false
}
},
methods: {
openModal() {
vex.dialog.open({
input: this.$refs.input.$el
});
this.modalOpened = true;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vex-js/4.0.0/js/vex.combined.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vex-js/4.0.0/css/vex.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="openModal">Open Modal</button>
<my-input v-show="modalOpened" ref="input"/>
</div>

What is difference between 'data:' and 'data()' in Vue.js?

I have used data option in two ways. In first snippet data object contains a key value, however, in second data is a function. Is there any benefits of individuals.Not able to find relevant explanations on Vue.js Docs
Here are two code snippets:
new Vue({
el: "#app",
data: {
message: 'hello mr. magoo'
}
});
new Vue({
el: "#app",
data() {
return {
message: 'hello mr. magoo'
}
}
});
Both are giving me the same output.
It seems as though the comments on your question missed a key point when considering your specific code example.
In a root Vue instance i.e. constructed via new Vue({ ... }), you can simply use data: { ... } without any problems. The issue is when you have reusable components that are defined via Vue.component(...). In these instances, you need to either use data() {return { ... };} or data: function() {return { ... };}.
The reason for this is to ensure that for each individual instance of the reusable child component, there is a unique object containing all of the data being operated on. If, in a child component, you instead use data: { ... }, that same data object will be shared between the child components which can cause some nasty bugs.
Please review the corresponding section of the Vue.js documentation for more information regarding this problem.
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
so initiating a new vue instance dose not matter between data:{} as a object or data(){return{}} or data:function(){return{}}.
It matters when it comes to component lets try an example:
<body>
<div id="app">
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component('counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: {
counter:0
}
});
</script>
Output:
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
Now lets watch in vue object:
<body>
<div id="app">
<button v-on:click="counter += 1">{{ counter }}</button>
<button v-on:click="counter += 1">{{ counter }}</button>
</div>
<script>
new Vue({
el: '#app',
/*data() {
return {
counter:0
}
},*/
//or (output same)
/*data: function () {
return {
counter: 0
}
}*/
//or (output same)
data:{
counter:0
}
});
</script>
</body>
//Now let's try data as a function in the component to reuse same component over and over again.
<body>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component('counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
}
})
new Vue({
el: '#app'
});
</script>
</body>

Is it possible to append a component on a button press?

Here's a problem that I want to solve:
I have a button that when is pressed must append my-component to a dom.
If it is pressed 2 times there must be 2 <p> tegs. How can I achieve this?
js:
<script>
Vue.component('my-component', {
template: "<p>hello</p>",
})
var vue = new Vue({
el: "#App",
data: {},
methods: {
append: function() {
// unknown code here
}
}
})
</script>
html:
<div id = "App">
<button #click="append" class="btn btn-primary">Spawn stuff!</button>
</div>
Here is one way you could do that. This code iterates over a counter using v-for to iterate over a range.
Vue.component('my-component', {
template: "<p>hello</p>",
})
var vue = new Vue({
el: "#App",
data: {
hellocount: 0
},
methods: {
append: function() {
// unknown code here
this.hellocount++
}
}
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="App">
<my-component v-for="n in hellocount" :key="n"></my-component>
<button #click="append" class="btn btn-primary">Spawn stuff!</button>
</div>
This is a little atypical; normally you will drive the components rendered from actual data, as #RoyJ suggests in your comments.
From your comment below, you could build a form something like this.
Vue.component('my-input', {
props:["value", "name"],
data(){
return {
internalValue: this.value
}
},
methods:{
onInput(){
this.$emit('input', this.internalValue)
}
},
template: `
<div>
{{name}}:<input type="text" v-model="internalValue" #input="onInput">
</div>
`,
})
var vue = new Vue({
el: "#App",
data: {
form:{
name: null,
email: null,
phone: null
}
},
methods:{
append(){
const el = prompt("What is the name of the new element?")
this.$set(this.form, el, null)
}
}
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="App">
<my-input v-for="(value, prop) in form"
:key="prop"
v-model="form[prop]"
:name="prop">
</my-input>
<button #click="append">Add New Form Element</button>
<div>
Form Values: {{form}}
</div>
</div>
The code defines a form object and iterates over the properties of the form to render inputs for each property.
This is obviously extremely naive, handles only input texts, etc. But hopefully you get the idea.

Categories

Resources