Vue.js change template data - vue.js

I have the following code:
Vue.component('greeting', {
template: `<h1>{{ greeting }}</h1>`,
data: function () {
return {
greeting: app.text
}
},
});
var app = new Vue({
el: '.app',
data: {
text: 'Hello'
},
methods: {
changeText: function () {
this.text = 'Goodbye'
}
}
});
So when I call changeText method it changes text but greeting in the component is not updated. I didn't understand if I should use props, watcher or computed property in this case.

You need to pass it as a prop to the component:
Vue.component('greeting', {
template: `<h1>{{ greeting }}</h1>`,
props: ['greeting']
});
and the html:
<greeting :greeting="text"></greeting>

Related

How to pass dynamic props to vue's render function?

I try to render components dynamically based on descriptions.
From
{component: 'customComponent', props: {value: "val1"}, ...}
I'd render
<custom-component :value="val1" #input="v=>val1=v" />`
I aim to do this for arbitrary events and dynamic props.
I have no idea though how to pass dynamic props to render.
Partial solution:
A solution that works but re-renders everytime val1 changes, based on (https://symfonycasts.com/screencast/vue/vue-instance) is
render: function(h){
const template = "...building up the html here..."
return Vue.compile(template).render.call(this, h);
}
My attempt using the VueJS docs
I could not find in the docs on render how I could pass dynamic variables.
In the minimal implementation you can see how far I've got, if you can help me finish it, it would be awesome!
Minimal implementation so far
I expect to see 'hello' instead of 'values.value1' and values.value1 should update once I change the text in the text box.
demo.html:
<!DOCTYPE html>
<html>
<body>
<div id="q-app">
The text input should say 'hello' instead of 'values.value1'
<custom-component :descriptor="mainComponent"></custom-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.15.15/dist/quasar.umd.min.js"></script>
<script>
Vue.component('custom-component', {
props: ['descriptor'],
render: function (createElement) {
const attributes = {
on: this.descriptor.events,
props: this.descriptor.props
}
return createElement(
this.descriptor.component,
attributes)
}
})
const app = new Vue({
el: '#q-app',
data: function(){
return {
mainComponent: {
component: 'q-input',
props: {
value: 'values.value1'
},
events: {
input: value => this.values.value1 = value
}
},
values: {
value1: 'hello'
}
}
}
})
</script>
</body>
I guess, I have fixed your example.
Of course, you can watch the value in the main app. But it is better to sent an input event with the value.
Added the reference to the component
ref="mc"
and the input event binding
#input="logEventValue"
Vue.component('custom-component', {
props: ['descriptor'],
render: function (createElement) {
const attributes = {
on: this.descriptor.events,
props: this.descriptor.props
}
return createElement(
this.descriptor.component,
attributes)
}
})
const app = new Vue({
el: '#q-app',
data: function(){
return {
mainComponent: {
component: 'q-input',
props: {
value: 'hello'
},
events: {
input: value => {
this.values.value1 = value;
// with ref="mc"
this.$refs.mc.$emit('input', value);
// or over the list of children
this.$children[0].$emit('input', value);
}
}
},
values: {
value1: 'hello'
}
}
},
watch: {
'values.value1': (newVal) => console.log(`1. watcher: ${newVal}`),
// or deeply
values: {
handler(newVal) {
console.log(`2. watcher: ${newVal.value1}`)
},
deep: true,
}
},
methods: {
logEventValue(value) {
console.log(`logEventValue: ${value}`);
}
}
})
<div id="q-app">
<custom-component ref="mc" #input="logEventValue" :descriptor="mainComponent"></custom-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.15.15/dist/quasar.umd.min.js"></script>

I need fresh eyes to fix VUE props not working

This is a silly task in VUE.JS... but I'm missing it.
I have a sub parent component having:
<teamPlayers :teamId="team.id_team"></teamPlayers>
The value teamId is sent to the child component and it works: I can see the value in child template <h2>{{teamId}}</h2> properly.
But in same child component I got undefined inside the methods using this.teamId.
Here the whole child code:
export default {
props: ['teamId'],
methods: {
getJokess: function () {
console.log(this.teamId);
},
},
created() {
this.getJokess();
}
}
The console should return the correct value but it returns undefined instead of the {{teamId}} is render perfectly.
All that I can think of is that teams may not be declared in your data() function. If it isn't it won't be reactive. Consider the example below:
const teamPlayers = {
props: ["teamId"],
methods: {
getJokess() {
console.log(this.teamId);
}
},
created() {
this.getJokess();
},
template: "<h2>{{teamId}}</h2>"
};
const app = new Vue({
el: "#app",
components: {
"team-players": teamPlayers
},
data() {
return {
teams: []
};
},
mounted() {
setTimeout(() => {
this.teams = [{
id_team: "fizz"
},
{
id_team: "buzz"
},
{
id_team: "foo"
},
{
id_team: "bar"
}
]
}, 1000);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="team of teams">
<team-players :team-id="team"></team-players>
</div>
</div>

How to destroy vuejs component from outside of component

I have created one of component in vuejs something like this
var tree_data = Vue.extend({
template: '#tree_data_template',
props: [
'groupmodal',
'search-name',
'tree-id'
], // props in single quotes
data: function () {
return {
shared: d2d.store
};
}
});
And use this component in another template like this.
var template_data = Vue.extend({
template: '#template_data',
created: function () {
var self = this;
self.shared.setCurrentRoute('templates');
},
components: {
'tree-data': tree_data
},
data: function () {
return {
id: this.$route.params.id,
shared: d2d.store,
};
},
methods: {
destroyComponent: function () {
//Need to code for destroy tree-data component
}
}
});
Blade file code
<tree-data
groupmodal="false"
search-name="user_search"
tree-id="user_tree"
>
</tree-data>
So finally how can i destroy my "tree-data" component through the "destroyComponent()" method
As cobaltway said you can use v-if
Setting v-if initially to false will render(generate) the component.
Then in your method setting v-if to true will destroy the component.
html
<div id="template_data">
<tree-data v-if="destroyComponent"></tree-data>
</div>
script
var template_data = Vue.extend({
template: '#template_data',
created: function () {
var self = this;
self.shared.setCurrentRoute('templates');
},
components: {
'tree-data': tree_data
},
data: function () {
return {
id: this.$route.params.id,
shared: d2d.store,
destroyComponent:true
};
},
methods: {
destroyComponent: function () {
//Need to code for destroy tree-data component
this.destroyComponent = false;
}
}
});
Here is the fiddle

Where I should place handler of emit?

I have child component and want to pass some data to it's parent.
My child component looks like:
// <button #click="sendClick($event)">Send</button>
// ...
data: function (){
return {
mycode: ""
}
},
methods: {
sendClick(e)
{
bus.$emit('change', this.mycode);
}
}
My parent component looks:
var app = new Vue({
el: '#app',
data: {
currentView: 'past-form',
mycode: ''
},
methods:
{
changeView()
{
this.currentView = 'past-form'
console.log(this.mycode);
},
},
created()
{
bus.$on('change', function(mycode){
this.mycode = mycode;
});
}
})
I haven't found a better place for placing bus.$on (bus is declared globally) than in created(), but the docs state that created() is for stuff that should be initialized after the page is loaded. The created() block works; I checked it by placing in it console.log(this.mycode), but should I move emit handler somewhere else?
It's look like my code does not execute mycode: '', because console.log(this.mycode); does not print anything.
As I mentioned in the comment, if your component is a direct child of your Vue, then there is no need for a bus.
That said, the created handler is fine for adding your bus event handler.
I expect the issue you have is a this issue. Try changing your handler to
bus.$on('change', mycode => this.mycode = mycode)
See How to access the correct this inside a callback?
Here is an example.
console.clear()
const bus = new Vue()
Vue.component("child", {
template: `<button #click="sendClick($event)">Send</button>`,
data: function() {
return {
mycode: "something"
}
},
methods: {
sendClick(e) {
bus.$emit('change', this.mycode);
}
}
})
var app = new Vue({
el: '#app',
data: {
currentView: 'past-form',
mycode: ''
},
methods: {
changeView() {
this.currentView = 'past-form'
console.log(this.mycode);
},
},
created() {
bus.$on('change', mycode => {
this.mycode = mycode
this.changeView()
})
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
<child></child>
Parent mycode: {{mycode}}
</div>

VueJS Extends Methods and Data

I would like to extend methods. Example:
Vue.extend({
data: function () {
return {
fetcData: 'Test',
}
},
methods: function(){
return {
modal: function(){ alert('Modal') },
}
}
});
Vue.extend({
....
});
I use multiple extends.
// VueJS Instance
new Vue({
el: 'html',
data: {
effect: true
},
methods: {
xhrGet: function () {
alert(this.fetcData); // Undefined
this.modal(); // Undefined
},
xhrPost: function (event) {
alert('xhrPost')
}
}
});
Error Code:
this.fetchData is undefined.
this.modal is not a function
Vue.extend returns a new Vue component definition that can be later on instantiated using new keyword, it doesn't change the global Vue object. So if you want to create a component hierarchy try:
var BaseComponent = Vue.extend({
methods: {
foo: function() { console.log('foo') }
}
})
var MyComponent = BaseComponent.extend({
methods: {
bar: function() {
this.foo()
console.log('bar')
}
}
})
let myComponentInstance = new MyComponent()
Check out that fiddle for a live example.