Vue 2.0 - How passing function to child component? - javascript

I have one issue. I want to pass function link to the child component. It's working but in HTML I get that code. It's correct how improve it?
I have Vue instance
app = new Vue({
... some code
data: {
onAppClose: null,
onAppSend: null
}
})
I want to add from global window any function. Or register function in Vue instance
app.onSend = () => console.log('data')
And pass this function to child
<div id="app">
<dynamsoft-component v-if="displayComponent"
:docs="docs"
:onAppSend="onSend"
:onAppClose="onClose"
></dynamsoft-component>
</div>
But I get this HTML template in console
<div id="app">
<div onappsend="()=>{}" onappclose="function (data) {
console.warn('dwdawad')
console.log('data')
}"></div>
</div>

You example code is not making a lot of sense - do you want to add a listener not a div or pass a function to a child component?`
I assume the latter. Vue has custom events for that .
Parent template:
<div v-on:appsend="someMethod" v-on:appclose="someOtherMethod"></div>
Parent component methods:
methods: {
someOtherMethod: function (data) {
console.warn('dwdawad')
console.log('data')
},
// ...
}
And then emit form the child:
this.$emit('appclose', {id: 'whatever'} /*pass data here*/)
Edit:
I still don't see how those functions would end up directly in the template, but the real problem is: HTML is not case-sensitive. so :onAppSend becomes :onappsend. You have to use kebap-case: :on-app-send. Vue will convert it to onAppSend in the component.

I have never used Vue.js before now..
But having a look at the how to on their site, this seems to work
In Vue style guide have recommendations about props naming
https://v2.vuejs.org/v2/style-guide/#Prop-name-casing-strongly-recommended
Vue.component('dynamsoft-component', {
props: ['onAppSend'],
template: '<button v-on:click="buttonclick">click me</button>',
methods: {
buttonclick(e){
// Check if onAppSend is defined.
if(Boolean(this.onAppSend)){
this.onAppSend();
}
}
}
})
new Vue({
el: '#app',
methods: {
onSend: function(){
console.log('child clicked');
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<dynamsoft-component :on-app-send="onSend"></dynamsoft-component>
</div>

Related

How to access data property of vue component

I am new to Vue.js and I think its amazing. I have been tasked to start implementing some vue components in our non-greenfield web application and I thought I would start by implementing some self-contained "widgets" that have to deal heavily with state in my work's rails app.
Its working great as a self-contained component but I want to load it with a data attribute so the component know what it needs to deal with. My Vue file looks like (I have redacted parts of this due to IP concerns):
<template>
<div class="card">
<div class="card-body">
${{ b.id }}
</div>
<div class="card-footer bg--blue-sky">
${{ b.amount }}
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
errors: [],
b: {
id: null,
amount: null
}
}
},
// Fetches posts when the component is created.
created: function () {
jQuery.ajax({
url: "/api/b/" + '2' + ".json",
method: 'GET',
dataType: "json"
})
.then(response => {
this.b = response.b
})
.catch(e => {
this.errors.push(e)
});
}
}
</script>
<style scoped>
</style>
The component is registered with:
import FiDis from '../components/fi_dis.vue'
Vue.component('fi_dis', FiDis);
document.addEventListener('turbolinks:load', () => {
const fi_dis = new Vue({
el: '#bs',
components: { FiDis }
})
});
And in my html.erb code I create the components with:
<div id="bs" policy="2">
<fi_dis data-b-id="1"></fi_dis>
<fi_dis data-b-id="2"></fi_dis>
</div>
This all works flawlessly, and does exactly what I want it to do except for one thing. I want to access the data-b-id attribute within the created function of the component (i.e. replace the number '2' in the url of the ajax call above with the value form the attribute). In this way, I hope for the component to handle ANY "fi_dis" I choose, merely by specifying the b-id in the data attribute I want it to handle.
How can I achieve this?
You communicate data values passing props from parent component to child components.
So for example you should define which props your component is allowed to receive:
import FiDis from '../components/fi_dis.vue'
Vue.component('fi_dis', FiDis);
document.addEventListener('turbolinks:load', () => {
const fi_dis = new Vue({
el: '#bs',
components: { FiDis },
props['bId'],
created() { // This is a lifecycle method
this.printPropertyValue();
},
methods: {
// Your custom methods goes here separeted by commas
printPropertyValue() {
console.log(this.bId);
}
}
})
});
And the sintax for passing the data from the component implementation is using v-bind:propertyName or :propertyName (short hand).
<div id="bs" policy="2">
<fi_dis :bId="1"></fi_dis>
<fi_dis :bId="2"></fi_dis>
</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>

how to share data between components in VUE js (while creating list)

Could you please tell me how to share data between components in VUE js (while creating list).I have two components list components and add todo component.I want to add items in list when user click on add button.But issue is input field present in different component and list is present in different component
here is my code
https://plnkr.co/edit/bjsVWU6lrWdp2a2CjamQ?p=preview
// Code goes here
var MyComponent = Vue.extend({
template: '#todo-template',
props: ['items']
});
var AddTODO = Vue.extend({
template: '#add-todo',
props: ['m'],
data: function () {
return {
message: ''
}
},
methods: {
addTodo: function () {
console.log(this.message)
console.log(this.m);
//this.m =this.message;
},
},
});
Vue.component('my-component', MyComponent);
Vue.component('add-todo', AddTODO)
var app = new Vue({
el: '#App',
data: {
message: '',
items: []
},
});
The whole point of having a great MVVM framework is to let you have a view-model: a central store of all the state in your page/app/whatever. Components can emit events. You can have an event bus. But if you can save the day with a simple, global variable containing all your state, this is by far the cleanest, best solution. So just put your to-dos in an array, in a variable in global scope, then declare them in the data of every component that needs them. Here it is working in Plunkr.
markup
<div id="App" >
<add-todo></add-todo>
<my-component></my-component>
</div>
<template id="add-todo">
<div>
<input type="text" v-model="message">
<button #click="addTodo">Add todo</button>
</div>
</template>
<template id="todo-template">
<div>
<ul >
<li v-for="(item,index) in store.items">
{{item.message}}
</li>
</ul>
</div>
</template>
<script src="vue.js"></script>
<script src="script.js"></script>
code
// This is the magic store. This is all you need.
var vueStore = {items : []};
var MyComponent = Vue.extend({
template: '#todo-template',
data : function(){return {store : vueStore}}
});
var AddTODO = Vue.extend({
template: '#add-todo',
data: function () {
return {
message: '',
store : vueStore
}
},
methods: {
addTodo: function (event) {
this.store.items.push({'message' : this.message})
},
},
});
Vue.component('my-component', MyComponent);
Vue.component('add-todo', AddTODO)
var app = new Vue({
el: '#App',
data: {
store : vueStore
},
});
This is not a savage hack! We're being called to stop thinking about events, move up the food chain, and think about reactive pipes. Components don't care when or by who the central store gets updated. Vue takes care of it.
Here's the page on state management.
So you could use events and emit the created todo to the root vue instance.
I edited / forked your plunkr (I'm rather the fiddle type).
https://plnkr.co/edit/bnMiDmi30vsj3a8uROBK?p=preview
So I edited this line here, which listens for a custom event added and pushes the first argument to items.
<add-todo v-on:added='items.push(arguments[0])'></add-todo>
And also these lines, which emit the event. And i changed from the property m to the data message, because you shouldnt mutate props:
<input type="text" v-model="message">
<button #click="$emit('added', message)">Add todo</button>

vuejs prototype array not being watched

in my vuejs program i am trying to make a global instance of an alert/notification system. This would be at the rootmost instance of the app. and then my plan was to push to an array of objects and pass that through to the component.
This only half works.
in my app.vue i have
<template>
<div id="app">
<alert-queue :alerts="$alerts"></alert-queue>
<router-view></router-view>
</div>
</template>
in my main.js i have
exports.install = function (Vue, options) {
Vue.prototype.$alerts = []
}
and my alert_queue.vue is
<template>
<div id="alert-queue">
<div v-for="alert in alerts" >
<transition name="fade">
<div>
<div class="alert-card-close">
<span #click="dismissAlert(alert)"> × </span>
</div>
<div class="alert-card-message">
{{alert.message}}
</div>
</div>
</transition>
</div>
</div>
</template>
<script>
export default {
name: 'alert',
props: {
alerts: {
default: []
}
},
data () {
return {
}
},
methods: {
dismissAlert (alert) {
for (let i = 0; i < this.alerts.length; i++) {
if (this.alerts[i].message === alert.message) {
this.alerts.splice([i], 1)
}
}
}
}
}
</script>
I can add to this list now by using this.$alerts.push({}) and i can see they are added by console.logging the results.
The problem is that the component doesn't recognise them unless i manually go in and force it to refresh by changing something in code and having webpack reload the results. as far as i can see, there is no way to do this programatically.... Is there a way to make prototype components be watched like the rest of the application?
I have tried making the root most file have a $alerts object but when i use $root.$alerts.push({}) it doesn't work because $root is readonly.
Is there another way i can go about this ?
You could make $alerts a Vue instance and use it as an event bus:
exports.install = function (Vue, options) {
Vue.prototype.$alerts = new Vue({
data: {alerts: []},
events: { ... },
methods: { ... }
})
}
Then in your components you might call a method this.$alerts.addAlert() which in turn pushes to the array and broadcasts an event alert-added. In other places you could use this.$alerts.on('alert-added', (alert) => { ... }
Other than that, I think this is a good use case for Vuex, which is pretty much designed for this: https://github.com/vuejs/vuex
Properties defined on Vue.prototype are not reactive like a Vue instance's data properties.
I agree that, in most cases, Jeff's method or using Vuex is the way to go.
However, you could simply set this.$alerts as a Vue instance's data property and then updating that property (which would be reactive) would, by association, update the global $alerts array:
Vue.prototype.$alerts = ['Alert #1'];
Vue.component('child', {
template: `<div><div v-for="i in items">{{ i }}</div></div>`,
props: ['items'],
})
new Vue({
el: '#app',
data() {
return {
globalAlerts: this.$alerts,
}
},
methods: {
addToArray() {
this.globalAlerts.push('Alert #' + (this.globalAlerts.length + 1));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.1/vue.min.js"></script>
<div id="app">
<child :items="$alerts"></child>
<button #click="addToArray">Add alert</button>
</div>

How to keep data in component when using v-with in Vue js

So here is my problem:
I want to make a component that takes it's values from v-with="values" and add them to my component model after some modification, then display those modified properties.
But from what I understand, when I set values with "v-with", component data are erased so the binding between my component data (not v-with one) and my directives are lost.
I'm really new to this framework, I don't see any solution, so I guess it was time to ask my first question here !
Here is the HTML:
<script type="text/x-template" id="my-template">
<p v-on="click:reloadParentMsg">Msg parent : {{ParentMsg}}</p>
<p v-on="click:reloadChildMsg">Msg child : {{ChildMsg}}</p>
</script>
<div id="myVue">
<my-component v-with="ParentData" ></my-component>
</div>
And here is the Javascript:
Vue.component('my-component', {
template: '#my-template',
data: function () {
return {
ChildMsg: "wololo"
}
},
methods:{
reloadParentMsg : function(){
this.ParentMsg="Parent";
console.log(this.ParentMsg);
},
reloadChildMsg : function(){
this.ChildMsg="Child";
console.log(this.ChildMsg);
}
}
})
var myVue = new Vue({
el: '#myVue',
data: {
ParentData:{ParentMsg: "gloubiboulga"}
}
})
And the js fiddle http://jsfiddle.net/KwakawK/hfj1tv4n/3/
I'm not totally clear on what you're trying to do, but I believe it can be solved by using the second form of v-with, which is v-with="childProp: parentProp". Rather than the parent property overriding all of the child data, this will replace only the property on the left of the colon.
So I think your code can be fixed by changing the v-with to this:
<my-component v-with="ParentMsg: ParentData.ParentMsg" ></my-component>
Here's the updated code as a snippet:
// register the grid component
Vue.component('my-component', {
template: '#my-template',
data: function () {
return {
ChildMsg: "wololo"
}
},
methods:{
reloadParentMsg : function(){
this.ParentMsg="Parent";
console.log(this.ParentMsg);
},
reloadChildMsg : function(){
this.ChildMsg="Child";
console.log(this.ChildMsg);
}
}
})
// bootstrap the demo
var myVue = new Vue({
el: '#myVue',
data: {
ParentData:{ParentMsg: "gloubiboulga"}
}
})
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/0.11.4/vue.min.js"></script>
<script type="text/x-template" id="my-template">
<p v-on="click:reloadParentMsg">Msg parent : {{ParentMsg}}</p>
<p v-on="click:reloadChildMsg">Msg child : {{ChildMsg}}</p>
</script>
<div id="myVue">
<my-component v-with="ParentMsg: ParentData.ParentMsg" ></my-component>
</div>
See the Vue guide for more information.

Categories

Resources