passing icons into a JS object - javascript

I have a js file with an array of objects, I am trying to load the attributes dynamically with a component and I cannot seem to figure out how to pass icons to the rendering component.
Here is the component that I am using to render the data:
import React, { Component } from 'react';
import SkillData from '../../store/skillData';
import './SkillsCard.css';
class SkillsCard extends Component {
state = { }
renderSkills = () =>
SkillData.map((skill, _id) =>
<div key={_id} className="skillCard col-sm-3 m-2">
<div className="top">
{/* ***line in question*** */}
<div className="icon">{skill.icon}</div>
<h5>{skill.title}</h5>
</div>
<div className="bottom">
{skill.techs.map((tech,index)=>(
<div className='skillCardList' key={index}> {tech}</div>
))}
</div>
</div>
);
render() {
return (
this.renderSkills()
);
}
}
export default SkillsCard;
and here is the file that I am pulling data from:
const SkillData = [
{
_id: '1',
icon: '../../assets/icons/frontend.png',
title: 'Front End',
techs: ['HTML5', 'CSS | SCSS', 'JavaScript', 'React | Redux', 'Angular']
},
{
_id: '2',
icon: '../../assets/icons/server.png',
title: 'Back End',
techs: ['NodeJS', 'Express', 'Postman', 'Authentication | Authorization']
},
{
_id: '3',
icon: '../../assets/icons/database.png',
title: 'Databases',
techs: ['MongoDB', 'mySQL', 'PostgreSQL']
}
]
export default SkillData
The issue that I am having is that I cannot get the path name to the icons to evaluate and actually render the icon; Instead my component renders the text, listed on the path. All the other attributes render just fine! Any thoughts?

Because you're just rendering the string value to the page:
<div className="icon">{skill.icon}</div>
Did you mean to use an <img> element?:
<div className="icon">
<img src={skill.icon} />
</div>

This worked when I added
const icons = require.context('../assets/icons', true);
in the SKillData.js file and set the paths to:
icons('./iconName.png'),
Thanks a million, David!

This works for me.
Direct require from your local assets folder, so you dont need the complexity to head file import a link from a json file request
{/* line in question */}
<div className="icon">
<img src={require(`${skill.icon}`)} />
</div>

Related

Ho to map through mui icons to redirect to url like github/project-url

