How to add props to Vue component programatically? - vue.js

I'm using ag-grid for vue, and in order to create a custom cell template, you need to define a Vue component and set it as the template, so this is how I define the column:
{
headerName: "Name",
field: "name",
template: NameLinkCell
},
And ag-grid injects into NameLinkCell, the params property for you to use:
<template>
<div class="flex center-v">
<router-link :to="{name:'policy',params:{id: id}}">{{name}}</router-link>
</div>
</template>
<script>
import Vue from "vue";
import router from "#/router";
export default Vue.extend({
router,
computed: {
id() {
return this.params.data ? this.params.data.id : "-1";
},
name() {
return this.params.data ? this.params.data.name : "";
}
}
});
</script>
I would like to create a generic component so I need this part to be dynamic:
:to="{name:'policy'
The problem is it is a metadata prop and not part of the params object passed to the component, how can I pass this extra property?

Related

Pass data from blade to vue and keep parent-child in sync?

I know that in Vue parents should update the children through props and children should update their parents through events.
Assume this is my parent component .vue file:
<template>
<div>
<my-child-component :category="category"></my-child-component>
</div>
</template>
<script>
export default {
data: {
return {
category: 'Test'
}
}
}
</script>
When I update the category data in this component, it will also update the category props in my-child-component.
Now, when I want to use Vue in Laravel, I usually use an inline template and pass the value from the blade directly to my components (as for example also suggested at https://stackoverflow.com/a/49299066/2311074).
So the above example my my-parent-component.blade.php could look like this:
#push('scripts')
<script src="/app.js"></script>
#endpush
<my-parent-component inline-template>
<my-child-component :category="{{ $category }}"></my-child-component>
</my-parent-component>
But now my-parent-component is not aware about the data of category. Basically only the child knows the category and there is no communication between parent and child about it.
How can I pass the data from blade without breaking the parent and child communication?
I just had to pass the category to the inline-template component through props like this:
#push('scripts')
<script src="/app.js"></script>
#endpush
<my-parent-component :initcategory="{$category}}" inline-template>
<my-child-component v-model="category"></my-child-component>
</my-parent-component>
In my-parent-component I had to set the props and initialize is using the create method:
export default {
props: {
initcategory: '',
},
data() {
return {
category: '',
};
},
created(){
this.category = this.initcategory;
}
}
Now my my-parent-component is fully aware of the category and it can communicate to the child using props and $emit as usual.
Your reference to this answer is different altogether from what you are looking for!
He's binding the :userId prop of the example component but not the parent component or in simple words: Any template using the example vue can either pass a string prop or bind :userId prop to a string variable. Following is similar:
<example :userId="{{ Auth::user()->id }}"></example>
OR
<example :userId="'some test string'"></example>
So you should rather assign {{ $category }} to a data variable but rather binds to a child component prop which will have no effect on the parent.
In the following snippet you're only binding the string but rather a data key:
<my-child-component :category="{{ $category }}"></my-child-component>
Update
See the following example which will change the h1 title after 3 seconds
// HelloWorld.vue
<template>
<app-name :name="appName" #appNameChanged="appName = $event"></app-name>
</template>
<script>
export default {
props: ['name'],
data() {
return {
appName: null
}
},
mounted() {
// NOTE: since Strings are immutable and thus will assign the value while objects and arrays are copied by reference
// the following is just for the purpose of understanding how binding works
this.appName = this.name;
}
}
</script>
The template which renders the app title or you can say the child component
// AppName.vue
<template>
<h1>{{ name }}</h1>
</template>
<script>
export default {
props: ['name'],
mounted() {
setTimeout(() => {
this.$emit('appNameChanged', 'Change App')
}, 3000);
}
}
</script>
And here's how it is being used in the welcome.blade.php
<div id="app">
<hello-world :name="'Laravel App'"></hello-world>
</div>

How do I manipulate Getters in computed property before using it in the html template?

I am mapping getters from my Vuex store as a computed property and want to manipulate the property (its an array of objects) before using it in the component template. Any idea how I can do that?
I have tried watching the computed property but that doesn't work.
import {mapGetters} from 'vuex
computed: {
...mapGetters([
'property'
])
}
You can use your getter in another custom property like you will do for a simple variable :
<template>
<div>
<div v-for="item in transformedItems" :key="item">{{item}}</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['items']),
transformedItems() {
return this.items.map(item => item.name)
}
}
}
</script>
And then you can use transformedItems in your template

