How to display all icons from icons folder in vuejs - javascript

Created a small project with vuejs and want to display all my icons but for some reason it does not displays my icons, Can anyone tell me where I am making the mistakes.
I want to display all my icons from that icons list in the div element.
Any help will be much appreciated, thanks!
ValidatingProps.vue
<template>
<div>
<h1>How to use Validation in props</h1>
<h3>{{ status }}</h3>
<div class="icons" v-html="icons"></div>
</div>
</template>
<script>
import icons from "./icons";
console.log(icons);
export default {
name: "validatingProps",
props: {
status: {
type: String,
default: "Validating",
validator: (value) => {
console.log("Val", value);
return ["in-progress", "complete"].includes(value);
},
},
icons: {
type: String,
required: true,
validator: (value) => {
console.log("Value >>>> ", value);
Object.keys(icons).includes(value);
console.log("Icons props: ", Object.keys(icons).includes(value));
},
},
},
mounted() {
console.log("mounted ", Object.keys(icons));
console.log("this.Icons: ", this.icons);
},
};
</script>
<style scoped>
.icons {
height: 200px;
width: 200px;
border: 2px solid red;
margin: 0 auto;
background: lightcyan;
}
App.vue
<div>
<template>
<ValidatingProps
status="progress"
:icons="Object.keys(this.icons.default)"
/>
</div>
</template>
<script>
import ValidatingProps from "./components/validatingProps.vue";
import * as icon from "./components/icons/";
export default {
name: "App",
components: {
ValidatingProps,
},
data() {
return {
icons: icon,
}
}
</script>
my icons folder structure:
My Div box shows:

Related

Update elements background color in VueJs

In my app, I have 4 components:
App.vue
ProfileCardSlider
ProfileCard
ColorPicker
The idea is users would be able to update the background color of their ProfileCard using the element.
I can't work out how I can get the color value from the input and then emit that value up to the parent (App.vue in this case). In App.vue I believe I also need a color data property which this emitted value would then update and pass down as props to the ProfileCard.
These are my two components:
App.vue
import ProfileCardSlider from "./components/ProfileCardSlider.vue";
import ColorPicker from "./components/ColorPicker.vue";
export default {
components: {
ProfileCardSlider,
ColorPicker,
},
data() {
return {
color: "red",
};
},
methods: {
updateColor() {
this.color = color;
},
},
};
</script>
<template>
<ColorPicker :color="color" #select-color="updateColor" />
<ProfileCardSlider :color="color" />
</template>
ColorPicker.vue
<script>
export default {
props: ["color"],
methods: {
selectColor(color) {
this.$emit('update-color', color)
},
},
};
</script>
<template>
<div class="color__picker">
<h2 class="color__picker--title">Card background colour:</h2>
<input type="color" #change="selectColor" />
</div>
</template>
Using v-model and props in the correct way can help achieve this.
In your App.vue, use the color data property as hex (best practice to use in props), i.e #000000, and bind the color property to v-model to ColorPicker component.
Then in ColorPicker component, use the value prop which is the v-model binding from App.vue, and emit an input event on color input updating.
At last, listen to the color-changing event in App.vue to pass the updated color to ProfileCardSlider.vue.
So, the final code should be-
App.vue
<template>
<div>
<ColorPicker v-model="color" #input="updateColor" />
<ProfileCardSlider :color="color" />
</div>
</template>
<script>
import ProfileCardSlider from "./components/ProfileCardSlider.vue";
import ColorPicker from "./components/ColorPicker.vue";
export default {
name: "App",
data() {
return {
color: "#ffffff",
};
},
components: {
ProfileCardSlider,
ColorPicker,
},
methods: {
updateColor(color) {
this.color = color;
},
},
};
</script>
ColorPicker.vue
<template>
<div class="color__picker">
<h2 class="color__picker--title">Card background colour:</h2>
<input
type="color"
:value="value"
#input="$emit('input', $event.target.value)"
/>
</div>
</template>
<script>
export default {
name: "ColorPicker",
props: ["value"]
};
</script>
<style>
</style>
ProfileSlider.vue
(I take some dummy code for this component as you didn't mention in the question but the logic would be the same.)
<template>
<div class="card">
<div class="container" :style="{ background: color }">
<h4><b>John Doe</b></h4>
<p>Architect & Engineer</p>
</div>
</div>
</template>
<script>
export default {
name: "ProfileCardSlider",
props: {
color: {
required: true,
},
},
};
</script>
<style>
.card {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
width: 40%;
}
.container {
padding: 2px 16px;
}
</style>
You should see that when you will change the color from the color input which is inside ColorPicker.vue, the card inside ProfileSlider.vue will have an updated color.

How to pass a style property to a child component as a computed property in Vue.js?

I have the following problem:
I have too much logic in my inline style and would to place it inside a computed property. I know, that this is the way, that I should go, but do not know, how to achieve it.
Below I a simple example that I made for better understanding. In it, on button press, the child's component background-color is changing.
My code can be found here: Codesandbox
My parent component:
<template> <div id="app">
<MyChild :colorChange="active ? 'blue' : 'grey'" />
<p>Parent:</p>
<button #click="active = !active">Click Me!</button> </div> </template>
<script> import MyChild from "./components/MyChild";
export default { name: "App", components: {
MyChild, }, data() {
return {
active: false,
}; }, }; </script>
and my child component:
<template> <div class="hello">
<p>Hello from the child component</p>
<div class="myDiv" :style="{ background: colorChange }">
here is my color, that I change
</div> </div> </template>
<script> export default { name: "HelloWorld", props: {
colorChange: {
type: String,
default: "green",
}, }, }; </script>
<!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .myDiv { color: white; padding: 1rem 0; } </style>
I also have a second question. Let's say, that I have more than one child component and also would like to change to colors on button click, but those colors differ. How can I achieve it without repeating myself (within the computed properties?)
Code example for my parent component:
<MyChild :colorChange="active ? 'blue' : 'grey'" />
<MyChild :colorChange="active ? 'grey' : 'blue'" />
<MyChild :colorChange="active ? 'blue' : 'red'" />
<MyChild :colorChange="active ? 'yellow' : 'blue'" />
Thanks in advance!
Maybe You can bind class and use different css classes:
Vue.component('MyChild',{
template: `
<div class="hello">
<p>Hello from the child component</p>
<div class="myDiv" :class="collorCurrent">
here is my color, that I change
</div>
</div>
`,
props: {
colorChange: {
type: String,
default: "green",
},
colorDef: {
type: String,
default: "green",
},
isActive: {
type: Boolean,
default: false,
},
},
computed: {
collorCurrent() {
return this.isActive ? this.colorChange : this.colorDef
}
}
})
new Vue({
el: "#demo",
data() {
return {
active: false,
}
},
})
.myDiv { color: white; padding: 1rem; }
.blue {
background: blue;
font-size: 22px;
}
.red {
background: red;
font-variant: small-caps;
}
.yellow {
background: yellow;
color: black;
}
.grey {
background: grey;
text-decoration: underline;
}
.green {
background: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<p>Parent:</p>
<button #click="active = !active">Click Me!</button>
<my-child :is-active="active" :color-def="'grey'" :color-change="'blue'"></my-child>
<my-child :is-active="active" :color-def="'blue'" :color-change="'grey'"></my-child>
<my-child :is-active="active" :color-def="'red'" :color-change="'blue'"></my-child>
<my-child :is-active="active" :color-def="'blue'" :color-change="'yellow'"></my-child>
</div>

Set up a v-on:click directive inside v-for

I have displayed a list of images with some information. I want those images to be clickable. And when clicked it should show a div with saying "HI!!". I have been trying to add a variable as show:true in Vue data and tried to build some logic that show becomes false when clicked. But I have not been able to achieve it.
Below is the sample code:
template>
<div>
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div ><img :src="launch.links.patch.small" alt="No Image" title={{launch.name}} /></div>
<div>ROCKET NAME: {{launch.name}} </div>
<div>DATE: {{ launch.date_utc}} </div>
<div>SUCCESS: {{ launch.success}} </div>
<div>COMPLETENESS: {{ launch.landing_success}} </div>
</div>
<!-- <v-model :start="openModel" #close="closeModel" /> -->
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'SpaceXTimeline',
components: {
},
data: () => ({
launches : [],
openModel : false,
show : true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + " is launched");
console.log("DETAILS: "+ launch.details);
console.log("ROCKET INFO: "+ launch.links.wikipedia);
console.log("CREW DETAILS: "+ launch.crew);
console.log("Launchpad Name: "+ launch.launchpad);
this.openModel = true;
},
closeModel () {
this.openModel = false;
}
},
async created() {
const {data} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
}
};
</script>
<style scoped>
.list {
border: 1px solid black;
}
</style>
Thanks, and appreciate a lot.
v-model is a binding and not an element, unless you've named a component that? Is it a misspelling of "modal"?
Either way, sounds like you want a v-if:
<v-model v-if="openModel" #close="closeModel" />
Example:
new Vue({
el: '#app',
components: {},
data: () => ({
launches: [],
openModel: false,
show: true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + ' is launched');
console.log('DETAILS: ' + launch.details);
console.log('ROCKET INFO: ' + launch.links.wikipedia);
console.log('CREW DETAILS: ' + launch.crew);
console.log('Launchpad Name: ' + launch.launchpad);
this.openModel = true;
},
closeModel() {
this.openModel = false;
},
},
async created() {
const {
data
} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
},
})
Vue.config.productionTip = false;
Vue.config.devtools = false;
.modal {
cursor: pointer;
display: flex;
justify-content: center;
position: fixed;
top: 0;
width: 100%;
height: 100vh;
padding: 20px 0;
background: rgba(255, 255, 255, 0.5);
}
img {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<div id="app">
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div>
<img :src="launch.links.patch.small" alt="No Image" :title="launch.name" />
</div>
<div>ROCKET NAME: {{ launch.name }}</div>
<div>DATE: {{ launch.date_utc }}</div>
<div>SUCCESS: {{ launch.success }}</div>
<div>COMPLETENESS: {{ launch.landing_success }}</div>
</div>
<div v-if="openModel" #click="closeModel" class="modal">
MODAL
</div>
</div>

VUE: How to use prop with CSS modules?

row.vue
<script>
export default {
name: "Row",
data() {
return {
app: [
"row",
"row-test",
"flex-center"
]
}
},
template: `
<div :class="$module[app]"><slot></slot></div>
`
}
</script>
row.scss
.row {
color: red;
}
.row-test {
color: green;
}
.flex-center {
align-items: center;
justify-content: center;
}
App.vue
<template>
<div id="app">
<row app="row-test flex-center">my row</row>
<router-view />
</div>
</template>
vue.config.js
css: {
requireModuleExtension: true,
loaderOptions: {
css: {
modules: {
localIdentName: 'hex-[HASH:HEX:3]'
}
}
},
modules: true
}
I want to declare my attributes using the app attribute, where they will be written similarly to an ordinary class. Then I want there to be an Array in row.vue, which will add only the values that I define in and convert them to CSS using CSS modules (class is randomly generated)
I'm getting this
<div app="row-test flex-center">my row</div>
Expected result
<div class="hex-g3D hex-f41">my row</div>
If you're passing app as prop to Row component, define a computed property to return the modules with the different classes:
<script>
export default {
name: "Row",
props:['app'],
computed:{
modules(){
return this.app.length? this.app.map(_class=>{
return this.$module[_class];
}):[];
}
},
template: `
<div :class="modules"><slot></slot></div>
`
}
</script>
and pass it like :
<template>
<div id="app">
<row :app="['row-test', 'flex-center']">my row</row>
<router-view />
</div>
</template>

Access the $refs of a parent from a child - Vue.js

Hopefully this has been answered before - essentially I'm trying to append a block ("CodeBlock.vue") to an element inside App.vue from an onClick event triggered inside a sibling of CodeBlock, and a child of App.vue, ("ButtonSidebar.vue"). I'm a little confused by emitting events and/or using an eventBus Vue instance, so any pointers would be greatly appreciated:
So far I have the following. CodeBlock.vue which will be used as an instance and appended to a div inside App.vue.
CodeBlock.vue:
<template>
<div :class="type">
THIS IS A CODE BLOCK!!
</div>
</template>
<script>
export default {
name: 'CodeBlock',
props: [ 'type' ]
}
</script>
App.vue:
<template>
<div id="app" class="container">
<ButtonSidebar/>
<div id="pageBlocks" ref="container"></div>
</div>
</template>
<script>
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'
// import { eventBus } from './main'
import AddTitle from './components/modules/AddTitle'
import AddSubTitle from './components/modules/AddSubTitle'
import ButtonSidebar from './components/modules/ButtonSidebar'
import CodeBlock from './components/modules/CodeBlock'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
export default {
name: 'App',
components: {
AddTitle,
AddSubTitle,
ButtonSidebar,
CodeBlock
}
}
</script>
<style>
#app {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #1f1f1f;
margin-top: 60px;
}
.no-border {
border: unset !important;
border: 0px !important;
}
</style>
ButtonSidebar.vue:
<template>
<div>
<b-button class="btn-circle absolute-float-tight text-dark" v-on:click="reveal=!reveal">
<font-awesome-icon v-if="!reveal" :icon="faPlusIcon" />
<font-awesome-icon v-if="reveal" :icon="faMinusIcon" />
</b-button>
<transition name="custom-classes-transition" enter-active-class="animated bounceInDown" leave-active-class="animated bounceOutRight">
<div v-if="reveal" class="absolute-float-reveal">
<b-button class="btn-circle text-dark" v-on:click="addCodeBlock"><font-awesome-icon :icon="faCodeIcon" /></b-button>
</div>
</transition>
</div>
</template>
<script>
import Vue from 'vue'
import FontAwesomeIcon from '#fortawesome/vue-fontawesome'
import faPlus from '#fortawesome/fontawesome-pro-regular/faPlus'
import faMinus from '#fortawesome/fontawesome-pro-regular/faMinus'
import faCode from '#fortawesome/fontawesome-pro-regular/faCode'
import CodeBlock from './CodeBlock'
export default {
name: 'ButtonSidebar',
computed: {
faPlusIcon () {
return faPlus
},
faMinusIcon () {
return faMinus
},
faCodeIcon () {
return faCode
}
},
components: {
FontAwesomeIcon,
CodeBlock
},
data () {
return {
reveal: false
}
},
props: ['codeBlocks'],
methods: {
addCodeBlock () {
var ComponentClass = Vue.extend(CodeBlock)
var instance = new ComponentClass({
propsData: { type: 'primary' }
})
instance.$mount()
this.$el.querySelector('#pageBlocks').appendChild(instance.$el)
}
}
}
</script>
<style scoped>
.absolute-float-tight {
left: 20px;
position: absolute;
}
.absolute-float-reveal {
left: 60px;
position: absolute;
}
.btn-circle {
background-color: transparent;
border-radius: 50%;
height: 34px;
padding: 0;
width: 34px;
}
</style>
It's around the this.$el.querySelector('#pageBlocks').appendChild(instance.$el) part that I start to loose the plot a bit...I'm worried that I have to strip everything down and start again perhaps?
You should avoid reaching to the DOM as much as possible. The source of truth for the data should be in your components.
refs are very useful to integrate other js library that needs a DOM element.
So in your case, assuming codeBlocks are available in your App.vue components, the SidebarButton needs to emit an event when it's clicked so that the parent App.vue can add a new Codeblock:
(I have removed some code not needed for the example. CodeBlock.vue stays the same)
App.vue
<template>
<div id="app" class="container">
<ButtonSidebar #add-block="addCodeBlock" />
<CodeBlock v-for="block in codeBlocks" :type="block.type" />
</div>
</template>
<script>
import ButtonSidebar from '../ButtonSidebar'
import CodeBlock from '../CodeBlock'
export default {
name: 'App',
components: {ButtonSidebar, CodeBlock},
data() {
return {
codeBlocks: []
}
},
methods: {
addCodeBlock() {
const newBlock = {type: 'whatever'}
this.codeBlocks.push(newBlock)
}
}
}
</script>
ButtonSideBar.vue
<template>
<div>
<b-button class="btn-circle text-dark" v-on:click="addCodeBlock</b-button>
</div>
</template>
<script>
export default {
name: 'ButtonSidebar',
data () {
return {
reveal: false
}
},
methods: {
addCodeBlock () {
this.$emit('add-block')
}
}
}
</script>
A good pattern to follow in Vue is to lift the state to the parents and passing it down as props whenever you feel like you want to share state between parents and children.
I think you could achieve it in this simple way:
App.vue (template section)
<ButtonSidebar #add="addCodeItem"/>
<div id="pageBlocks">
<codeBlock v-for="code in arrCodes" :type="code.type"/>
</div>
App.vue (script)
export default {
data() {
return {
arrCodes: []
}
},
methods: {
addCodeItem(codeType) {
this.arrCodes.push( { type: codeType } )
}
}
}
ButtonSidebar.vue (script section)
addCodeBlock () {
this.$emit('add', 'yourtype');
}

Categories