//i have a separate project file of the projectlist as an array with object, which have the necessary links that i need to map through.
//I just need some help with adding them into the github icon and when a user clicks they can navigate through to the appropriate links from the projectlist. I realise i need to use Object.entries(obj).map(). However, none of the methods i have attempted so far have worked. I am new to react so this may be simpler than I am actually making it. All help is appreciated.
import { useParams } from "react-router-dom";
import { ProjectList } from "../helpers/ProjectList";
import GitHubIcon from "#mui/icons-material/GitHub";
import LanguageIcon from "#mui/icons-material/Language";
import "../styles/ProjectDisplay.css";
//useParams returns an object key/value pairs of the dynamic params from the current URL that were matched by the <Route path>
function ProjectDisplay() {
const { id } = useParams();
const project = ProjectList[id];
return (
<div className="project">
<h1>{project.name}</h1>
<img src={project.image} alt="portfolio-projects" />
<p>
<b>Skills:</b>
{project.skill}
</p>
<GitHubIcon />
<LanguageIcon />
</div>
);
}
export default ProjectDisplay;
*//projectlist below*
export const ProjectList = [
{
name: "SquareSpace Website Homage",
image: squarespace,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/Portoflio-Website",
website: "https://mysquarespacehomage.netlify.app/",
},
{
name: "HarryPorter theme TODO CRUD app",
image: harryporter,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/TO-DO-APP",
website: "https://gabriellatodoapp.netlify.app/",
},
{
name: "Restaurant Reservation System",
image: reservation,
skill: "React, Redux Toolkit and TypeScript",
github:
"https://github.com/LouisNzavi/RestaurantReservation---reduxToolkit-Typescrpt",
},
{
name: "Deposit/Withdraw system",
image: depositWithdraw,
skill: "React, JavaScript, Redux: reducers/store/action-creators",
github: "https://github.com/LouisNzavi/React-with-redux-deposit-withdraw-",
},
{
name: "Four-card landing page feature",
image: fourcardfeature,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/Four-card-feature-design-file",
},
{
name: "Vancouver Sleep Clinc website",
image: vancouver,
skill: "HTML, CSS",
github: "https://github.com/LouisNzavi/Vancouver-Sleep-Clinc-PROJ",
},
{
name: "Intro component with SignUp form",
image: signupForm,
skill: "HTML, CSS, JavaScript",
github: "https://github.com/LouisNzavi/Intro-Signup-form",
},
];
I think this is you want to do
import { useParams } from "react-router-dom";
import { ProjectList } from "../helpers/ProjectList";
import GitHubIcon from "#mui/icons-material/GitHub";
import LanguageIcon from "#mui/icons-material/Language";
import "../styles/ProjectDisplay.css";
//useParams returns an object key/value pairs of the dynamic params from the current URL that were matched by the <Route path>
function ProjectDisplay() {
const { id } = useParams();
const project = ProjectList[id];
return (
<React.Fragment>
{ProjectList.map((project, index) =>
<div key={index} className="project">
<h1>{project.name}</h1>
<img src={project.image} alt="portfolio-projects" />
<p>
<b>Skills:</b>
{project.skill}
</p>
<a href={project.github} rel="noopener noreferrer" target="_blank">
<GitHubIcon />
</a>
<LanguageIcon />
</div>
)}
</React.Fragment>
);
}
export default ProjectDisplay;
You can map your array to the component which will return an array of project components then you can directly render it. I am assuming you are using import to use images in project.name.

VueEditor document is not defined Nuxt.js

In my Nuxt.js project I installed vue2-editor package to be able to write articles with HTML. When I come to page, write something and press the button everything works correctly, but when I reload page, I get document is not defined error.
Here is the code:
<template>
<div>
<SideBar />
<div class='content'>
<h1>Write article</h1>
<client-only>
<VueEditor
v-model='articleContent'
/>
</client-only>
<div style='margin-top: 15px'><button #click='postArticle'>Post article</button></div>
</div>
</div>
</template>
<script>
import { VueEditor } from 'vue2-editor';
import SideBar from '../components/SideBar';
export default {
name: 'Articles',
components: {
SideBar,
VueEditor
},
data() {
return {
articleContent: null,
}
},
methods: {
postArticle() {
console.log(this.articleContent)
},
},
}
</script>
And the error looks like that:
Also in documentation I've found that for Nuxt.js projects vue2-editor should be added to modules, and I did it, but it still doesn't work:
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
'vue2-editor/nuxt'
],
You can try to load it dynamically:
<template>
<div>
<SideBar />
<div class='content'>
<h1>Write article</h1>
<client-only>
<VueEditor
v-model='articleContent'
/>
</client-only>
<div style='margin-top: 15px'><button #click='postArticle'>Post article</button></div>
</div>
</div>
</template>
<script>
import SideBar from '../components/SideBar';
export default {
name: 'Articles',
components: {
SideBar,
VueEditor: () => process.client ? (await import("vue2-editor")).VueEditor : ""
},
data() {
return {
articleContent: null,
}
},
methods: {
postArticle() {
console.log(this.articleContent)
},
},
}
</script>
Do follow the below steps the add that plugin into your Nuxt
There will be plugins folder just like pages and components, if not create one and add a js file into it vue2-editor.js.
Copy the below content inside vue2-editor.js
import Vue from "vue";
import Vue2Editor from "vue2-editor";
Vue.use(Vue2Editor);
Inside nuxt.config.js remove the 'vue2-editor/nuxt' from the modules and create a separate array called plugins as below
/*
** Plugins to load before mounting the App
*/
plugins: [{ src: "~/plugins/vue2-editor", mode: 'client' }],
Thats it you are done. Now you can start using it in any of the vue files like
<vue-editor placeholder="Write Something..." v-model="content"></vue-editor>