Vue js how to use props values to v-model

I have two component namely App.vue and hello.vue
In App component I import the hello component and use props to pass relevant data to the hello component.
there I bind data which are took from the App component.
In my hello component I have a input box bind to the passed value.
My final goal is pass values as props to the hello component and change it and finally
pass that edited values to the backend using the save method.
How do I achive this?
This is what I have done up to now.
App.vue
<template>
<div id="app">
<hello-world :msg="'hello good morning'"></hello-world>
</div>
</template>
<script>
import helloWorld from "./components/HelloWorld";
export default {
components: {
helloWorld
}
};
</script>
hello.vue
<template>
<div>
<input type="text" :value="msg">
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
}
};
</script>
In my hello component's input field v-model is not possible. I want something similar to the v-model.
You cannot use prop to bind to v-model. Child component is not supposed to modify prop passed by the parent component.
You will have to create a copy of prop in your child component if you wish to use prop with v-model and then watch prop like this:
<template>
<div>
<input type="text" #input="onInput" v-model="msgCopy">
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return { msgCopy: '' };
},
methods: {
onInput(newInputValue) {
this.$emit('msgChange', newInputValue);
}
}
watch: {
msg(newVal) {
this.msgCopy = newVal;
}
}
};
</script>
Also, notice the use of event handler #input to pass changed prop back to the parent component via event. As a syntax sugar, you can make your Hello component work as a custom form input control by adopting to v-model lifecycle.

How can I pass parameters from vue custom element to a vue component?

I don't have a whole vue app, so I use custom elements to replace some elements that should be handled with vue.
I simply want to use the vue multiselect plugin in a html file.
So I tried the following:
index.ts
import Vue from "vue"
import VueCustomElement from 'vue-custom-element'
import Autocomplete from "./vue/autocomplete.vue"
Vue.use(VueCustomElement);
Vue.customElement('auto-complete', Autocomplete);
test.html
<auto-complete
v-model="value"
:options="options"
placeholder="test"
#search-change="getData"
>
</auto-complete>
test.vue
<template>
<multiselect v-model="value" :options="options" #search-change="getData"></multiselect>
</template>
<script type="ts">
const Multiselect = require('vue-multiselect').default
export default {
components: { Multiselect },
data () {
return {
value: 'test',
options: ['list', 'of', 'options']
}
},
methods: {
getData (query) {
console.log(123)
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
In the output the data of the custom element is always ignored and only the parameters in the part in the .vue file is used.
How can i achieve that the parameters like placeholder or #search-change are used from the custom element?
I am also using vue-custom-elements in one of my projects.
You are passing option as props so you need to add it as a prop in your autocomplete.vue.
<template>
<multiselect v-model="value" :options="options" #search-change="getData"></multiselect>
</template>
<script type="ts">
const Multiselect = require('vue-multiselect').default
export default {
props: ['options'],
components: { Multiselect },
data () {
return {
value: 'test'
}
},
methods: {
getData (query) {
console.log('123')
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

What's the correct to modify VUE component via javascript?

javascript
(function(exports){
Vue.component('my-component',{
props: {
name: String
},
template: '<div>\
<h1>name: {{name}}</h1>\
</div>\
'
});
var myApp = new Vue({
el: '#myApp'
});
exports.app = myApp;
});
html
<div id="myApp">
<my-component name="yo!" ref="test"></my-component>
</div>
console or javascript to access component
app.$refs.test.name = "yo man";
Then console display Vue Warning as following.
What's the correct to modify VUE component via javascript?
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "name"
(found in component )
What you should be doing is binding the name directive to a variable in the parent app.
(function(exports){
Vue.component(
'my-component',
{
props: {
name: String
},
template: '<div><h1>name: {{name}}</h1></div>'
}
);
var myApp = new Vue(
{
el: '#myApp',
data: {
name: "Yo!"
}
}
);
exports.app = myApp;
}
))();
And your HTML
<div id="myApp">
<my-component v-bind:name="name" ref="test"></my-component>
<button v-on:click="name = 'Yo man'">Change</button>
</div>
JSFiddle