Passing data to the modal in Vue not working - javascript

I am trying to pass data to the UserModal. But the issue I am facing here is that the value of
user_clicked field is set when the openuserdialog method runs(checked in console: the value is assigned) but I am not able to pass it as an argument to the modal. Please help me solve the problem.
<v-data-table :items="users" :disable-initial-sort="true" :mustSort="true" hide-actions>
<template slot="items" slot-scope="props">
<td>{{ props.item.file_type.name }}</td>
<td>{{ props.item.created_at | moment }}</td>
<td><a #click="openUserDialog(props.item.id, props.item.user_type)" href='javascript:void(0);' class="details-link"><span class="hidden-xs-only">UserTypes</span><span class="hidden-sm-and-up">User Types</span></a></td>
</template>
</v-data-table>
<v-dialog v-model="userDialog" max-width="1275">
<UserModal :document="user_clicked" />
<div class="text-xs-right">
<v-btn class='vue-file-button text-right' #click="closeUserDialog" >Close</v-btn>
</div>
</v-dialog>
<script>
import UserModal from 'views/users/shortlisted_users.vue';
export default {
components: {
UserModal
},
data: function() {
return {
userDialog: false,
user_clicked: ''
}
}
methods: {
openUserDialog(document_id, user_type) {
this.userDialog = true;
this.user_clicked = user_type;
console.log(this.user_clicked);
},
closeUserDialog(document_id) {
this.userDialog = false;
}
}
</script>
Update 1
openUserDialog(document_id, user_type) {
this.user_clicked = user_type;
this.userDialog = true;
console.log(this.user_clicked);
}
Update 2
<template>
<div>
<v-card id="users-card">
<Users :users="users"></Users>
</v-card>
</div>
</template>
<script>
import 'vue-awesome/icons';
import Icon from 'vue-awesome/components/Icon';
import Users from 'views/user/_user_table.vue';
export default {
components: {
Icon,
Users
},
props: ['document'],
data: () => ({
users: [],
tab_view: 'tab-users-card'
}),
created: function() {
console.log(this.document);
this.fetchUsers(this.document);
},
methods: {
fetchUsers(document) {
this.$axios.get('/my_account/users/document_suggested_users.json', {
params: {
document: document.id
}
})
.then(response => {
this.users = response.data;
})
},
}
};
</script>

The problem is that you are trying to use document in the created handler of the component which is far too early in its life-cycle.
Instead, one approach is to use a watch handler in your UserModal like this:
watch: {
document: function () {
console.log(this.document);
if (this.document) {
this.fetchUsers(this.document);
}
}
}

Try to declare your prop like so:
props: {
document: Object
}

Related

How to pass dynamically props from one child component to another on the parent page

I have two child components I have to pass dynamically props from first child to parent and from parent to second child.
Parent
<script>
data: () => ({
model: {}
}),
methods: {
changeData(payload) {
this.model.personalData = {...payload}
}
}
</script>
<template>
<first-child #changeData="(payload) => changeData(payload)"/>
<second-child :enter-object="model" />
</template>
Child one
<script>
data: () => ({
model: {}
}),
methods: {
changeData() {
this.$emit("changeData", this.model);
}
}
</script>
<template>
<v-text-field v-model="model.name" #input="changeData()">
<v-text-field v-model="model.email" #input="changeData()">
</template>
Child two
<script>
props: {
enterObject: {
type: Object,
required: false,
default: () => ({})
}
},
data: () => ({
model: {}
}),
watch: {
enterObject: {
immediate: true,
handler() {
Object.assign(this.model.personalData, this.enterObject.personalData);
}
}
</script>
<template>
<div>
<div v-if="model.personalData.name || model.personalData.email">
<span class="mr-3">{{ model.personalData.name }}</span>
<span>{{ model.personalData.email }}</span>
</div>
<div v-else>
No data
</div>
</div>
</template>
I get data in parent component with no problem, but this data doesn't pass to second child, why I have always "No data" ?
I tested your code and found a few things:
You need to create "personalData" inside the model in "childTwo".
<template>
<div>
// I changed the validation for personalData
<div v-if="model.personalData">
<span class="mr-3">{{ model.personalData.name }}</span>
<span>{{ model.personalData.email }}</span>
</div>
<div v-else>No data</div>
</div>
</template>
export default {
props: {
enterObject: {
type: Object,
required: false,
default: () => ({})
}
},
data: () => ({
model: {
personalData: {}
}
}),
watch: {
enterObject: {
deep: true,
handler() {
// Add a validation in the handler, you can use Object assign inside the validation.
if(this.enterObject) {
Object.assign(this.model.personalData, this.enterObject.personalData)
}
}
}
}
It's worked for me.I hope it helps you.
You have to assign the value of the object using this.$set for more about object reactivity click here
your Parent component should be like this:-
here is the working example
<template>
<div>
<first-child #change-data="(payload) => changeData(payload)" />
<second-child :enter-object="model" />
</div>
</template>
<script>
import FirstChild from "./FirstChild";
import SecondChild from "./SecondChild";
export default {
data: () => ({
model: {},
compKey: 0,
}),
components: {
FirstChild,
SecondChild,
},
methods: {
changeData(payload) {
this.$set(this.model, "test", payload);
//this.model.test = payload;
},
},
};
</script>

$emit functions inside promise

I've got a problem with event orders, I have one method for getting data and another to open modal with data from previous method, and it works fine, but modal is rendered before getting data, so I see previous result for a sec. I do understand that I need my methods to be called in promise, but fail to realize how to do this.
App.vue
<v-app>
<v-main>
<h1 class="text-center text-uppercase">Gallery</h1>
<Cards
:images="images"
#addImage="updateImage($event)"
#showModal="showPopup($event)"
/>
<Card :image="image" v-if="modal" #closeImage="toggleImage($event)" />
</v-main>
</v-app>
</template>
<script>
import Cards from "./components/Cards.vue";
import Card from "./components/Card.vue";
export default {
name: "App",
components: { Cards, Card },
data: () => ({
images: {},
image: {},
modal: false,
}),
methods: {
updateImage: function (updatedImage) {
this.image = updatedImage;
},
showPopup: function (state) {
this.modal = state;
},
toggleImage: function (state) {
this.modal = state;
},
},
};
</script>
Cards.vue
<v-row>
<v-col
v-for="image in images"
:key="image.id"
class="d-flex"
cols="4"
#click="
getImage(image.id);
toggleWindow();
"
>
<v-img :src="image.url" :id="image.id">
<template v-slot:placeholder>
<v-row class="fill-height ma-0" align="center" justify="center">
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
</v-row>
</template>
<script>
export default {
name: "Cards",
props: ["images"],
methods: {
getImage(imageId) {
fetch(`https://boiling-refuge-66454.herokuapp.com/images/${imageId}`)
.then((res) => {
if (res.status == 200) {
return res.json();
} else {
throw new Error(res.status);
}
})
.then((data) => {
this.$emit("addImage", data);
});
},
toggleWindow() {
let toggle = true;
this.$emit("showModal", toggle);
},
},
};
</script>
<style></style>
I believe this is because getImage() is an async method. It should return an Promise that resolves itself after the last then(). The last then is the one containing this.$emit("addImage", data);.
In your #click you should then wait for getImage() to be resolved before calling toggleWindow().
So something like #click="async () => { await getImage(image.id); toggleWindow();}".

Retain filled form fields on page refresh in Vue

The issue I am facing here is, I am not able to figure out how can I retain the values in the form on page refresh. Each time I refresh the page all the filled values in the form are gone.
Help me resolve this issue. I was thinking of using localStorage but not sure how I can implement it.
<template>
<v-card class="mb-12">
<v-form :model='user' class="content-padding" ref='pdfInputs'>
<div class="section-header">
User
</div>
<v-container fluid>
<ul>
<li v-for="(input, index) in user.inputs">
<input type="text" v-model="input.one"> - {{ input.one }}
<input type="text" v-model="input.two"> - {{ input.two }}
<button type="button" #click="deleteRow(index)">Delete</button>
</li>
</ul>
</v-container>
</v-form>
</v-card>
</template>
<script>
export default {
data () {
return {
user: {
inputs: []
}
}
}
methods: {
addRow() {
this.user.inputs.push({
one: '',
two: ''
})
},
deleteRow(index) {
this.user.inputs.splice(index,1)
}
}
}
</script>
There is watch functionality in vue
export default {
data () {
return {
user: {
inputs: []
}
}
},
mounted() {
this.user.inputs = JSON.parse(localStorage.getItem('form')) || [];
},
watch: {
user: {
handler: function() {
localStorage.setItem('form', JSON.stringify(this.user.inputs));
},
deep: true
}
},
methods: {
addRow() {
this.user.inputs.push({
one: '',
two: ''
})
},
deleteRow(index) {
this.user.inputs.splice(index,1)
}
}
}

How can I select just one item of items to be show in a component after click? in vue js

I need to Click the icon to show in child component "comandasInd " the data of one item
<template>
<v-data-table :items="comandas">
<template v-slot:items="props">
<td>{{ props.item.nombre }}</td>
<v-icon #click="abrirComanda(props.item)">
book
</v-icon>
</template>
</v-data-table>
...
This is the component, but open all the compenents with all the items that i have, and i only need the one i clicked:
<comandasInd
v-for="comanda in comandas"
:key= "comanda.cid"
:nombre="comanda.nombre"
#click="abrirComanda(item)">
</comandasInd>
<script>
export default {
components: { comandasInd },
data: () => ({
comandas: [],
comanda: {
nombre: '',
}
selectComanda: null,
}),
methods: {
abrirComanda(comandas) {
this.selectComanda = comandas.nombre
}
</script>
This should work (not sure if you need the #click here):
<comandasInd
v-if="selectComanda"
:key= "selectComanda.cid"
:nombre="selectComanda.nombre">
</comandasInd>
<script>
export default {
components: { comandasInd },
data: () => ({
comandas: [],
comanda: {
nombre: '',
}
selectComanda: null,
}),
methods: {
abrirComanda(comanda) {
this.selectComanda = comanda;
}
}
</script>

why can't child components get the data from parent component?

I disunderstood the documentation of passing parent component to child component.The parent component as the follow code:
<template>
<div className="fixed-table">
<basic-container>
<el-table
:data="dataSource"
border
style="width: 100%">
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="primary" size="mini" round #click="handleEdit(scope.$index, scope.row)">编辑
</el-button>
<edit-dialog ref="editDialog" :row="scope.row" :index="scope.$index" :allBaseRules="allBaseRules" :allActions="allActions"></edit-dialog>
</template>
</el-table-column>
</el-table>
</basic-container>
</div>
</template>
<script>
import BasicContainer from '#vue-materials/basic-container';
import EditDialog from "./components/EditDialog";
import HttpUtils from '../../../../components/HttpUtils.js'
export default {
components: {
BasicContainer,
EditDialog
},
name: 'FixedTable',
data() {
return {
dataSource: [],
allActions: [],
};
},
methods: {
handleEdit(index, row) {
this.$refs.editDialog.$emit("open",row);
}
},
mounted() {
let self = this;
HttpUtils.get('/api/rule/action/queryAll')
.then(function (response) {
self.allActions = response.data.data;
})
.catch(function (error) {
});
}
}
</script>
I want to parse "allActions" to child components.The child components is a dialog,I open it by control the 'dialogFormVisible'. The child components like this:
<template>
<el-dialog title="编辑业务规则" :visible.sync="dialogFormVisible" :append-to-body="true">
<el-form :model="formRow" :label-position="labelPosition" label-width="20%">
<el-form-item label="前置行为" prop="preHandlers">
<el-select v-model="preHandler" clearable placeholder="请选择">
<el-option v-for="item in allActions" :key="item.actionID" :label="item.actionName"
:value="item.actionID"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button #click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" #click="handleSubmit('ruleForm')">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
dialogFormVisible: false
preHandler: ""
};
},
computed: {
formRow() {
return Object.assign({}, this.row);
}
},
props: {
row: {
type: Object,
default: {}
},
index: {
type: Number,
default: 0
}
allActions: {
type: Array,
default: function () {
return []
}
}
},
created: function () {
this.$on('open', function (row) {
this.dialogFormVisible = true
});
}
};
</script>
However,I can't get 'allActions' from parent component. How can i get it?
When defining the attributes on an HTML element keep in mind that HTML is case insensitive. So a prop defined as allBaseRules really is seen as allbaserules. So you need to use "Kabab-case" when defining the attribute name as below.
<edit-dialog
ref="editDialog"
:row="scope.row"
:index="scope.$index"
:all-base-rules="allBaseRules"
:all-actions="allActions"
>
Vue automatically recognizes the kabab-case props and converts them to camelCase for you. So you are fine to still receive the props as you are currently.
https://v2.vuejs.org/v2/guide/components-props.html#Prop-Casing-camelCase-vs-kebab-case
See the the example here https://jsfiddle.net/skribe/1dbfj8h6/

Categories