Gatsby: Trying to get image path from front matter but getting this "TypeError: Cannot read property 'image' of undefined"

Im building a blog with Gatsby and I'm trying to display a hero image on each post page with the image path that is defined in each posts front matter. But, I'm getting this error from my hero component:
TypeError: Cannot read property 'image' of undefined
Here is my code:
Post front matter
---
path: /blog-post1
title: Blog Post 1
image: ../../images/blog-post-1.jpg
description: Blog post description
---
Hero.js
import React from 'react'
import Img from "gatsby-image";
const Hero = props => (
<section className="hero is-large">
<Img
fluid={props.frontmatter.image.childImageSharp.resize}
/>
<div className="hero-body">
</div>
</section>
);
export default Hero
Post.js
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/layout';
import Hero from '../components/hero';
const PostTemplate = ({ data }) => {
const { markdownRemark } = data;
const { frontmatter, html } = markdownRemark;
return (
<Layout>
<Hero headerImage={frontmatter.image} />
<section class="section">
<div className="container is-medium">
<div dangerouslySetInnerHTML={{__html: html}} />
</div>
</section>
</Layout>
)
}
export default PostTemplate;
export const pageQuery = graphql`
query($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
date
path
title
description
image {
childImageSharp {
resize(width: 1500, height: 1500) {
src
}
fluid(maxWidth: 786) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`;
Any ideas on what's happening? Thanks in advance.
I am assuming you have data in frontmatter variable all the time. If you look at how you are calling Hero Component, where you are passing data as headerImage.
<Hero headerImage={frontmatter.image} />
If you look at Hero component you are reading it as frontmatter, You can do following changes and check.
You can add the condition to Img component to avoid the errors because of missing data.
{
props.headerImage && props.headerImage.image && props.headerImage.image.childImageSharp
<Img
fluid={props.headerImage.image.childImageSharp.resize}
/>
}
I figured out was the issue.
In my hero.js, I was calling the image using {props.frontmatter.image.childImageSharp.resize}
But in my post.js I was passing the data into the hero component like this <Hero headerImage={frontmatter.image} />
So, it was trying to find frontmatter.image.image, which doesn't exist. All I had to do was remove the .image like this <Img fluid={props.headerImage.childImageSharp.resize} />

How do I bind a :src for an image in the child component?

