Vue js get parent property AFTER it's ready method has ran - vue.js

I know I can use inherit to allow a child component to grab it's parent's properties, BUT the thing is.. is that I need to grab the property AFTER the parent ready method has ran. I'm having this issue everywhere in order to get width and height of parent components that are set in the ready method.
var Carousel = Vue.component('carousel', {
template: '#carousel',
replace: true,
data: function() {
return {
current: 1,
slideWidth: 600,
count: 6,
style: {
width: 600,
viewport: 600,
marginLeft: 0
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px',
marginLeft: this.style.marginLeft + 'px'
}
},
viewport: function() {
return {
width: this.style.viewport + 'px'
}
},
rounds: Math.floor(this.count / this.show)
},
props: ['show', 'slideMargin'],
ready: function() {
this.slideWidth = $(this.$el).width();
this.count = this.$children.length;
this.style.width = (this.slideWidth * this.count) + (this.slideMargin * (this.count * 2));
this.style.viewport = (this.slideWidth * this.show) + (this.slideMargin * (this.show * 2));
}
});
var CarouselSlide = Vue.component('carouselslide', {
template: '#slide',
replace: true,
data: function() {
return {
style: {
width: 200
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
ready: function() {
this.style.width = this.$parent.$get('slideWidth');
}
});
new Vue({
el: '#testimonials'
});
#testimonials {
width: 50%;
margin: 0 auto;
position: relative;
float: left;
min-height: 1px;
padding-left: 1.25rem;
padding-right: 1.25rem;
display: block;
}
h3 {
color: #b50937;
text-transform: uppercase;
margin: 0 0 20px;
font-size: 1.75rem;
}
.carousel {
position: relative;
overflow: hidden;
}
.carousel .slides {
overflow: hidden;
margin: 0 auto;
}
.carousel .slides .viewport {
overflow: hidden;
-webkit-transform: translateZ(0);
transform: translateZ(0);
transition: all 800ms cubic-bezier(0.77, 0, 0.175, 1);
transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
}
.carousel .slides .slide {
position: relative;
display: block;
float: left;
margin: 0 2px;
}
.carousel .slides .slide .box {
background-color: #d1dbe5;
box-sizing: border-box;
padding: 15px 20px;
}
.view-all {
text-align: right;
}
.arrows {
position: relative;
text-align: right;
width: 100%;
}
.arrows .arrow {
background-color: #d3d3d3;
color: #fff;
padding: 2px 13px;
position: static;
transition: 0.4s ease-in-out;
display: inline-block;
cursor: pointer;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/0.12.13/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="x-template" id="carousel">
<div class="carousel">
<div class="slides" v-style="viewport">
<div class="viewport" v-style="styles">
<content></content>
</div>
</div>
<div class="view-all">View all <i class="fa fa-angle-double-right"></i></div>
<div class="arrows">
<div class="arrow prev" v-on="click: prevSlide"><i class="fa fa-chevron-left"></i></div>
<div class="arrow next" v-on="click: nextSlide"><i class="fa fa-chevron-right"></i></div>
</div>
</div>
</script>
<script type="x-template" id="slide">
<div class="slide" v-style="styles">
<content></content>
</div>
</script>
<section id="testimonials">
<h3>What People Are Saying About Us</h3>
<carousel show="1" slide-margin="2">
<carouselslide>
<div class="phrase">
<div class="box">
We were looking to upgrade our equipment when we came across Ventrac. It was "wow" for
us, why did we suffer for the first six years with these other pieces of equipment when we could of had this.
</div>
</div>
</carouselslide>
<carouselslide>
<div class="phrase">
<div class="box">
We were looking to upgrade our equipment when we came across Ventrac. It was "wow" for
us, why did we suffer for the first six years with these other pieces of equipment when we could of had this.
</div>
</div>
</carouselslide>
</carousel>
</section><!-- END #TESTIMONIALS -->
Here is my Vue code since it's the only part that's relevant, although you can see what I'm having issues with upstairs ^^ (the snippet)
var Carousel = Vue.component('carousel', {
template: '#carousel',
replace: true,
data: function() {
return {
current: 1,
slideWidth: 600,
count: 6,
style: {
width: 600,
viewport: 600,
marginLeft: 0
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px',
marginLeft: this.style.marginLeft + 'px'
}
},
viewport: function() {
return {
width: this.style.viewport + 'px'
}
},
rounds: Math.floor(this.count / this.show)
},
props: ['show', 'slideMargin'],
ready: function() {
this.slideWidth = $(this.$el).width();
this.count = this.$children.length;
this.style.width = (this.slideWidth * this.count) + (this.slideMargin * (this.count * 2));
this.style.viewport = (this.slideWidth * this.show) + (this.slideMargin * (this.show * 2));
}
});
var CarouselSlide = Vue.component('carouselslide', {
template: '#slide',
replace: true,
data: function() {
return {
style: {
width: 200
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
ready: function() {
this.style.width = this.$parent.$get('slideWidth');
}
});
new Vue({
el: '#testimonials'
});
The reason I need to get it from the parent is because the clientWidth includes padding which I can't. So I can't do $(this.$el).width() in the data or computed properties data since $el is not available yet. From my child, I need to get this width AFTER the ready method has fired.
Thanks for any insight.

Without looking too closely at your code, my first thought to get parent data in the child is:
computed: {
val: this.$parent.val;
}
But I'm not certain that will work for you. Alternatively you might be able to change your parent's ready method to compiled so it runs before the child.

Related

Using wheelnav.js on Vue 3 project

So I have seen this pie menu generator which gives you an HTML, CSS and JS code and I wanted to use it in my Vue 3 project. I am new to vue and this was how I imported it.
here is the link to the pie menu generator: http://pmg.softwaretailoring.net/
I did this in my wrapper component. Somehow this bought many errors in which I think is because of how I imported the JS library.
<template>
<div class="context-menu" v-show="show" :style="style" ref="context" tabindex="0" #blur="close">
<div id='piemenu' data-wheelnav data-wheelnav-slicepath='DonutSlice' data-wheelnav-marker
data-wheelnav-markerpath='PieLineMarker' data-wheelnav-rotateoff data-wheelnav-navangle='270'
data-wheelnav-cssmode data-wheelnav-init>
<div data-wheelnav-navitemtext='0' onmouseup='alert("Place your logic here.");'></div>
<div data-wheelnav-navitemtext='1' onmouseup='alert("Place your logic here.");'></div>
</div>
</div>
</template>
<script>
import '../assets/raphael.min.js'
import '../assets/raphael.icons.min.js'
import '../assets/wheelnav.min.js'
var piemenu = new wheelnav('piemenu');
piemenu.wheelRadius = piemenu.wheelRadius * 0.83;
piemenu.createWheel();
export default {
name: 'CmpContextMenu',
props: {
display: Boolean, // prop detect if we should show context menu
},
data() {
return {
left: 0, // left position
top: 0, // top position
show: false, // affect display of context menu
};
},
computed: {
// get position of context menu
style() {
return {
top: this.top + 'px',
left: this.left + 'px',
};
},
},
methods: {
// closes context menu
close() {
this.show = false;
this.left = 0;
this.top = 0;
this.myTrigger = false;
console.log('trigger false');
},
open(evt) {
this.show = true;
// updates position of context menu
this.left = evt.pageX || evt.clientX;
this.top = evt.pageY || evt.clientY;
},
},
};
</script>
<style>
.context-menu {
position: fixed;
z-index: 999;
cursor: pointer;
}
#piemenu>svg {
width: 100%;
height: 100%;
}
#piemenu {
height: 400px;
width: 400px;
margin: auto;
}
#media (max-width: 400px) {
#piemenu {
height: 300px;
width: 300px;
}
}
[class|=wheelnav-piemenu-slice-basic] {
fill: #497F4C;
stroke: none;
}
[class|=wheelnav-piemenu-slice-selected] {
fill: #497F4C;
stroke: none;
}
[class|=wheelnav-piemenu-slice-hover] {
fill: #497F4C;
stroke: none;
fill-opacity: 0.77;
cursor: pointer;
}
[class|=wheelnav-piemenu-title-basic] {
fill: #333;
stroke: none;
}
[class|=wheelnav-piemenu-title-selected] {
fill: #fff;
stroke: none;
}
[class|=wheelnav-piemenu-title-hover] {
fill: #222;
stroke: none;
cursor: pointer;
}
[class|=wheelnav-piemenu-title]>tspan {
font-family: Impact, Charcoal, sans-serif;
font-size: 24px;
}
.wheelnav-piemenu-marker {
stroke: #444;
stroke-width: 2;
}
</style>

Vue-multiselect - How to insert html code in placeholder?

Im trying insert span in placeholder, for color change. But placeholder returns only string, ow to fix that?
computed: {
customPlaceholder () {
let numLength = this.options.length;
return this.placeholder + "<span>"+numLength+"</span>"
}
}
I think you're trying to add a custom placeholder inside an input field.
to do this you need some mix of css and html.
new Vue({
el: '#editor',
data: {
input: '',
input2: 'some text'
},
computed: {
placeholderText: function () {
return `${this.input2} <span>*</span>`
}
},
methods: {
update: _.debounce(function (e) {
this.input = e.target.value
}, 300)
}
})
#editor div {
display: inline-block;
}
.input-placeholder {
position: relative;
}
.input-placeholder input {
padding: 10px;
font-size: 25px;
}
.input-placeholder input:valid + .placeholder {
display: none;
}
.placeholder {
position: absolute;
pointer-events: none;
top: 0;
bottom: 0;
height: 25px;
font-size: 25px;
left: 10px;
margin: auto;
color: #ccc;
}
.placeholder span {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/lodash#4.16.0"></script>
<div id="editor">
<div class="input-placeholder">
<input type="text" #input="update">
<div class="placeholder" v-if="!input" v-html="placeholderText">
Email <span>*</span>
</div>
</div>
</div>
I have created this jsfiddle for my solution.
you can use css placeholder selector
input::-webkit-input-placeholder { /* Edge */
color: green!important;
}
input:-ms-input-placeholder { /* Internet Explorer 10-11 */
color: green!important;
}
input::placeholder {
color: green!important;
}
Try it, then try to remove the !important.
But information is missing. You want to change the color dynamically or not? or you want to have different colours into the same placeholder?

How can I modify a value in a array with a click method ? [VueJS]

I just started vuejs today. I got vue "example1" which contain as data, a variable "items". This variable contains an array "deck". This array contains multiple character stats (team, weapon, position...).
I don't know how to figure this out, if you have any solution or any direction where I can find my anwser.
I want on click on the character, to modify the gridColumn position, which is binded by "x". They are displayed on a 9*12 grid.
Thanks a lot.
html, body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#board {
display: grid;
grid-template-columns: repeat(12, 80px);
grid-template-rows: repeat(9, 80px);
grid-gap: 10px;
}
#board .card {
background-color: pink;
border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<section id="board">
<div class="card" v-for="item in items" v-bind:style="{backgroundColor:item.bg,gridColumn:item.x,gridRow:item.y}" v-on:click="move">
{{ item.clan }}
<br>
{{ item.arme }}
<br>
{{ item.force }}
</div>
</section>
<script>
var deck = [
//natif
{
clan: 'natif',
arme:'filet',
force: 1,
bg: 'green',
x: 2,
y: 6
},
{
clan: 'natif',
arme:'filet',
force: 2,
bg: 'green',
x: 3,
y: 6
}
//etc
];
var example1 = new Vue({
el: '#board',
data: {
items: deck
},
methods: {
move: function () {
// increase "x" value of the clicked item.
}
}
});
</script>
You can pass the index of the item clicked and modify it inside the function by referencing the index.
html, body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
#board {
display: grid;
grid-template-columns: repeat(12, 80px);
grid-template-rows: repeat(9, 80px);
grid-gap: 10px;
}
#board .card {
background-color: pink;
border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<section id="board">
<div class="card" v-for="(item,index) in items" v-bind:style="{backgroundColor:item.bg,gridColumn:item.x,gridRow:item.y}" v-on:click="move(index)">
{{ item.clan }}
<br>
{{ item.arme }}
<br>
{{ item.force }}
</div>
</section>
<script>
var deck = [
//natif
{
clan: 'natif',
arme:'filet',
force: 1,
bg: 'green',
x: 2,
y: 6
},
{
clan: 'natif',
arme:'filet',
force: 2,
bg: 'green',
x: 3,
y: 6
}
//etc
];
var example1 = new Vue({
el: '#board',
data: {
items: deck
},
methods: {
move: function (i) {
this.items = this.items.map((item,indx) => {
if(indx === i)
return ({...item,x: item.x + 1});
return item;
}) //modify logic accordingly
}
}
});
</script>
This is how you do it according to the OFFICIAL VUE.JS DOCUMENTATION
[Mutating the array with Vue.set method]:
var deck = [
//natif
{
clan: 'natif',
arme: 'filet',
force: 1,
bg: 'green',
x: 2,
y: 6
},
{
clan: 'natif',
arme: 'filet',
force: 2,
bg: 'green',
x: 3,
y: 6
}
//etc
];
var example1 = new Vue({
el: '#board',
data: {
items: deck
},
methods: {
move: function(index) {
/* creating a REFERENCE of the clicked item's object */
let modifiedObject = this.items[index];
/* increaseing "x" value of temporary REFERENCE */
modifiedObject.x++;
/* Mutating the items array WITHOUT LOSING REACTIVITY by replacing the existing object with local modified object */
Vue.set(this.items, index, modifiedObject);
}
}
});
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#board {
border: 1px solid black;
display: grid;
grid-template-columns: repeat(12, 40px);
grid-template-rows: repeat(9, 40px);
grid-gap: 10px;
}
#board .card {
background-color: pink;
border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<section id="board">
<div class="card" v-for="(item,index) in items" v-bind:style="{backgroundColor:item.bg,gridColumn:item.x,gridRow:item.y}" v-on:click="move(index)">
{{ item.clan }}
<br> {{ item.arme }}
<br> {{ item.force }}
</div>
</section>

