Vue-multiselect - How to insert html code in placeholder? - vue.js

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?

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 3 Composition API component doesn't work reactivate class

I have a button and I just want it animate on a click - make as it been pressed. It works if I make optional component as below:
<template>
<button class="button" :class="{'shadow__click': classButton}" #click="buttonClass">
Tell me already!
</button>
</template>
<script>
export default {
data(){
return {
classButton : false
}
},
methods: {
buttonClass(){
this.classButton = true;
setTimeout(() => {
this.classButton = false
}, 1000)
}
}
}
</script>
<style lang="less">
.button{
cursor: pointer;
padding: 12px 24px;
position: relative;
border-radius: 5px;
background-color: #38b2ac;
border: none;
color: #fff8e1;
}
.shadow__click{
animation: click 1s
}
#keyframes click {
0% {
top: 0;
left: 0;
}
25% {
top: 5px;
left: 1px;
}
50% {
top: 10px;
left: 3px;
}
75% {
top: 5px;
left: 1px;
}
100% {
top: 0;
left: 0;
}
}
</style>
but it doesn't want to work when I do Composition way and I don't see a problem but it simply doesn't work (( I console.loged function and it goes to function changes the value of a variable, but class is not applying. Is it a Vue 3 bug?
<script>
import { ref } from "vue"
setup(){
let classButton = ref(false);
function buttonClass(){
classButton = true;
setTimeout(() => {
classButton = false
}, 1000)
}
return { classButton, buttonClass}
}
</script>
You should mutate the ref using the value field :
let classButton = ref(false);
function buttonClass(){
classButton.value = true;
setTimeout(() => {
classButton.value = false
}, 1000)
}

How to get images to automatically reload in a vue component

I'm pretty new to Vue, I have an app running with a few different pages. One of the pages I'm trying to have is one that displays all images that are found in a directory on my host and to have them auto reload whenever the image changes (a separate app updates these images every 10 seconds). I've been able to display all the images (although only by listing them) and I can't seem to figure out how to get the pictures to auto refresh. Below is the code, any help is much appreciated.
<template>
<div id="app" class="media-display">
<figure class="media-post" v-for="(image, index) in images" v-bind:key="image.id" >
<img :key="index" :src="getImage(index)" v-bind:alt="image" width="580" height="390" v-bind:key="index" />
</figure>
</div>
</template>
<script>
import moment from 'moment'
export default {
el: '#app',
data(){
return {
images: [
'/charts/chart1.png?rnd='+Math.random(),
'/charts/chart2.png?rnd='+Math.random(),
'/charts/chart3.png?rnd='+Math.random(),
],
id : 1,
}
},
methods: {
getImage(index) {
return this.images[index]
}
}
}
</script>
<style>
.media-post {
display: inline-block;
padding: 1vmin;
//border-radius: 2vmin;
box-shadow: 0 10px 5px rgba(0, 0, 0, 0.2);
margin: 0;
background: #FFF;
position: relative;
cursor: pointer;
}
.media-post img {
//border-radius: 1vmin;
display: block;
max-width: 100%;
height: auto;
}
.media-post figcaption {
color: #FFF;
position: absolute;
top: 0;
left: 0;
font-weight: bold;
padding: 1rem 1.5rem;
z-index: 2;
font-size: 2rem;
text-shadow: 0 1px 2px #000;
}
</style>
You just need to regenerate the random number suffix periodically. Untested:
<img
v-for="url of images"
:key="url"
:src="url + '?rnd=' + cacheKey"
/>
data() {
return {
images: [
'/charts/chart1.png',
'/charts/chart2.png',
'/charts/chart3.png',
],
cacheKey: +new Date(),
};
},
created() {
this.interval = setInterval(() => {
this.cacheKey = +new Date();
}, 60 * 1000);
},
destroyed() {
clearInterval(this.interval);
},
If it isn't clear, +new Date() returns the number of seconds since 1 January 1970 00:00:00 UTC (docs).

How to do databind two way in v-html?

I have an element div with atribute contenteditable="true". This div behaves like an element textarea.
<div v-on:keyup.enter="SendMensage" v-html="msg" contenteditable="true"></div>
my code:
data() {
return {
msg: '',
}
},
methods: {
enviaMensagem() {
console.log(this.msg);
}
}
My problem is that the databind does not work. What is typed in the div does not reflect on the variable. Does anyone know what can it be?
You need to listen to changes of the element, because v-model only works on <textarea> or <input>. You can do this by using an #input listener.
The markup you get like this will be escaped. If you want to unescape it, you can use e.g. this approach. Then, you actually have the markup right next to the pseudo-textarea field. So, why not using a <textarea> from begin with?
new Vue({
el: '#editor',
data: {
msg: ''
},
methods: {
typing: function(el) {
this.msg = el.target.innerHTML;
},
submit: function() {
console.log("Submitting: ", this.msg);
}
}
});
.input {
display: inline-block;
vertical-align: middle;
border: 1px solid black;
width: 200px;
height: 100px;
}
.output {
display: inline-block;
vertical-align: middle;
width: 200px;
height: 100px;
background: #eee;
}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="editor">
<div class="input" #input="typing" #keyup.enter="submit" contenteditable="true"></div>
<div class="output" v-html="msg"></div>
</div>

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

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.