call a component from another component in vue.js - javascript

I have an alert component like in this video: https://laracasts.com/series/learning-vue-step-by-step/episodes/21 And I have another component (Book). When a book was created how can I call Alert component in the success callback function like this:
<alert>A book was created successfully !!!</alert>
I am a newbie in using vue.js. Thank you for your help.
Updated: This is my code
submit: function () {
this.$http.post('/api/books/add', {
data: this.data,
}).then(function (response) {
// I want to use Alert component right here to notice to users.
}, function (response) {
});
}
Update 2:
Alert Component
<template>
<div class="Alert Alert--{{ type | capitalize }}"
v-show="show"
transition="fade"
>
<slot></slot>
<span class="Alert__close"
v-show="important"
#click="show = false"
>
x
</span>
</div>
</template>
<script>
export default {
props: {
type: { default: 'info' },
timeout: { default: 3000 },
important: {
type: Boolean,
default: false
}
},
data() {
return {show: true};
},
ready() {
if (!this.important)
{
setTimeout(
() => this.show = false,
this.timeout
)
}
}
}
</script>
<style>
.Alert {
padding: 10px;
position: relative;
}
.Alert__close {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
}
.Alert--Info {
background: #e3e3e3;
}
.fade-transition {
transition: opacity 1s ease;
}
.fade-leave {
opacity: 0;
}
</style>
And in Book.vue I want to do like this:
// resources/assets/js/components/Book.vue
<template>
.....
<alert>A book was created successfully !!!</alert>
//Create book form
....
</template>
<script>
export default {
methods: {
submit: function () {
this.$http.post('/api/books/add', {
data: this.data,
}).then(function (response) {
this.$refs.alert
}, function (response) {
});
}
</script>

this JSfiddle does what you're looking for: https://jsfiddle.net/mikeemisme/s0f5xjxu/
I used a button press rather than a server response to trigger the alert, and changed a few method names, but principle is the same.
The alert component is nested inside the button component. Button passes a showalert prop to the alert component with the sync modifier set.
<alert :showalert.sync="showalert" type="default" :important="true">A book was saved successfully</alert>
Press the button, showalert is set to 'true', 'true' passed to alert as prop, alert displays as v-show condition is now true,
data() {
//by default we're not showing alert.
//will pass to alert as a prop when button pressed
//or when response from server in your case
return {
showalert: false
};
},
a watch on the showalert prop in alert component sees a change and triggers a method that sets showalert back to 'false' after whatever many seconds set in timeout property.
//this method is triggered by 'watch', below
//when 'showalert' value changes it sets the timeout
methods: {
triggerTimeout: function() {
//don't run when detect change to false
if (this.showalert === true) {
setTimeout(
() => this.showalert = false,
this.timeout
)
}
},
},
watch: {
// detect showalert being set to true and run method
'showalert': 'triggerTimeout',
}
Because this prop is synched back to parent, button state updated too.
It works but using watch etc. feels overblown. Vue may have a better way to handle this. I'm new to Vue so somebody with more knowledge might chime in.

Add a data property
alertShow: false
Next, in the callback:
this.alertshow = true;
When you want to remove it, set it to false.
In the component add a directive:
v-show="alertshow"
Update:
Add a components attribute to block component.
components: {Alert},
Next outside of the component, import the Alert component file:
import Alert from './directory/Alert.vue'
The above is if you are using vueify. Otherwise, add a component using
Vue.component
Check out the docs.
Update 2:
Your code, with the changes:
<script>
import Alert from './directory/alert.vue';
export default {
components: {
Alert
},
methods: {
submit: function () {
this.$http.post('/api/books/add', {
data: this.data,
}).then(function (response) {
this.$refs.alert
}, function (response) {
});
}

Related

Update math equation using MathLive and Vue

I have been struggling to use Vue and MathLive to handle typesetting randomly generated numbers and their squares. The function of the program is to generate a random integer from 1 to 35, calculate the square, and typeset it with MathLive. There are two buttons that add one to the integer or create another random one. I have no problem typesetting the initial value but when I create a different integer or add 1 the page, it never re-typesets. I am trying to implement this program as a component in Vue. Here is my MWE (component only):
<template lang="html">
<div class="problem">
<p id="math">$${{num}}^2 = {{square()}}$$</p>
<button #click="addOne">Add One</button>
<button #click="randomInt">Random Number</button>
</div>
</template>
<script>
import math from 'mathjs'
import MathLive from 'mathlive'
export default {
name: 'Problem',
data: function () {
return {
num: math.randomInt(1,35)
}
},
watch: {
num: function () {
console.log("Data changed");
// this.renderMath();
}
},
created: function () {
console.log("Hello This is created!");
this.renderMath();
},
beforeMount: function () {
console.log("This is beforeMount");
},
mounted: function () {
console.log("This is mounted!");
},
beforeUpdate: function () {
console.log("This is beforeUpdate");
this.renderMath();
},
methods: {
addOne: function() {
this.num++
},
randomInt: function () {
this.num = math.randomInt(1,35)
},
square: function () {
return this.num**2
},
renderMath: function (event) {
this.$nextTick(function(){
MathLive.renderMathInElement("math");
})
}
}
}
</script>
<style lang="css" scoped>
#import url("../../node_modules/mathlive/dist/mathlive.core.css");
#import url("../../node_modules/mathlive/dist/mathlive.css");
p {
color: white;
}
</style>
Edit: To clarify when I load the page up, the initial value is typeset correctly using MathLive as shown below:
Then after I click either the Add One or Random Number button, the program should generate a new value, calculate its square, and update that value on the screen as shown below:
It seems MathLive's DOM manipulation conflicts with Vue's virtual DOM, preventing Vue from patching the DOM with the updated text node.
A workaround is to apply a key to force the MathLive p element to be re-created when the key changes. We could use num as the key, since it changes with each button press:
<p :key="num">...</p>
The current watcher on num would need to be updated to call renderMath() to refresh the MathLive element:
watch: {
num() {
this.renderMath();
}
},
You should also consider making square() a computed property for more efficient rendering:
// script
computed: {
square() {
return this.num ** 2
}
}
// template
<p :key="num">$${{num}}^2 = {{square}}$$</p>
You need to use vue.js computed properties
new Vue({
name: 'Problem',
data: function () {
return {
num: math.randomInt(1,35)
}
},
watch: {
num: function () {
console.log("Data changed");
this.renderMath();
}
},
computed: {
square: function () {
return this.num**2;
}
},
created: function () {
console.log("Hello This is created!");
this.renderMath();
},
beforeMount: function () {
console.log("This is beforeMount");
},
mounted: function () {
console.log("This is mounted!");
},
beforeUpdate: function () {
console.log("This is beforeUpdate");
//this.renderMath();
},
methods: {
addOne: function() {
this.num++
},
randomInt: function () {
this.num = math.randomInt(1,35)
},
renderMath: function (event) {
this.$nextTick(function(){
MathLive.renderMathInElement("math");
})
}
}
}).$mount("#app")
<script src="https://unpkg.com/mathjs/dist/math.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mathlive#0.26.0/dist/mathlive.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<span>$${{num}}^2 = {{square}}$$</span>
<span id="math"></span>
<button #click="addOne">Add One</button>
<button #click="randomInt">Random Number</button>
</div>

Can I make it so a click event only executes if a certain variable is true?

I want to make it so that a user can only trigger an on click event and then execute a function only if a certain variable is true. For example:
<button #click='hello'>Trigger</button>
data: function() {
return {
isAuth: true
}
},
methods: {
hello(){
console.log('hello')
}
}
I just want to point out that I don't want to only hide the button. I want to make clicks on the button element not trigger unless isAuth: true.
I guess you can do the following way, if you really want:
<button #click='isAuth ? hello : {}'>Trigger</button>
but honestly, this, to me, is not the right way. and I think you should consider calling the function on button click and inside that function, you can use an if statement:
<button #click='hello'>Trigger</button>
data: function() {
return {
isAuth: true
}
},
methods: {
hello(){
if (!this.isAuth) return;
console.log('hello')
}
}
<button #click='hello'>Trigger</button>
data: function() {
return {
isAuth: true
}
},
methods: {
hello() {
if (this.isAuth) {
console.log('hello')
}
}
}

vuejs listening for event on component

I am unable to catch the flash event on my custom component that i am emitting from the console . Here is my component:
/* file flash.vue */
<template>
<span :class="type" class="alert flash-alert" v-show="show">
{{ body }}
</span>
</template>
<script>
export default {
props: ['type','message'],
data() {
return {
body: this.message,
show: false,
};
},
created() {
if(this.body)
{
this.showComp();
this.hide();
}
},
methods: {
showComp: function(){
this.show = true;
},
hide: function()
{
var vm = this;
setTimeout(function() {
vm.show = false;
},2000);
},
},
events: {
flash: function(newMessage) {
this.body = newMessage;
this.showComp();
},
}
}
on the chrome console i am firing the event with:
/* from console */
window.vueEventBus = new Vue();
window.vueEventBus.$emit('flash','my message');
the event is firing as i can see that on the vue devtools tab. But upon catching the event the component should become visible, which is not.
However, if i piggyback the listener on the global event bus inside the components created() method, it works.
created() {
window.vueMessageBus.$on('flash',newMessage => {
this.body = newMessage;
this.showComp();
});
}
What should i do if i want the event listener to be registered inside the events property of the component itself?
-Thanks, Yeasir
look this example
eventbus created in index.js
Vue.prototype.$vueEventBus = new Vue()
listener on (see components/eventBus/eventBus.vue)
created() {
this.$vueEventBus.$on('message-in', this.newMessage)
},
beforeDestroy() {
this.$vueEventBus.$off('message-in')
}
emit event (see components/eventBus/childEventBus.vue)
methods: {
newMessage(something) {
this.$vueEventBus.$emit('message-in', something)
}
}
app page https://3xyx386q65.codesandbox.io/eventBus

vuejs - remount after update background url

I have a vue component with the binding style:
<div id="profile-icon" :style="{'background': 'url('+profile.icon+')'}"></div>
<input name="name" v-model="profile.name" type="text" placeholder="Name">
The image will only display if I update the profile.icon under beforeMount function:
props: ['profileprops'],
data: function() {
return {
profile: {
address:'',
name:'Name',
description:'Short description',
address:'address',
user_id:'',
background:'/images/admin/bg.png',
icon:''
},
}
},
beforeMount: function() {
console.log('profileedit mounted.')
var self = this;
if(self.profileprops){
self.profile = self.profileprops;
};
if(!self.profile.icon){
self.profile.icon = '/images/admin/icon-144.png';
},
mounted: function() {
var self = this;
self.$eventHub.$on('ImageSelected', (imagelink) => {///<-- I have another vue component for selecting images to emit event and to catch it here.
self.profile.icon = imagelink;
$('#profilemodal').modal('hide');
});
},
watch: {
'profile': {
handler: function(newVal, oldVal) {
console.log("changed")
},
deep: true
},
}
I did a few tests:
if I select the image, I can see the console.log within the $on has given the correct data from profile.icon. However, the :style did not update the background image with the new profile.icon. And watch.profile did not react at all.
If I start to type on input with v-model bind with profile.name, everything update immediately, including the background image in :style.
I believe I must have miss something to sync the inside and outside of the $on. How can I resolve this?
I found the solution here.
So I just $forceUpdate() inside $on:
self.$eventHub.$on('ImageSelected', (imagelink) => {
self.profile.icon = imagelink;
self.$forceUpdate();//<-- this does the magic.
});
then the data will update and re-render.

Call method from another component VueJS version 1

I want to call the method from another component in let's say parent component... So, let's say I have notie.vue and there's my method named 'flash' and I want to call that after API request when I get success.
So let's say this is the case: after get API I want to call something like this with parameters ---> notie.success('notification type', 'notification message')
Here's the code:
Props are defined like this
props: {
type: {
default: 'info',
required: false
},
content: {
default: 'This is just demo text',
required: false
},
visible: {
type: Boolean,
default: false
}
}
Here's data
data: function () {
return {
show: true
}
}
Here's method
methods: {
flash: function () {
this.show = true;
}
}
Here's HTML code
<div class="notie" v-bind:class="[{active: show}, type]" v-on:click="close()">
<div class="notie__icon" :class="type"></div>
<div class="notie__content" v-text="content"></div>
</div>
Here for example i want to call my notie component
submit: function () {
this.$http.post('/api/books/add', {
data: this.data,
}).then(function (response) {
// I want to use notie component right here to notice to users.
}, function (response) {
});
}
So my question is how can I call flash() after API request on success or error?

Categories

Resources