Fix animated images on slide

I'm trying to make an animation when changing a slide. The old slide disappears with the animation, and the new one shows up with the animation. My animation is alternating. Help. Thank you all !!
var app = new Vue({
el: '#app',
data() {
return {
selectedIndex: 0,
message: "Test work vue",
isOpenSlide: true,
startVal: 0,
decimals: 0,
duration: 2.5,
options: {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '.',
prefix: '',
suffix: ''
},
items: [
{
title: 'Center of osteopatia and rehabilitation',
url_img: 'https://i.imgur.com/gQp3VSW.jpg',
info_block: [
{
incremental: '800',
description: 'Increasing the number of transactions from organic search results'
},
{
incremental: '240',
description: 'Raising your revenue'
}
]
},
{
title: 'SLide 2',
url_img: 'https://newevolutiondesigns.com/images/freebies/space-wallpaper-5.jpg',
info_block: [
{
incremental: '140',
description: 'Increasing the numb organic search results'
},
{
incremental: '790',
description: 'Raising your revenue'
}
]
},
{
title: ' SLIDE 3',
url_img: 'https://www.planwallpaper.com/static/images/4433836-space-wallpapers.jpg',
info_block: [
{
incremental: '110',
description: 'Increasing the number of trans'
},
{
incremental: '99',
description: 'Raising your revenue'
}
]
}
]
}
},
methods: {
select(index) {
this.selectedIndex = index
},
index_dotnav: function (index) {
this.selectedIndex = index
},
open() {
this.isOpenSlide = true;
},
close() {
this.isOpenSlide = false;
},
toggle() {
if (this.isOpenSlide) {
this.close();
} else {
this.open();
}
},
ChangeSlider() {
setTimeout(() => {
if (++this.selectedIndex === this.items.length) {
this.selectedIndex = 0;
}
this.toggle();
this.ChangeSlider()
}, 5000)
},
callback(instance) {
instance.start();
}
},
mounted() {
this.ChangeSlider();
}
})
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
ul {
padding-left: 0;
margin: 0;
}
.img-block,
section > *,
.uk-slideshow,
.uk-slideshow > ul {
height: 100vh !important;
}
.information-slide .uk-container {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto 0;
display: flex;
flex-direction: column;
justify-content: center;
color: #fff;
}
.slideshow > div.dotnav-block {
top: 50%;
left: 95%;
z-index: 2;
}
.slideshow > div.dotnav-block li a {
background: #fff;
}
.slideshow > div.dotnav-block li.active a {
width: 13px;
height: 13px;
}
.slideshow > div.dotnav-block ul {
align-items: center;
}
.slideshow .slideshow-items > li {
display: none;
}
.slideshow .slideshow-items > li.active {
display: block;
position: relative;
}
.slideshow .slideshow-items > li img {
height: 100%;
width: auto;
object-fit: cover;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-rc.14/css/uikit.min.css"/>
<body>
<div id="app">
<section>
<div class="uk-child-width-1-2" uk-grid>
<div>
<h1>{{ message }}</h1>
</div>
<div>
<div id="slideshow">
<div class="slideshow">
<ul class="slideshow-items">
<li v-for="(item,index) in items" :class="{'active':index===selectedIndex}"
v-on:click="select(index)">
<div class="information-slide">
<transition name="slide">
<div class="img-block" v-show="isOpenSlide">
<img v-bind:src="item.url_img" alt="">
</div>
</transition>
<div class="uk-container">
<div class="title title-1">{{item.title}}</div>
<div class="info-block">
<div class="info" v-for="(iblock,ind) in item.info_block">
<div class="incremental">
<span>+</span>
<!--<app-count-up-->
<!--:startVal="startVal"-->
<!--:endVal="iblock.incremental"-->
<!--:decimals="decimals"-->
<!--:duration="duration"-->
<!--:options="options"-->
<!--:callback="onReady"></app-count-up>-->
<span>%</span>
</div>
<div class="description descr-1">{{iblock.description}}</div>
</div>
</div>
</div>
</div>
</li>
</ul>
<div class="dotnav-block uk-position-bottom-center uk-position-small">
<ul class="uk-dotnav uk-dotnav-vertical">
<li :class="{'active':index===selectedIndex}" v-for="(item,index) in items"
v-on:click="index_dotnav(index)">
Item {{index}}</li>
</ul>
</div>
</div>
</div>
</template>
</div>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-rc.14/js/uikit.min.js"></script>

How to add preloader and success message on form submit using vue-resource

How to accomplish below task using vue-resource:
Include preloader text Loading... or gif image when fetching the data
from the server.
Show success message on form submit.
One way of doing this is :
<template>
<div>
<div class="loader" v-if="loader"></div>
<div>
//display fetchedData using logic you wish like v-for.....
</div>
<form>
//your form inputs
<button #click.prevent="submit">Submit</button>
</form>
</div>
</template>
<script>
export default{
data(){
return{
loader: false,
fetchedData: null
}
},
mounted(){
this.loader = true;
this.$httpget('your_url')
.then(response => {
this.fetchedData = response;
this.loader = false;
},err => {
});
},
methods:{
submit(){
this.loader = true;
this.$http.post('your_url', {your_body})
.then(response => {
this.loader = false;
},err => {
alert('form not submitted');
});
}
},
}
</script>
<style scoped>
loader {
position: absolute;
left:50%;
top:50%;
transform: translate(-50%, -50%);
border: 10px solid #f3f3f3; /* Light grey */
border-top: 16px solid #3498db; /* Blue */
border-radius: 50%;
width: 75px;
height: 75px;
animation: spin 2s linear infinite;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
Here is the working fiddle
This was questioned by me, with the help that I got from #Vamsi, here is my solution:
Component
<loading-indicator v-if="loadingGroup" :bgAlpha="'.6'"></loading-indicator>
<script>
import LoadingIndicator from '../partials/LoadingIndicator'
export default {
data () {
return {
loadingGroup: true,
}
},
components: {LoadingIndicator},
methods: {
fetchGroup() {
let _this = this;
this.loadingGroup = true;
api._get({url: 'api/group/' + _this.$route.params.id})
.then(function (response) {
_this.groupData = response.data;
_this.loadingGroup = false;
});
}
},
mounted() {
this.fetchGroup();
}
}
</script>
My Template that's in: ../partials/LoadingIndicator.vue
<template>
<div class="pin pin-xy d-flex"
:style="{ backgroundColor: 'rgba(255, 255 ,255,' + bgAlpha + ')'}">
<div class="loading-indicator">
<div class="loading-indicator-circle"></div>
</div>
</div>
</template>
<script>
export default {
props: {
bgAlpha: String
}
}
</script>
<style lang="scss">
.pin {
position: absolute;
&-xy {
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
.d-flex {
display: flex;
}
.loading-indicator {
width: 32px;
height: 32px;
margin: auto;
overflow: hidden;
animation: animation-fadeIn 1s ease-in;
}
.loading-indicator-circle {
animation: loading-indicator-rotation 0.67s linear infinite;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAzMiAzMic+PGxpbmVhckdyYWRpZW50IGlkPSdGYXN0TG9hZGluZ0luZGljYXRvci1saW5lYXJHcmFkaWVudCcgZ3JhZGllbnRVbml0cz0ndXNlclNwYWNlT25Vc2UnIHgxPScxLjc4MDQnIHkxPScxNi4wMzc5JyB4Mj0nMzAuMTQzOScgeTI9JzE2LjAzNzknPjxzdG9wIG9mZnNldD0nMC40MTY5JyBzdG9wLWNvbG9yPScjQ0RDRkQyJy8+PHN0b3Agb2Zmc2V0PScwLjkzNzYnIHN0b3AtY29sb3I9J3JnYmEoMjQ4LDI0OCwyNDksMCknLz48L2xpbmVhckdyYWRpZW50PjxjaXJjbGUgY3g9JzE2JyBjeT0nMTYnIHI9JzEyLjcnIHN0eWxlPSdmaWxsOiBub25lOyBzdHJva2U6IHVybCgjRmFzdExvYWRpbmdJbmRpY2F0b3ItbGluZWFyR3JhZGllbnQpOyBzdHJva2Utd2lkdGg6IDI7Jz48L2NpcmNsZT48L3N2Zz4=");
height: 100%;
width: 100%
}
#keyframes loading-indicator-rotation {
from {
transform: rotate(0deg)
}
to {
transform: rotate(360deg)
}
}
</style>