Declaring data in Vue with components - javascript

According to the docs, this is how you declare data in Vue:
data: {
name: 'Vue.js'
}
However, when I do that it doesn't work and an error shows in the console:
The "data" option should be a function that returns a per-instance value in component definitions.
I change it to the following and then it works fine:
data() {
return {
name: 'Vue.js',
}
}
Why do the Vue docs show the top bit of code when it doesn't work? Is there something wrong on my end?
Edit: This only happens when using components.

In a root Vue instance (which is constructed via new Vue({ . . . }), you can simply use data: { . . . } without any problems.
When you are planing to reuse Vue components using Vue.component(...) or using "template" tag, Use data attribute as a function.
Please review the corresponding section of the Vue.js documentation for more information regarding this problem
https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function

You should declare data in Vue.js by doing
var app = new Vue({
el: '#app', //This is the container in which Vue will be in. The #app means the id of the container is app
data: {
}
});

It turns out you need to declare data in components different than when you set it on a Vue object.
Instead, a component’s data option must be a function, so that each instance can maintain an independent copy of the returned data object:
More: Vue docs

Related

How to set vue-data after new vue and work for data-binding

e.g:
I need to add data-value after new vue and work for data-binding.
why i need to do that :
I know it's work if i declare first on new Vue object.
But there's a old project with a lot of layout-subject-page,if i need to add a vue global varible then i need to edit every page's vue data-value.
what i expected :
var app = new Vue({
el: '#app',
data: {}
})
app.$data.message = "test"
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>{{ message }}</h1>
</div>
It can't be done.
Vue runs internal setup on the initially declared data properties which won't happen if you try to declare them later.
From the docs:
Vue does not allow dynamically adding new root-level reactive properties to an already created instance.
You can add new object/array items using Vue.set if that helps you.

Get script file outside of vue2 scope

I need to detect if adblocker is being used on my site, from googling around the most common method of checking this is to create a ads.js or adverts.js file and then display a message if that has been blocked.
This file has been set up however I am having trouble accessing this file when it needs to be outside of the vue scope in a vue componenet, any suggestions?
You might need to register independent js file's to the window object, then inside your component, you can call the object or function. For example, if your ads.js contain like as follow snippet
function block(){
// console.log('i am gonnna show this ')
}
In your vue component
var newData = new Vue({
el: '#app',
data: {
demo:'',
},
methods: {
fetchData: function (data) {
window.block()
}
},
created: function () {
window.block()
}
})
Like above the code you can achieve.

Where to use the main variable of a new vue instance

I'm obviously missing the point somewhere here, but where does one use the main variable of a new vue instance?
I'm new to vue.js (obviously) and whilst reading various documentation I can't help notice that each new vue instance starts with something like var app = new Vue({ but then in the examples I've read this app variable doesn't get referenced again in the js or html. The code works fine without referencing it anywhere.
Could someone please kindly advise on where or why I would use the app variable?
Many thanks
It's completely not required to capture the result of new Vue() if you don't need or want to.
The reason it's done is primarily for testing (ala from the console) or for interaction with external libraries. Because all of the methods and data of the Vue are available on the variable it's possible to call those methods and use that data from outside Vue.
For example, let's say I have some logic on my page completely outside Vue that has some data I want to use inside my Vue.
const externalData = {message:"I'm some interesting data."}
const myVueApp = new Vue({
el: "#app",
data:{
message: null
}
})
myVueApp.message = externalData.message
Here the code is setting the message property of Vue from outside Vue.
This is useful primarily when you have existing code, and you are integrating Vue into that existing environment.
Another scenario is just plain testing. Open your console and run the snippet below. Change the context to the snippet's javascript:
And then type
app.message = "Hey, this is nifty!"
And the new message will be reflected in the Vue.
console.clear()
const app = new Vue({
el: "#testing",
data:{
message: "Change me from the console!"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="testing">
{{message}}
</div>

vue JS not propagating changes from parent to component

I am pretty new to Vue Framework. I am trying to propagate the changes from parent to child whenever the attributes are added or removed or, at a later stage, updated outside the component. In the below snippet I am trying to write a component which shows a greeting message based on the name attribute of the node which is passed as property from the parent node.
Everything works fine as expected if the node contains the attribute "name" (in below snippet commented) when initialized. But if the name attribute is added a later stage of execution (here for demonstration purpose i have added a set timeout and applied). The component throws error and the changes are not reflected . I am not sure how I can propagate changes for dynamic attributes in the component which are generated based on other events outside the component.
Basically I wanted to update the component which displays different type of widgets based on server response in dynamic way based on the property passed to it .Whenever the property gets updated I would like the component update itself. Why the two way binding is not working properly in Vuejs?
Vue.component('greeting', {
template: '#treeContainer',
props: {'message':Object},
watch:{
'message': {
handler: function(val) {
console.log('###### changed');
},
deep: true
}
}
});
var data = {
note: 'My Tree',
// name:"Hello World",
children: [
{ name: 'hello' },
{ name: 'wat' }
]
}
function delayedUpdate() {
data.name='Changed World';
console.log(JSON.stringify(data));
}
var vm = new Vue({
el: '#app',
data:{
msg:data
},
method:{ }
});
setTimeout(function(){ delayedUpdate() ;}, 1000)
<script src="https://vuejs.org/js/vue.js"></script>
<div id="app">
<greeting :message="msg"></greeting>
</div>
<script type="text/x-template" id="treeContainer">
<h1>{{message.name}}</h1>
</script>
Edit 1: #Craig's answer helps me to propagate changes based on the attribute name and by calling set on each of the attribute. But what if the data was complex and the greeting was based on many attributes of the node. Here in the example I have gone through a simple use case, but in real world the widget is based on many attributes dynamically sent from the server and each widget attributes differs based on the type of widget. like "Welcome, {{message.name}} . Temperature at {{ message.location }} is {{ message.temp}} . " and so on. Since the attributes of the node differs , is there any way we can update complete tree without traversing through the entire tree in our javascript code and call set on each attribute .Is there anything in VUE framework which can take care of this ?
Vue cannot detect property addition or deletion unless you use the set method (see: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats), so you need to do:
Vue.set(data, 'name', 'changed world')
Here's the JSFiddle: https://jsfiddle.net/f7ae2364/
EDIT
In your case, I think you are going to have to abandon watching the prop and instead go for an event bus if you want to avoid traversing your data. So, first you set up a global bus for your component to listen on:
var bus = new Vue({});
Then when you receive new data you $emit the event onto the bus with the updated data:
bus.$emit('data-updated', data);
And listen for that event inside your component (which can be placed inside the created hook), update the message and force vue to re-render the component (I'm using ES6 here):
created(){
bus.$on('data-updated', (message) => {
this.message = message;
this.$forceUpdate();
})
}
Here's the JSFiddle: https://jsfiddle.net/9trhcjp4/

Understanding props in vue.js

I'm working through the guide for learning vue.js, got to the section on props, and ran into a question.
I understand that child components have isolated scops and we use the props configuration to pass data into it from the parent, but when I try it out I can't get it to work.
I have the example I'm working on up on js fiddle:
var vm = new Vue({
el: '#app',
// data from my parent that I want to pass to the child component
data:{
greeting: 'hi'
},
components:{
'person-container':{
// passing in the 'greeting' property from the parent to the child component
props:['greeting'],
// setting data locally for the child
data: function (){
return { name: 'Chris' };
},
// using both local and parent data in the child's template
template: '<div> {{ greeting }}, {{ name }}</div>'
}
}
});
When I run the above code, my output is only:
, Chris
The data local to the child component renders fine, but the passed in parent's data is either not coming through or is not properly rendering.
I don't see any errors in the javascript console and the template is rendering.
Am I misunderstanding how the props are supposed to be passed in?
You have to bind the value to the component prop like this:
<person-container v-bind:greeting="greeting"></person-container>
Jsfiddle
https://jsfiddle.net/y8b6xr67/
Answered here:
Vue JS rc-1 Passing Data Through Props Not Working
I've updated your fiddle
<person-container :greeting="greeting"></person-container>
You need to pass props from the parent to the child on the html component.
You can also pass any string to "greeting" by just setting it like normal html attribute, without using v-bind directive.
<person-container greeting="hi"></person-container>
Will also work. Note that anything you pass that way will be interpreted as plain string.
<person-container greeting="2 + 2"></person-container>
Will result in "2 + 2, Chris".
More in user guide: https://v2.vuejs.org/v2/guide/components.html#Props

Categories

Resources