I am trying to create a FAQ page and I am having below three files:
App.js
import React, { useState } from 'react';
import Header from './Header';
import FAQ from './FAQ';
function App () {
const [faqs, setfaqs] = useState([
{
id: 1,
question: 'This is question 1?',
answer: 'This is answer 1',
open: false
},
{
id: 2,
question: 'This is question 2?',
answer: 'This is answer 2',
open: false
},
{
id: 3,
question: 'This is question 3?',
answer: 'This is answer 3',
image: 'Question3.png',
open: false
},
{
id: 4,
question: 'This is question 4?',
answer: 'This is answer 4',
open: false
}
]);
const toggleFAQ = index => {
setfaqs(faqs.map((faq, i) => {
if (i === index) {
faq.open = !faq.open
} else {
faq.open = false;
}
return faq;
}))
}
return (
<div className="App">
<Header />
<div className="faqs">
{faqs.map((faq, i) => (
<FAQ faq={faq} index={i} key={faq.id} toggleFAQ={toggleFAQ} />
))}
</div>
</div>
);
}
export default App;
FAQ.js
import React from 'react'
function FAQ ({faq, index, toggleFAQ}) {
// console.log(faq.hasOwnProperty('url'));
if(faq.hasOwnProperty('url') && faq.hasOwnProperty('image')){
console.log("Hello URL");
return (
<div
className={"faq " + (faq.open ? 'open' : '')}
key={faq.id}
onClick={() => toggleFAQ(index)}
>
<div>
<div className="faq-question">
{faq.question}
</div>
<div className="faq-answer">
{faq.answer}
<div className="faq-url">
<a href={faq.url}>Link to URL</a>
</div>
<div className="faq-image">
<img src={`/src/media/${faq.image}`} alt="Image for FAQ"/>
</div>
</div>
</div>
</div>
)
}
else {
console.log("No url");
return (
<div
className={"faq " + (faq.open ? 'open' : '')}
key={faq.id}
onClick={() => toggleFAQ(index)}
>
<div>
<div className="faq-question">
{faq.question}
</div>
<div className="faq-answer">
{faq.answer}
</div>
</div>
</div>
)
}
}
export default FAQ;
Index.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: rgb(255, 255, 255);
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
header {
display: flex;
justify-content: center;
align-content: center;
padding: 5px;
background-color:#4caf50;
border-bottom: 3px solid #3c3c3c;
}
header h1 {
color: rgb(26, 25, 25);
font-size: 28px;
font-weight: 700;
text-transform: uppercase;
}
.faqs {
width: 100%;
max-width: 768px;
margin: 0 auto;
padding: 15px;
}
.faqs .faq {
margin: 20px;
padding: 15px;
background-color:#f5f5f5 ;
border: 2px solid black;
border-radius: 8px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}
.faqs .faq:hover {
background-color: #f0ebeb;
}
.faqs .faq .faq-question {
position: relative;
font-size: 20px;
padding-right: 80px;
transition: all 0.4s ease;
}
.faqs .faq .faq-question::after {
content: '\2B9B';
position: absolute;
color: black;
top: 50%;
right: 0px;
transform: translateY(-50%);
margin-top: 10px;
width: 50px;
height: 50px;
transition: all 0.4s ease-out;
}
.faqs .faq .faq-answer {
opacity: 0;
max-height: 0;
overflow-y: hidden;
transition: all 0.4s ease-out;
}
.faqs .faq.open .faq-question {
margin-bottom: 15px;
}
.faqs .faq.open .faq-question::after {
/* transform: translateY(-70%) rotate(180deg); */
content: "\2B99";
}
.faqs .faq.open .faq-answer {
max-height: 1000px;
opacity: 1;
}
Directory structure of all the pages are like below:
App.js consist of state of objects containing various question and answers for FAQ page. Also it consist of FAQToggle which checks if Accordion is open or not and closes the accordion if it is open and vice versa.
FAQ.js Line:24(Actual issue which I am facing): I am trying to add an image so that answer 3 can hold the image. But all I can see is a broken image icon. Can anyone help me in debugging this?
I think you can only use photos in your components if you import then first, let me know if im wrong. https://create-react-app.dev/docs/adding-images-fonts-and-files/
This post says you "need" to import them first: https://www.edwardbeazer.com/importing-images-with-react/
Heres another: https://daveceddia.com/react-image-tag/
Quote - "A common mistake for beginners is to set the src to a file path on their computer, like /Users/yourname/Projects/this-react-app/src/image.png. That won’t work."
Quote - "Browsers are mostly sandboxed these days and won’t let you access files by their path on disk. If you did get that to work (maybe with file://), it’d break as soon as you deployed the app, because a web server won’t have that file in the same place! (And no, the solution is not to put it in the same place on the server"
import React, { useState } from 'react';
import Header from './Header';
import FAQ from './FAQ';
import Question3 from "./media/Question3.png" //import img here
function App () {
const [faqs, setfaqs] = useState([
{
id: 1,
question: 'This is question 1?',
answer: 'This is answer 1',
open: false
},
{
id: 2,
question: 'This is question 2?',
answer: 'This is answer 2',
open: false
},
{
id: 3,
question: 'This is question 3?',
answer: 'This is answer 3',
image: Question3, // use it as a variable
open: false
},
{
id: 4,
question: 'This is question 4?',
answer: 'This is answer 4',
open: false
}
]);
const toggleFAQ = index => {
setfaqs(faqs.map((faq, i) => {
if (i === index) {
faq.open = !faq.open
} else {
faq.open = false;
}
return faq;
}))
}
return (
<div className="App">
<Header />
<div className="faqs">
{faqs.map((faq, i) => (
<FAQ faq={faq} index={i} key={faq.id} toggleFAQ={toggleFAQ} />
))}
</div>
</div>
);
}
export default App;
if(faq.hasOwnProperty('url') && faq.hasOwnProperty('image')){
console.log("Hello URL");
return (
<div
className={"faq " + (faq.open ? 'open' : '')}
key={faq.id}
onClick={() => toggleFAQ(index)}
>
<div>
<div className="faq-question">
{faq.question}
</div>
<div className="faq-answer">
{faq.answer}
<div className="faq-url">
<a href={faq.url}>Link to URL</a>
</div>
<div className="faq-image">
<img src={faq.image} alt="Image for FAQ"/> //target it here
</div>
</div>
</div>
</div>
Related
So I have a problem with VueJs. I created a "Confirmation Dialogue" and added it to a On-Click-Event on buttons. It worked fine.
Now I tried to copy the implementation to add it to another button on a different parent. It says "TypeError: this.$refs.confirmDialogue.show is not a function" in the Console whenever I try to click the button. The other button still works completly normal.
Am I missing something? I already tried to remove the working button, so only one component uses the Confirm Dialogue but that also didn't work.
I'm new to VueJs. Hope someone can help me with this problem.
Child PopupModal:
<template>
<transition name="fade">
<div class="popup-modal" v-if="isVisible">
<div class="window">
<slot></slot>
</div>
</div>
</transition>
</template>
<script>
export default {
name: 'PopupModal',
data: () => ({
isVisible: false,
}),
methods: {
open() {
this.isVisible = true
},
close() {
this.isVisible = false
},
},
}
</script>
<style scoped>
/* css class for the transition */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.popup-modal {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 0.5rem;
display: flex;
align-items: center;
z-index: 1;
}
.window {
background: #fff;
border-radius: 5px;
box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.2);
max-width: 480px;
margin-left: auto;
margin-right: auto;
padding: 1rem;
}
</style>
Parent ConfirmDialogue:
<template>
<popup-modal ref="popup">
<h2 style="margin-top: 0">{{ title }}</h2>
<p>{{ message }}</p>
<div class="btns">
<button class="cancel-btn" #click="_cancel">{{ cancelButton }}</button>
<span class="ok-btn" #click="_confirm">{{ okButton }}</span>
</div>
</popup-modal>
</template>
<script>
import PopupModal from "../confirmDialogue/PopupModal.vue"
export default {
name: 'ConfirmDialogue',
components: { PopupModal },
data: () => ({
// Parameters that change depending on the type of dialogue
title: undefined,
message: undefined, // Main text content
okButton: undefined, // Text for confirm button; leave it empty because we don't know what we're using it for
cancelButton: 'Abbrechen', // text for cancel button
// Private variables
resolvePromise: undefined,
rejectPromise: undefined,
}),
methods: {
show(opts = {}) {
this.title = opts.title
this.message = opts.message
this.okButton = opts.okButton
if (opts.cancelButton) {
this.cancelButton = opts.cancelButton
}
// Once we set our config, we tell the popup modal to open
this.$refs.popup.open()
// Return promise so the caller can get results
return new Promise((resolve, reject) => {
this.resolvePromise = resolve
this.rejectPromise = reject
})
},
_confirm() {
this.$refs.popup.close()
this.resolvePromise(true)
},
_cancel() {
this.$refs.popup.close()
this.resolvePromise(false)
// Or you can throw an error
// this.rejectPromise(new Error('User cancelled the dialogue'))
},
},
}
</script>
<style scoped>
.btns {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.ok-btn {
padding: 0.5em 1em;
background-color: #1F51FF;
color: #fff;
border: 2px solid #0ec5a4;
border-radius: 5px;
font-size: 16px;
text-transform: uppercase;
cursor: pointer;
}
.cancel-btn {
padding: 0.5em 1em;
background-color: #d5eae7;
color: #000;
border: 2px solid #0ec5a4;
border-radius: 5px;
font-size: 16px;
text-transform: uppercase;
cursor: pointer;
}
</style>
Working button:
<td class="last-td last-row">
<div class="button-wrapper">
<div class="wrapper-edit">
<button class="button button-edit">Bearbeiten</button>
</div>
<div class="wrapper-cancel">
<button class="button button-cancel" #click="doDelete">Löschen</button> <!-- Here is the working button -->
<confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
</div>
</div>
</td>
</tr>
</thead>
</template>
<script>
import ConfirmDialogue from '../confirmDialogue/ConfirmDialogue.vue'
export default {
name: "bookingElements",
components: { ConfirmDialogue },
methods: {
async doDelete() {
const ok = await this.$refs.confirmDialogue.show({
title: 'Buchung löschen',
message: 'Sind Sie sicher, dass Sie die Buchung löschen wollen?',
okButton: 'Buchung löschen',
})
if (ok) {
alert('Die Buchung wurde Erfolgreich gelöscht')
}
},
Button that isn't working:
<td id="buttonCell">
<button class="button" #click="doDelete">Buchen</button>
<confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
</td>
</tr>
</tbody>
</template>
<script>
import ConfirmDialogue from "../confirmDialogue/ConfirmDialogue.vue"
export default {
name: "bookElements",
components: { ConfirmDialogue },
methods: {
async doDelete() {
const ok = await this.$refs.confirmDialogue.show({
title: 'Buchung löschen',
message: 'Sind Sie sicher, dass Sie die Buchung löschen wollen?',
okButton: 'Buchung löschen',
})
if (ok) {
alert('Die Buchung wurde Erfolgreich gelöscht')
}
},
I got found the mistake.
I created a for-each loop to create the Table.
At the working button there was no for-each loop though.
So VueJs tried to generate the Confirmation Dialogue 9 times and this resulted to an error.
So I just need to put the
<confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
to the top of Template like this
<template>
<confirm-dialogue ref="confirmDialogue"></confirm-dialogue>
...
</template>
because it's vanished and only shows when the button is clicked.
This question already has answers here:
React - toggle only one button, not all
(3 answers)
Closed 11 months ago.
I ma trying to make a Quiz App using React.So, I have been trying to use various methods to make a button change its color when clicked (only the button that was clicked) but when I click it all of them change their color. Any solution for making only the button clicked to change its color? in React.js.
App.js
import Main from './Main'
import Quiz from './Quiz'
import { useState } from 'react'
export default function App() {
const [switch1, setSwitch1] = useState(false)
const [color , setColor] = useState(false)
const qanda = [
{
"question": "In web design, what does CSS stand for?",
"answerOptions" : [ {"answerText" : "Cascading Style Sheet" , "correctAns" : "true" , "id":1 } ,
{"answerText" : "Counter Strike: Source" , "correctAns" : "false" , "id":2 } ,
{"answerText" : "Corrective Style Sheet" , "correctAns" : "flase" , "id":3 } ,
{"answerText" : "Computer Style Sheet" , "correctAns" : "false" , "id":4 } ]
},
{
"question": "Under what pseudonym did Stephen King publish five novels between 1977 and 1984?",
"answerOptions" : [ {"answerText" : "Mark Twain" , "correctAns" : "false" , "id":5} ,
{"answerText" : "Richard Bachman" , "correctAns" : "true" , "id":6} ,
{"answerText" : "J. D. Robb" , "correctAns" : "false" , "id":7} ,
{"answerText" : "Lewis Carroll" , "correctAns" : "false" , "id":8} ]
},
{
"question": "Which modern day country is the region that was known as Phrygia in ancient times?",
"answerOptions" : [ {"answerText" : "Greece" , "correctAns" : "false" , "id":9} ,
{"answerText" : "Syria" , "correctAns" : "false" , "id":10} ,
{"answerText" : "Egypt" , "correctAns" : "false" , "id":11 } ,
{"answerText" : "Turkey" , "correctAns" : "true" , "id":12} ]
},
]
const quizQ = qanda.map(ques => <Quiz question={ques.question} answer1={ques.answerOptions[0].answerText} answer2={ques.answerOptions[1].answerText}
answer3={ques.answerOptions[2].answerText} answer4={ques.answerOptions[3].answerText} click={switchColor} clicked={color} />)
// function getId() {
// for(const i = 0 ; i > 3 ; i++) {
// const qId = qanda.map(ques => ques.answerOptions[i].id)
// }
// }
function switchIt() {
setSwitch1(prevValue => !prevValue)
}
function switchColor() {
setColor(prevValue => !prevValue)
}
return (
<div className="body">
{switch1 ? quizQ : <Main onclick={switchIt}/> }
</div>
)
}
Quiz.js
import blob1 from './blob1.png'
import blob2 from './blob2.png'
export default function Quiz(props) {
const style = {
backgroundColor: props.clicked && '#D6DBF5',
border: props.clicked && '#293264'
}
return (
<div className='quiz-body'>
<img src={blob1} className="blob1"/>
<img src={blob2} className="blob2"/>
<h2 className='h2-quiz'>{props.question}</h2>
<button className='btn-ans' onClick={props.click} style={style}>{props.answer1}</button>
<button className='btn-ans' onClick={props.click} style={style}>{props.answer2}</button>
<button className='btn-ans' onClick={props.click} style={style}>{props.answer3}</button>
<button className='btn-ans' onClick={props.click} style={style}>{props.answer4}</button>
<br/>
<br/>
<hr/>
</div>
)
}
Main.js
import blob1 from './blob1.png'
import blob2 from './blob2.png'
export default function Main(props) {
return (
<main>
<img src={blob1} className="blob1"/>
<h1 className='main-h1'>Quizzical</h1>
<p className='main-description'>Welcome, to the Quizzical Quiz game.</p>
<button className='main-button' onClick={props.onclick} >Start Quiz</button>
<img src={blob2} className="blob2"/>
</main>
)
}
index.css
body {
margin: 0%;
padding: 0%;
background-color: #F5F7FB;
font-family: 'karla' , sans-serif ;
}
/* Home Page Part */
main {
text-align: center;
margin-top: 40vh;
}
.main-h1 {
margin: 0;
font-size: 100px;
}
.main-description {
font-size: 40px;
margin-top: auto;
margin-bottom: 50px;
}
.main-button {
font-size: 30px;
padding: 5px;
background: #4D5B9E;
border-radius: 15px;
width: 150px;
border: none;
color: #F5F7FB;
font-family: 'karla' , sans-serif ;
cursor: pointer;
}
.blob1 {
position: absolute;
top:0;
right: 0;
}
.blob2 {
position: absolute;
bottom:0;
left: 0;
}
/* Quiz Part */
.quiz-body {
/* background-color: #4D5B9E; */
width: 65%;
text-align: left;
margin: auto;
}
.h2-quiz {
font-size:25px;
font-weight:800;
}
.btn-ans {
font-size: 15px;
border: solid 1px black;
padding-left: 15px;
padding-right: 15px;
padding-top: 5px;
padding-bottom: 5px;
font-family: 'karla';
font-weight: 600;
margin: 10px;
background-color:#F5F7FB ;
border-radius: 10px ;
}
I am sorry if I have done the techniques wrong this is my first project after learning React
You can try to use state to store the color. Maybe this would give you the idea how to solve the problem :
class Test extends React.Component {
constructor(){
super();
this.state = {
black: true
}
}
changeColor(){
this.setState({black: !this.state.black})
}
render(){
let btn_class = this.state.black ? "blackButton" : "whiteButton";
return (
<button className={btn_class} onClick=.
{this.changeColor.bind(this)}>
Button
</button>
)
}
}
React.render(<Test />, document.getElementById('container'));
ej:https://jsfiddle.net/tkkqx2y2/
thnks to #user3350597 for response
import React, { useState } from "react";
import "./App.css";
const App = () => {
const [style, setStyle] = useState(true);
const changeStyle = () => {
setStyle(!style);
};
return (
<div className={style ? "cont" : "cont2"}>
<button className="button" onClick={changeStyle}>
Click me!
</button>
</div>
);
};
export default App;
.cont {
width: 250px;
height: 250px;
margin-top: 50px;
margin-left: 150px;
background-color: violet;
}
.cont2 {
width: 250px;
height: 250px;
margin-top: 50px;
margin-left: 150px;
background-color: yellow;
}
You can try this way :-
import "./styles.css";
import "./App.css";
import { useState } from "react";
export default function App() {
const [active, setActive] = useState(null);
const handler = (i) => {
setActive(i);
};
const btns = [
{ id: 0, title: "First Button" },
{ id: 1, title: "Second Button" },
{ id: 2, title: "Third Button" }
];
return (
<div className="App">
{btns.map((btn, i) => (
<button
key={i}
className={i === active ? "active-btn" : "inactive-btn"}
onClick={() => handler(i)}
>
{btn.title}
</button>
))}
</div>
);
}
.inactive-btn {
border: none;
padding: 8px;
border-radius: 12px;
color: white;
background: grey;
}
.active-btn {
color: white;
border: none;
padding: 8px;
border-radius: 12px;
background: black;
}
I have some cards in my dashboard and in the dashboard I am getting some cards which contains title and description of the card, which I am getting from backend(axios.js).Upto display section i am getting, but in my case i want to update a particular card, when i click on any card the update popup card is coming. when i click on any card it opens popup card this card purpose is to update the content based on the card id(card details stored inside notes[] array in Getnote.vue),Here my question is How to get that particular card id when user clicks on card and how to connect this thing to the back end Api for update the particular note. please help me to fix this issue
Updatenote.vue
<template>
<div class="updatecard-notes">
<form class="updatecard-container" #submit.prevent="handleSubmit" id="update-id">
<input name="title" id="name-in" v-model="title" placeholder="Title" autocomplete="off" />
<textarea name="content" id="text-in" v-model="description" placeholder="Take a note..." autocomplete="off"></textarea>
<Icon />
<button #click="updateNotes()" type="submit">Close</button>
</form>
</div>
</template>
<script>
import service from '../../service/User'
import Icon from '../../components/pages/Icon.vue'
export default {
name: 'Updatenote',
components: {
Icon
},
data() {
return {
id:'',
title:'',
description:''
}
},
methods: {
updateNotes: function() {
const updateData ={
id:this.id,
title:this.title,
description:this.description
};
service.userUpdateNote(updateData).then(response => {
console.log("update",response);
localStorage.setItem('token',response.data.token);
this.notes.push(...response.data);
})
},
}
}
</script>
<style scoped>
.updatecard-container {
/* width: 100px; */
padding: 4px 10px;
font-size: 1rem;
/* margin-left: 200px; */
margin-bottom: -200px;
margin-top: -160px;
position: fixed;
width: 620px;
height: 150px;
box-shadow: 5px 5px 10px #e0dede;
/* margin-left: 731px; */
font-family: 'Times New Roman', Times, serif;
}
form textarea {
width: 100%;
border: none;
padding: 0px 10px;
outline: none;
font-size: 1rem;
resize: none;
}
form input {
width: 90%;
border: none;
padding: 4px 10px;
margin-bottom: 10px;
margin-left: 0px;
margin-top: 2px;
font-size: 1.1rem;
}
form button {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
right: 25px;
bottom: 10px;
background: white;
color: rgb(0, 0, 0);
border: none;
width: 50px;
height: 36px;
cursor: pointer;
font-size: 1.1rem;
font-family: 'Times New Roman', Times, serif;
}
</style>
User.js
import AxiosService from '../service/axios';
const axios = new AxiosService()
export default{
userRegister(data){
return axios.postData('/register', data);
},
userLogin(data){
return axios.postData("/login",data);
},
userForgotPassword(data){
return axios.postData("/auth/sendPasswordResetLink",data);
},
userResetPassword(data){
return axios.postData("/auth/resetPassword",data);
},
userCreateNote(data){
return axios.postData("/notes",data);
},
userGetNote(){
return axios.getData("/notes");
},
userUpdateNote(id, data){
console.log("ID: ",id);
return axios.putData(`/notes/${id}`, data);
}
}
axios.js
import axios from 'axios'
axios.defaults.baseURL=process.env.VUE_APP_ROOT_URL
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token');
export default class AxiosService{
postData(url, data){
return axios.post(url, data).then(response =>{
return response;
}).catch(error=>{
return error;
})
}
getData(url){
return axios.get(url).then(response =>{
return response;
}).catch(error=>{
return error;
})
}
putData(url, data){
return axios.put(url, data).then(response=>{
return response;
}).catch(error=>{
return error;
})
}
}
Getnotes.vue
<template>
<div class="carddisplay-notes">
<div class="carddisplay-container" v-for="note in notes" :key="note.data">
<div class="carddisplay" #click="togglePopup()">
<h3>{{note.title}}</h3>
<p>{{note.description}}</p>
</div>
<div class="carddisplay-icons">
<Icon />
<button class="card-button" type="button" v-if="flag" #click="handleSubmit();ToggleButton();">Close</button>
</div>
</div>
<div class="cardupdate-popup" id="popup">
<Updatenote />
</div>
</div>
</template>
<script>
import service from '../../service/User'
import Icon from '../../components/pages/Icon.vue'
import Updatenote from '../../components/pages/Updatenote.vue'
export default {
name: 'Getnote',
components: {
Icon, Updatenote
},
data() {
return {
flag: true,
notes:[{
id:1,
title: 'notes',
description: 'display notes'
},],
}
},
methods: {
ToggleButton(){
this.flag = !this.flag;
},
async handleSubmit() {
service.userGetNote().then(response => {
this.notes.push(...response.data);
})
},
togglePopup(){
var popup=document.getElementById('popup');
popup.classList.toggle('active');
}
}
}
</script>
<style lang="scss" scoped>
#import "#/SCSS/Getnote.scss";
</style>
In GetNotes.vue create a property in the data option, which will track the currently clicked card using the id and then pass that id to the UpdateNote component.
GetNotes.vue
<template>
<div class="carddisplay-notes">
<div class="carddisplay-container" v-for="note in notes" :key="note.id">
<div class="carddisplay" #click="togglePopup(note.id)">
<h3>{{note.title}}</h3>
<p>{{note.description}}</p>
</div>
<div class="carddisplay-icons">
<Icon />
<button class="card-button" type="button" v-if="flag" #click="handleSubmit();ToggleButton();">Close</button>
</div>
</div>
<div class="cardupdate-popup" id="popup">
<Updatenote :cardId="clickedCard"/>
</div>
</div>
</template>
<script>
import service from '../../service/User'
import Icon from '../../components/pages/Icon.vue'
import Updatenote from '../../components/pages/Updatenote.vue'
export default {
name: 'Getnote',
components: {
Icon, Updatenote
},
data() {
return {
flag: true,
notes:[{
id:1,
title: 'notes',
description: 'display notes'
},],
clickedCard: '',
}
},
methods: {
ToggleButton(){
this.flag = !this.flag;
},
async handleSubmit() {
service.userGetNote().then(response => {
this.notes.push(...response.data);
})
},
togglePopup(id){
var popup=document.getElementById('popup');
popup.classList.toggle('active');
this.clickedCard = id;
}
}
}
</script>
<style lang="scss" scoped>
#import "#/SCSS/Getnote.scss";
</style>
In Updatenote component use that id to make the api call. Here the cardId will contain the id of currently clicked card.
Updatenote.vue
<template>
<div class="updatecard-notes">
<form class="updatecard-container" #submit.prevent="handleSubmit" id="update-id">
<input name="title" id="name-in" v-model="title" placeholder="Title" autocomplete="off" />
<textarea name="content" id="text-in" v-model="description" placeholder="Take a note..." autocomplete="off"></textarea>
<Icon />
<button #click="updateNotes()" type="submit">Close</button>
</form>
</div>
</template>
<script>
import service from '../../service/User'
import Icon from '../../components/pages/Icon.vue'
export default {
name: 'Updatenote',
components: {
Icon
},
props: ['cardId'],
data() {
return {
title:'',
description:''
}
},
methods: {
updateNotes: function() {
const updateData ={
id:this.cardId,
title:this.title,
description:this.description
};
service.userUpdateNote(updateData).then(response => {
console.log("update",response);
localStorage.setItem('token',response.data.token);
this.notes.push(...response.data);
})
},
}
}
</script>
<style scoped>
...........
</style>
Am trying to bulid vertical tab that will function exactly like in the demo link below
sample links from w3schools
here is the screenshot of what am trying to achieve as per the demo sample above
To this effect tried solution found here at but it does not give me what I want as per demo sample above
Stackoverflow link
Now I have decided to go my own way in trying it out.
I have succeeded in displaying the content from an array via reactjs. when user click on each country, the content
of that country gets displayed.
My Problem:
My issue is that I cannot get it to display the content in a vertical tab div as can be seen in the screenshot
Here is the coding so far
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
class Country extends React.Component {
state = { open: false };
toggleOpen = id => {
alert(id);
this.setState(prevState => ({
open: !prevState.open
}));
};
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button onClick={() => this.toggleOpen(this.props.data.id)}>
{this.props.data.name}
</button>
</div>
<div>
{this.state.open && (
<div>
<div>
<b>id: </b>
{this.props.data.id}
</div>
<div>
<b>Info: </b>
{this.props.data.info}
</div>
<div>
<b>Country name:</b> {this.props.data.name}
</div>
content for <b> {this.props.data.name}</b> will appear here..
</div>
)}
</div>
</React.Fragment>
);
}
}
class VerticalTab extends React.Component {
constructor() {
super();
this.state = {
data: [
{ id: "1", name: "London", info: "London is the capital city of England." },
{ id: "2", name: "Paris", info: "Paris is the capital of France." },
{ id: "3", name: "Tokyo", info: "Tokyo is the capital of Japan." }
]
};
}
render() {
return (
<div>
<div>
{this.state.data.map(country => (
<Country key={country.id} data={country} />
))}
</div>
</div>
);
}
}
Is this what you are looking for?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentTab: -1,
data: [
{ id: "1", name: "London" ,info: "London is the capital city of England."},
{ id: "2", name: "Paris" ,info: "Paris is the capital of France." },
{ id: "3", name: "Tokyo" ,info: "Tokyo is the capital of Japan."}
]
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(currentTab) {
this.setState({ currentTab });
}
render() {
return (
<div>
<h2>Vertical Tabs</h2>
<p>Click on the buttons inside the tabbed menu:</p>
<div className="tab">
{this.state.data.map((button, i) => (
<button key={button.name} className="tablinks" onClick={() => this.handleClick(i)}>{button.name}</button>
)
)
}
</div>
<div className="tabcontent">
{this.state.currentTab !== -1 &&
<React.Fragment>
<h3>{this.state.data[this.state.currentTab].name}</h3>
<p>{this.state.data[this.state.currentTab].info}</p>
</React.Fragment>
}
</div>
</div>
)
}
}
ReactDOM.render( < App / > ,
document.getElementById('root')
);
* {box-sizing: border-box}
body {font-family: "Lato", sans-serif;}
/* Style the tab */
.tab {
float: left;
border: 1px solid #ccc;
background-color: #f1f1f1;
width: 30%;
height: 300px;
}
/* Style the buttons inside the tab */
.tab button {
display: block;
background-color: inherit;
color: black;
padding: 22px 16px;
width: 100%;
border: none;
outline: none;
text-align: left;
cursor: pointer;
transition: 0.3s;
font-size: 17px;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current "tab button" class */
.tab button.active {
background-color: #ccc;
}
/* Style the tab content */
.tabcontent {
float: left;
padding: 0px 12px;
border: 1px solid #ccc;
width: 70%;
border-left: none;
height: 300px;
}
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<div id="root" />
React Tabs with Hooks
Here is a link to react tabs. Maybe this will help you.
enter code here
I am new to Vue.js and I am stuck. I have pulled in API data from Github jobs via Vanilla JavaScript and now I want to create a user filter. I am starting out with a filter for job "type" meaning Full time, part time, etc. Also, this code in being put into a plugin in WordPress called Shortcoder. I have watched tutorials and looked at three other posts on Stackoverflow that are similar but cannot figure out why I am getting this error: "unexpected SyntaxError:Unexpected token: on the line that states selectedType="Full Time". Maybe I have just stared at it for too long and need a fresh set eyes. I would really appreciate someone else reviewing it. Thanks in advance. Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- VUE.JS CDN -->
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.22/dist/vue.js"></script>
<title>Github Jobs API</title>
<style>
* {
box-sizing: border-box
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: 'Dosis', sans-serif;
line-height: 1.6;
color: #696969;
background: white;
}
#root {
max-width: 1200px;
margin: 0 auto;
}
h1 {
text-align: center;
padding: 1.5rem 2.5rem;
background-color: #b0bac6;
margin: 0 0 2rem 0;
font-size: 1.5rem;
color: #696969;
}
p {
padding: 0 2.5rem 2.5rem;
margin: 0;
}
.container1{
display: flex;
flex-wrap: wrap;
}
.card {
margin: 1rem;
background: #bobac6;
box-shadow: 2px 4px 25px rgba(0, 0, 0, .1);
border-radius: 12px;
overflow: hidden;
transition: all .2s linear;
}
.card:hover {
box-shadow: 2px 8px 45px rgba(0, 0, 0, .15);
transform: translate3D(0, -2px, 0);
}
#media screen and (min-width: 600px) {
.card {
flex: 1 1 calc(50% - 2rem);
}
}
#media screen and (min-width: 900px) {
.card {
flex: 1 1 calc(33% - 2rem);
}
}
.card:nth-child(2n) h1 {
background-color: #b0bac6;
color: #696969;
}
.card:nth-child(4n) h1 {
background-color: #b0bac6;
color: #696969;
}
.card:nth-child(5n) h1 {
background-color #b0bac6;
color: #696969;
}
.container2 {
padding: 20px;
width: 90%;
max-width: 400px;
margin: 0 auto;
}
label {
display: block;
line-height: 1.5em;
}
ul {
margin-left: 0;
padding-left: 0;
list-style: none;
}
li {
padding: 8px 16px;
border-bottom: 1px solid #eee;
}
</style>
</head>
<body>
<!-- DIV for Vue.js filter -->
<div class="container2" id="jobs">
<div class="filter">
<label><input type="radio" v-model="selectedType" value="Full Time"/>Full Time</label>
<label><input type="radio" v-model="selectedType" value="Part Time"/>Part Time</label>
</div>
<ul class="job-list">
<li v-for="job in filteredJobs">{{ job.title }}</li>
</ul>
</div>
<!-- DIV FOR API DATA CARD DISPLAY -->
<div id="root"></div>
<script>
// USED STRICT MODE TO SOLVE: “UNCAUGHT SYNTAX ERROR: UNEXPECTED TOKEN
U IN JSON # POSITION 0”
'use strict';
// INITIATING APIDATA AS GLOBAL VARIABLE
var apiData= " ";
const app = document.getElementById('root');
const container1 = document.createElement('div');
container1.setAttribute('class', 'container1');
app.appendChild(container1);
var request = new XMLHttpRequest();
//GET REQUEST WITH USE OF HEROKU AS A PROXY TO SOLVE CORS ERROR
request.open('GET','https://cors-anywhere.herokuapp.com/https://jobs.github.com/positions.json?&markdown=true&page=1',
true);
request.onload = function () {
//CONVERT JSON DATA TO JAVASCRIPT OBJECTS USING JSON.PARSE
var apiData = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
apiData.forEach(job => {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const h1 = document.createElement('h1');
h1.textContent = job.title;
const p = document.createElement('p');
job.description = job.description.substring(0, 300);
p.textContent = `${job.description}...`;
container1.appendChild(card);
card.appendChild(h1);
card.appendChild(p);
});
// ERROR HANDLING
} else {
const errorMessage = document.createElement('marquee');
errorMessage.textContent = `It's not working!`;
app.appendChild(errorMessage);
}
}
request.send();
// APPLY FILTER TO API DATA USING VUE.JS
var vm = new Vue({
el: "#jobs",
data() {
return {
apiData:[],
search: ' ',
filterJobs: [ ]},
selectedType:"Full Time"
},
computed: {
filteredJobs: function() {
vm = this;
var category = vm.selectedType;
if(type === "part time") {
return vm.jobs;
} else {
return vm.jobs.filter(function(job) {
return job.type === type;
});
}
}
}
});
</script>
</body>
</html>
The syntax errors are in data():
data() {
return {
apiData: [],
search: ' ',
filterJobs: []}, // <-- FIXME: unexpected '}'
selectedType: "Full Time"
// <-- FIXME: missing '}' for the return statement
},
computed: {
...
Here's the code corrected:
data() {
return {
apiData: [],
search: ' ',
filterJobs: [], // <-- fixed
selectedType: "Full Time"
} // <-- fixed
},
computed: {
...
var vm = new Vue({
el: "#jobs",
data() {
return {
apiData: [],
search: " ",
jobs: [],
selectedType: "full time"
};
},
computed: {
filteredJobs: function() {
vm = this;
var type = vm.selectedType;
if (type === "part time") {
return vm.jobs;
} else {
return vm.jobs.filter(function(job) {
return job.type === type;
});
}
}
},
mounted() {
this.jobs = [
{id: 1, type: 'part time'},
{id: 2, type: 'full time'},
{id: 3, type: 'part time'},
{id: 4, type: 'full time'},
{id: 5, type: 'part time'},
]
}
});
<script src="https://unpkg.com/vue#2.6.1/dist/vue.min.js"></script>
<div id="jobs">
<ul>
<li v-for="job in filteredJobs" :key="job.id">
type: {{job.type}}
</li>
</ul>
</div>