Triggering a component dialog - vuejs2

I'm attempting to learn VueJS and ElementUI to port over a legacy app. I'm very new to VueJS and am trying to get to grips with the basics. Understanding reusable components is going to be key for me, so I'm trying to get an example dialog working. Can someone help me work out why the dialog won't display when I click on the button on my Test page. I've registered the component but am unsure how I trigger it. The sample code is based on a tutorial for components I've found and ElementUI form example.
Test.vue
<template>
<el-button
type="success"
#click="dialogFormVisible = true"
size="small"
icon="el-icon-plus"
>click to open the Dialog</el-button>
<Dialog v-model="dialogFormVisible" />
</template>
<script>
import Dialog from "#/components/CustomerForm.vue";
export default {
name: "App",
components: { Dialog },
data() {
return {
dialogFormVisible: false,
};
},
methods: {
submit() {
console.log("confirm");
this.dialogFormVisible = false;
},
},
};
</script>
CustomerForm.vue
<template>
<el-dialog title="Customer Name" v-model="dialogFormVisible">
<el-form :model="form">
<el-form-item label="Activity name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="Activity zone">
<el-select v-model="form.region" placeholder="please select your zone">
<el-option label="Zone one" value="shanghai"></el-option>
<el-option label="Zone two" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Activity time">
<el-col :span="11">
<el-date-picker
type="date"
placeholder="Pick a date"
v-model="form.date1"
style="width: 100%"
></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker
placeholder="Pick a time"
v-model="form.date2"
style="width: 100%"
></el-time-picker>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" #click="submit">Create</el-button>
<el-button>Cancel</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script>
export default {
data() {
return {
dialogFormVisible: false,
form: {
name: "",
region: "",
date1: "",
date2: "",
},
formLabelWidth: "120px",
};
},
methods: {
submit() {
console.log("submit!");
},
},
};
</script>

Related

Cannot enter data into form input after using composition api in vue 3