I am attempting to render a list of components. All the data properties are displaying correctly except the img src url.
the files/folders are :
CryptContent.vue - contains the v-for
the component to render
assets/ - contains the images
The CryptContent.vue contain:
<template>
<OwnedCardContent
v-for="card in allCards"
:id="card.id"
:name="card.name"
:cost="card.cost"
:cset="card.cset"
:edition_total="card.edition_total"
:level="card.card_level"
:unlock_czxp="card.unlock_czxp"
:buy_czxp="card.buy_czxp"
:transfer_czxp="card.transfer_czxp"
:sacrifice_czxp="card.sacrifice_czxp"
:url="card.graphic"
:card_class="card.bg"
></OwnedCardContent>
</template>
<script>
allcards : [
{id:0, name: 'Jim Zombie',graphic: './assets/jim.svg', cost: 300, cset: 'We like to party set', edition_total: ' of 100',unlock_czxp : '1,300,300',card_level: 80, buy_czxp: '1,800',transfer_czxp: '100', sacrifice_czxp: '2,300',bg: 'card-bg card-bg-6'},
]
</script>`
OwnedCardContent.vue contains:
<template>
<div id="1" :class="card_class">
<img class="card-img" :src="url" />
<span class="card-edition">#1{{edition_total}}</span>
<div class="card-item-name text-center">{{name}}<br>{{cset}}</div>
<div class="card-czxp text-left">{{unlock_czxp}}</div>
<div class="card-level">{{level}}</div>
</div>
</div>
</template>
<script>
export default {
name: 'OwnedCardContent',
props: ['id','name','url','edition_total','cset','unlock_czxp','level','cost','buy_czxp','transfer_czxp','sacrifice_czxp','card_class'],
data () {
return {
}
}
}
</script>
The image won't render. When I inspect the code, the correct value from allCards graphic gets injected into the page..
when I remove :src and put just src="./assets/jim.svg" it works.
so I assume it's how webpack prepares it maybe ? I dont know enough about it :(
any help would be super helpful, thanks !
With webpack images are considered as modules so you should import or require them like :
allcards : [ {id:0, name: 'Jim Zombie',graphic: require('./assets/jim.svg'), ....]
or
import img from './assets/jim.svg';
export default{
...
data(){
return {
allcards : [ {id:0, name: 'Jim Zombie',graphic: img, ....],
...
}
}
...
}
Could you try use method for src
getImgUrl(path) {
var images = require.context('../assets/', false, /\.png$/)
return images('./' + path + ".png")
}
<div class="col-lg-2" v-for="pic in pics">
<img :src="getImgUrl(pic)" v-bind:alt="pic">
</div>
You can try this
<img v-attr="src:imgUrl">

pass a prop from a v-link in vue.js with vue-router

I have a prototype that I'm using vue.js, and vue-router in.
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let router = new VueRouter
import App from './App.vue'
import Details from './Details.vue'
import Pics from './Pics.vue'
router.map({
'/details':{
name: 'details',
component: Details
},
'/pictures':{
name: 'pics',
component: Pics
}
})
router.start(App, '#app')
App.vue contains my router-view mounting point. App also contains a list of Location components based on the location data stored in my shared state:
App.vue:
<script>
import state from './state.js'
import Location from './Location.vue'
module.exports = {
components: {Location},
data: () => {
return {
name: 'app',
locations: state.locations
}
}
}
</script>
<template>
<div class="app-container">
<h2 class="heading">Locations</h2>
<div class="body">
<div class="column">
<location v-for="location in locations" :location="location"></location>
</div>
<div class="column">
<router-view></router-view>
</div>
</div>
</div>
</template>
state.js:
exports.locations = [
{ name: 'Home', address: '123 main st', pics: [{src: '/images/123.png'}]},
{ name: 'Work', address: '555 Avenue st', pics: [{src: '/images/lol.jpg'}, {src: '/images/wrkn.jpg'}]},
{ name: 'Some Landmark', address: '42 E West st', pics: [{src: '/images/coolpic.jpg'}, {src: '/images/qwerty.jpg'}]}
]
The Location.vue component holds the v-links that I'm using to trigger the router:
Location.vue:
<script>
module.exports = {
props:['location'],
data: () => {
return {name: 'location'}
}
}
</script>
<template>
<div class="location-container">
<h3>{{location.name}}</h3>
<a v-link="{name: 'pics'}">Pics</a>
<a v-link="{name: 'details'}">Details</a>
</div>
</template>
What I would like would be to pass in the given location state instance as a prop to the component called by the router (either Details.vue or Pics.vue) when the particular location's v-link is clicked.
The problem I'm having is that while I know the docs say you can do this, they don't explain how to do this and I've not been able to figure out how. I tried binding location to the router-view in App.vue:
<router-view :location="location"></router-view>
And binding it to a placeholder within router-view:
<router-view>
<details :location="location"></location>
</router-view>
Neither of which work.
What's the proper way of doing this?
I have a WebpackBin demo of the problem here: http://www.webpackbin.com/4kDRbt28W
For those intersted: We figured it out on gitter.
Solution is to not pass the object at all, but pass it's ID as a param in the URL (e.g. /details/1827), then get the object for that ID from the store in the component.
Advantages: URLs can be directly navigated to from external sources and application state will be fine.

Categories