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

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.

Related

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>

Why I am unable to get the value using v-for?

I want to get the values of "1999-00" (which is a part of stateStats data property) through a function xyz() defined in computed property but I am unable to do so.
Does anyone have some idea about it?
var app = new Vue({
el: "#app",
data(){
return {
stateStats : [{"State":"Andaman & Nicobar Islands","1999-00":"45"},
{"State":"Andhra Pradesh","1999-00":"27"},
{"State":"Arunachal Pradesh","1999-00":"9"}]
}
},
computed:{
xyz(){
return this.stateStats['1999-00']
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="x in xyz">
{{x}}
</div>
</div>
The computed property should be the same level as data.
var app = new Vue({
el: "#app",
data(){
return {/* whatever */}
},
computed : {
xyz(){
return this.stateStats.map( s => s['1999-00']);
}
}
});
You can use Array map function to get the desired property out of your array of objects.
var app = new Vue({
el: "#app",
data(){
return {
stateStats : [{"State":"Andaman & Nicobar Islands","1999-00":"45"},
{"State":"Andhra Pradesh","1999-00":"27"},
{"State":"Arunachal Pradesh","1999-00":"9"}]
}
},
computed:{
xyz(){
return this.stateStats.map(state => state["1999-00"]);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="x in xyz">
{{x}}
</div>
</div>

Unable to pass data to vue template

I am trying to pass the name from data to my settingTemplate.
However, I have not been able to make it work. Could anyone advice how I should approach this? I am new to Vue.
app.js
var app = new Vue({
el: '#app',
components: {
settingTemplate
},
data: {
name: 'Elon'
}
})
setting-template.js
const settingTemplate = {
template:
`<div class="d-flex flex-column text-md-center">
<div class="p-2">
<b-btn id="popoverButton-disable" variant="primary"></b-btn>
</div>
<div class="p-2">
<b-popover :disabled.sync="disabled" target="popoverButton-disable" title="{{name}}">
<a>Profile</a> | <a>Logout</a>
</b-popover>
</div>
</div>`
,
data() {
return {
disabled: false
}
},
methods: {
disableByRef() {
if (this.disabled){
this.$refs.popover.$emit('enable')
}else{
this.$refs.popover.$emit('disable')
}
}
},
props: ['name']
}
You should pass name to your component by attribute, not by data:
<div id="app">
<setting-template name="Elon" />
</div>
Here you can check working example:
https://codepen.io/anon/pen/dwrOqY?editors=1111
data is component private data - it's not passed to child components.
If you still need name in your main component data you can pass it to the child component like this:
<div id="app">
<setting-template :name="name" />
</div>
var app = new Vue({
el: '#app',
components: {
settingTemplate
},
data: {
name: 'Leon'
}
})
https://codepen.io/anon/pen/qLvqeO?editors=1111

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>

Property or method "value" is not defined on the instance in vue js 2 nested component

I wrote a basic vue js 2 basic example to test nested components.
Below is components and template structure.
Vue.component('form-com', {
template: '#form',
props: ['value'],
methods: {
onInput: function (event) {
this.$emit('input', event.target.value);
}
}
});
Vue.component('message-com', {
template: '#message',
data: function () {
return {
msg: 'Hello'
}
},
props: ['user']
});
Vue.component('welcome-com', {
template: '#welcome',
data: function () {
return {
user: 'ahmad'
}
}
});
new Vue({
el: '#container'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<!--Form Template-->
<template id="form">
<div>
<div class="form-control">
<label>Enter Your Name:</label>
<input type="text" v-bind:value="value" :input="onInput">
</div>
</div>
</template>
<!--Hello Message Template-->
<template id="message">
<div>
<h3>{{msg}} {{user}}</h3>
</div>
</template>
<template id="welcome">
<div>
<form-com :value="value"></form-com>
<br>
<message-com :user="user"></message-com>
</div>
</template>
<div id="container">
<welcome-com></welcome-com>
</div>
But when run app in browser this error is shown:
[Vue warn]: Property or method "value" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
found in
---> <WelcomeCom>
<Root>
what is problem?
Update:
I just Rewrite this Fiddle from one of chapters of Learning Vue.js 2. I just rename some parameters and component and templates names. but when I copy main fiddle to my code all things worked.
In your form-com component you can set up a v-model which binds the input value and set up a watcher to observer the changes in the input which in turn emits an custom-event which telss the parent comonent that a change has taken place.
Vue.component('form-com', {
template: '#form',
data(){
return{
myInput:''
}
},
watch: {
myInput: function (inputVal) {
this.$emit('input', inputVal);
}
}
});
Vue.component('message-com', {
template: '#message',
data: function () {
return {
msg: 'Hello'
}
},
props: ['user']
});
Vue.component('welcome-com', {
template: '#welcome',
data: function () {
return {
user: 'ahmad'
}
},
methods:{
updateUser(value){
this.user = value;
}
}
});
new Vue({
el: '#container'
})
You can listen to the events emitted from the child **form-com ** component using v-on:input or shorthand #input directly in the parent template (welcome component) where the child component is used.
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<!--Form Template-->
<template id="form">
<div>
<div class="form-control">
<label>Enter Your Name:</label>
<input type="text" v-model="myInput">
</div>
</div>
</template>
<!--Hello Message Template-->
<template id="message">
<div>
<h3>{{msg}} {{user}}</h3>
</div>
</template>
<template id="welcome">
<div>
<form-com #input="updateUser($event)" ></form-com>
<br>
<message-com :user="user"></message-com>
</div>
</template>
<div id="container">
<welcome-com></welcome-com>
</div>
Here is the jsFiddle
If you don't want to use a watcher then you can do it using computed setter . Have a look at the fiddle which is using a computed-setter
You are missing in your Component 'welcome-com' the value object:
Vue.component('welcome-com', {
template: '#welcome',
data: function () {
return {
value: '',
user: 'ahmad'
}
}
});

Categories

Resources