I have the following code where I am creating a simple login form everything works file until i try to type into the form input, it seems I cannot type into the form fields.
The following is my code. I have to mention that I am not calling any server api yet.
<template>
<el-row justify="center">
<el-col :span="6" class="login">
<el-card shadow="always">
<template #header>
<span>Memeber Login</span>
</template>
<div class="login__inner">
<el-form ref="user" :model="user">
<el-form-item>
<el-input
v-model="user.email"
placeholder="Email Address"
clearable
prefix-icon="message">
</el-input>
</el-form-item>
<el-form-item>
<el-input
v-model="user.password"
placeholder="Password"
clearable show-password
prefix-icon="lock"
>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary">
<el-icon><check /></el-icon> Login
</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</el-col>
</el-row>
</template>
<script lang="js">
import { reactive } from 'vue';
export default {
setup() {
const user = reactive({
email: '',
password: '',
});
return {
user,
};
},
};
</script>
Edit: here is the image.
Image Link
The attribute ref="user" on el-form conflict with reactive user key, just use other word like ref="userForm"
See here
Try the following alternative for the <script> section:
<script lang="js">
export default {
name: "LoginForm",
data() {
return {
user: {
email: '',
password: ''
}
}
};
</script>
where LoginForm is your component name.

How can I write emit even to tell parent is icon is clicked in Vuejs

I am write input element with icon to show/hide password, how can I write event emit in v-icon to tell parent component that icon is click
Here is my child component BaseInputPassword
<div class="label">
{{ labelName }} <span v-if="required" class="required">※</span>
</div>
<div class="input_password">
<input
:type="type ? 'password' : 'text'"
:placeholder="placeholder"
/>
<v-icon #click="type =! type">{{ type ? "mdi-eye-off" : "mdi-eye" }}</v-icon>
</div>
</div>
</template>
<script>
export default {
props: ["labelName", "placeholder", "required", "type" ],
data() {
return {
};
},
methods: {
updateValue($event) {
this.$emit("input", $event);
},
}
}
</script>
Here is my parent component, im using three child component
<div class="input_area">
<BlockInputPassword labelName="現在のパスワード" required="true" :type="show1" v-model="password" ></BlockInputPassword>
<BlockInputPassword labelName="現在のパスワード" required="true" :type="show2" v-model="password" ></BlockInputPassword>
<BlockInputPassword labelName="新しいパスワードの確認" required="true" :type="show3" v-model="password"></BlockInputPassword>
</div>
</div>
<div class="footer">
<router-link to=""
><div class="btn_login btn_simple">
キャンセル
</div></router-link>
<router-link to=""
><div class="btn_login btn_simple status_color_4">
変更
</div></router-link>
</div>
</div>
</div>
</template>
<script>
import BlockInputPassword from "../components/common/BlockInputPassword"
export default {
components: {
BlockInputPassword,
},
name: "PasswordChange",
data() {
return {
password: '',
show1: false,
show2: false,
show3: false,
};
},
have you child component v-icon emit a custom event
<v-icon #click="$emit('icon-clicked')">
then from the parent component
<div class="input_area">
<BlockInputPassword #icon-click="doSomething" ...></BlockInputPassword>
...
</div>

Template slot in buefy carousel showing broken image

Hi i am newbie in vuejs and buefy. I wanted to do a carousel. However its already printing in the b-carousel-item but in template slot="indicators" it showing broken image. Can anyone help me i want to show the image also in the template slot
this is the code:
https://codesandbox.io/s/wonderful-gagarin-5wc8d?file=/src/App.vue
App.vue
<template>
<b-carousel :indicator-inside="false">
<b-carousel-item v-for="(item, i) in imgurl" :key="i">
<span class="image">
<img :src="getImgUrl(item)" />
</span>
</b-carousel-item>
<template slot="indicators" slot-scope="props">
<span class="al image">
<img :src="getImgUrl(props.item)" :title="props.item" />
</span>
</template>
</b-carousel>
</template>
<script>
export default {
data() {
return {
thumbs: null,
imgurl: [
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTE7e4ENLA4IRiYClFOOyc418WmdNTuWAAX_A&usqp=CAU",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQrMMLeNArJ-NmM-sRGGGr0ya8y0NSF4HZ8Aw&usqp=CAU",
],
};
},
methods: {
getImgUrl(value) {
this.thumbs = value;
return `${value}`;
},
},
};
</script>

Vue-MultiSelect: Using two multiselects at once and how to hide options based on what is shown in other

I am using a plugin called Vue-MultiSelect and showing it twice in my component. The first multiselect has a label of "Add New Contacts" and the second multiselect has a label of "Current Listed Contacts".
How can I hide the users for the "Add New Contacts" multiselect dropdown if they are already listed in the "Current Listed Contacts"?
Screenshot of problem:
I am using props to show the users for the "Current Listed contacts" multiselect. Here's the code for my Single file component where these multiselects reside (also demo link: CodeSandBox Code Editor) Note: click on POSTS --> EDIT (Acme Widget) to see the page where I am talking about
<template>
<div>
<label>Add New Contacts:</label>
<multiselect
id="add_new_contacts_input"
v-model="NewContacts"
:options="options"
label="lastname"
placeholder="Select or search for an existing contact"
track-by="uid"
:loading="isLoading"
:custom-label="selectedNameLabel"
aria-describedby="searchHelpBlock"
selectLabel
:multiple="true"
>
<template
slot="singleLabel"
slot-scope="props"
>{{ props.option.lastname }}, {{props.option.firstname}}</template>
<template slot="option" slot-scope="props">
<strong>{{ props.option.lastname }}</strong>
, {{ props.option.firstname }} —
<small>{{ props.option.email }}</small>
</template>
</multiselect>
<!-- <small id="searchHelpBlock" class="form-text text-muted"><font-awesome-icon icon="exclamation-circle" /> If customer does not exist, you will be prompted to add a new customer</small> -->
<!-- <h3>New contacts to be added:</h3>
<ul>
<li v-for="value in values" :key="value.uid">{{value.lastname}}, {{value.firstname}}</li>
</ul>-->
<label>Current Listed Contacts</label>
<multiselect
id="current_listed_contacts_input"
v-model="CurrentListedValues"
placeholder="There are no current contacts"
label="lastname"
track-by="uid"
:options="options"
:multiple="true"
:custom-label="selectedNameLabel"
:loading="isLoading"
selectLabel
>
<!-- formatting for the drop down list -->
<template slot="option" slot-scope="props">
<strong>{{ props.option.lastname }}</strong>
, {{ props.option.firstname }} —
<small>{{ props.option.email }}</small>
</template>
</multiselect>
</div>
</template>
<script>
import Multiselect from "vue-multiselect";
// import ApiService from "#/apiService";
export default {
components: { Multiselect },
props: ["users", "contacts"],
data() {
return {
NewContacts: [],
CurrentListedValues: this.contacts,
options: this.users,
isLoading: true
};
},
created() {
this.isLoading = false;
},
methods: {
selectedNameLabel(option) {
return `${option.lastname}, ${option.firstname} -- ${option.email}`;
}
}
};
</script>
you can use computed to filter your list:
computed: {
addOptions() {
let opt = this.users;
this.CurrentListedValues.forEach(c => {
opt = opt.filter(i => i.uid !== c.uid);
});
return opt;
}
}
and in your select list change options to addOptions: :options="addOptions"

Vue Component interact with page where its in

I'm using 2 components in my page, one for a comment and inside the comment component is the comment reply component, I did it this way to add some functionality that I needed but now I don't know how to get the buttons in the components to do the stuff they did before I turned them into components. For example the edit function opens a dialog that is in the page where the comment component is located but now it doesn't do anything, same with the reply functionality.
How can I get this to work, or is there a way to keep those methods in the main page and not have to put them in the components? I've never made my own component before so I'm not sure how to do this.
This is the Comment component code, the editComment and openReply are methods from the main page
<template>
<div class="comment">
<el-card shadow="never" v-if="comment.parent_id === null">
<el-row v-if="comment.deleted === 0">
<el-row style="margin-bottom: 15px">
<el-col :span="20" v-if="forum.anonymous === 0">
<p class="comment-user-name">{{comment.user.name}} dice: </p>
</el-col>
<el-col :span="20" v-if="forum.anonymous === 1">
<p class="comment-user-name">Anónimo dice: </p>
</el-col>
<el-col :span="4">
<div style="text-align: end"
v-if="comment.user_id === $page.auth.user.auth.user.id">
<div v-if="canEdit" class="btn-link-edit action-button"
#click="editComment(comment)">
<i class="fas fa-pencil-alt"></i>
</div>
<div class="btn-link-delete action-button"
#click="remove(comment.id)">
<i class="fas fa-trash"></i>
</div>
<div class="btn-link-preview action-button"
#click="openReply(comment)">
<i class="fas fa-reply"></i>
</div>
</div>
<div style="text-align: end"
v-if="comment.user_id !== $page.auth.user.auth.user.id">
<div class="btn-link-preview action-button"
#click="openReply(comment)">
<i class="fas fa-reply"></i>
</div>
</div>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<p class="comment-comment">{{comment.comment}}</p>
</el-row>
<el-row class="fa-pull-right pb-1">
<p class="comment-user-time ">{{formatDate(comment.comment_time)}}</p>
</el-row>
</el-row>
<el-row v-if="comment.deleted === 1">
<el-row style="margin-top: 15px">
<p class="comment-comment">{{comment.comment}}</p>
</el-row>
<el-row class="fa-pull-right pb-1">
<p class="comment-user-time ">{{formatDate(comment.comment_time)}}</p>
</el-row>
</el-row>
<el-row style="margin-left: 30px">
<div v-for="reply in comment.replies">
<ReplyComponent :reply="reply" :forum="forum"/>
</div>
</el-row>
</el-card>
</div>
</template>
<script>
import moment from "moment";
import ReplyComponent from "./ReplyComponent";
export default {
name: "Comment",
props: {
comment: Object,
forum: Object,
},
components: {
ReplyComponent
},
data() {
return {
canEdit: Boolean,
interval: null,
mode: '',
form: {
comment: '',
},
};
},
methods: {
openReply(row) {
this.dialogReplyVisible = true;
this.parent = row;
},
editComment(item) {
this.mode = 'Editar';
this.form = _.cloneDeep(item);
this.dialogFormVisible = true;
},
checkTime() {
var minutes = moment().diff(moment(this.comment.comment_time), 'minutes');
if (minutes >= 30) {
this.canEdit = false;
// here you could also already clear the interval, since it won't change
} else if (minutes <= 29) {
this.canEdit = true;
}
}
},
created() {
this.checkTime();
this.interval = setInterval(() => {
this.checkTime();
}, 10000);
},
beforeDestroy() {
clearInterval(this.interval);
}
};
</script>
If I understood your questions correctly, you want to communicate (pass data) from Child components to parent component (page).
The way we can achieve this is by $emitting events from Child components and have the parent component respond to these events.
So, in your editComment and openReply methods you would fire events like this:
openReply(row) {
this.$emit('openReply', {any payload that you would want pass to parent});
},
editComment(item) {
this.$emit('editComment', {any payload that you would want pass to parent}
},
And, in your parent component / page you would subscribe and handle those events. Pseudo-code below:
<Comment v-on:openReply="handleOpenReply"
v-on:editCommnet="handleEditComment"/>
Further Reading:
Passing Data to Child Components With Props
Listening to Child Components Events