ReactJS Collapsable Element with "Progess/Completion bar" - javascript

I am struggling to make a relatively simple component in React. The goal is to get something close to the following image:
In the image there are two components of the same type (lets call them a Panel) in which content can be collapsed and expanded. Ideally a Panel would have a Header Component, a Progress Bar Component, and Content(i.e radio buttons, text, etc). When collapsed, I would like the "progress bar" to turn green. I've started with the following code snippet to create a progress bar, though it is very rough (some of the code in there will be placed in other components and is there for testing).. I am new to react so any insight or direction would be appreciated!
import React, { Component } from 'react';
import './styles.css';
export default class IconProgressBar extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
return (
<div className="row">
<div className="progress-bar">
<span className="progress-line"></span>
<span className="progress-icon"></span>
</div>
<div className="step-container">
<div className="step-header">
<span className="col s6"><h3>Header 1</h3></span>
<span className="col s6 text-right step-summary">
<button className="secondary right edit-button">Edit</button>
<span className="current-value right"> . </span>
</span>
</div>
<div className="step-body">
</div>
</div>
</div>
);
}
}
Edit: In any answers I'm not super concerned about styling (that can be worked out later) i.e a Circle with a line under it in a collapsible & stackable element would suffice :)

I have implemented a majority of your functionality, except the binding and some of the styling. You will just have to finish up the styling and add your icons and callbacks to record user actions.
The idea is simple in this case, you have a list of panels which contain a header and a bunch of options to go with each. First, you can simply render the elements and then within your new ProgressBar component, maintain the state of the bar i.e. click to toggle and changing the styles of the bar on the left. Let me know if you have any further questions.
For the sake of simplicity, I have kept everything in a single component, but you might want to change that in case you want to isolate and reuse sub components.
https://react-2nhcbe.stackblitz.io

Related

How to create button which adds new Vue-Grid-Item?

I am creating a program for my Universities Research department, the program is for the operation of an Atomic Layer Deposition system.
The program needs to be able to allow the user to set a custom 'recipe' if you will, each grid-item will have a button with 'edit' in the bottom corner, and will take you to a separate page where you can enter your system stats like zone temps, durations, cycles, etc. We have gotten the draggable grid-items working, so that we could make the system run multiple steps over and over if we wish, but here is my goal I can't seem to accomplish:
We need to be able to add a new 'step' grid-item on button click, and we need to be able to remove a grid-item as well. I have created a button 'New Tile' and I defined a function I was hoping would work, I was trying to see if I could duplicate a grid item, but when I run the program and click the button I get the error:
"[Vue warn]: Property or method "duplicate" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties."
Image of app: https://imgur.com/a/DgKebPR
image of JS trying to be used: https://imgur.com/a/EjW4t6d
<h2 style="color: #f6a821;">Steps</h2>
<hr class="hr" />
<grid-layout
:layout.sync="stepsGrid"
:col-num="8"
:row-height="75"
:is-draggable="true"
:is-resizable="false"
:is-mirrored="false"
:vertical-compact="true"
:margin="[50, 50]"
:use-css-transforms="true">
<div id="duplicater">
<grid-item
:x=stepsGrid[0].x
:y=stepsGrid[0].y
:w=stepsGrid[0].w
:h=stepsGrid[0].h
:i=stepsGrid[0].i
:isDraggable=stepsGrid[0].isDraggable>
<div class="Panel__name">1</div>
<div class="editButton">
<router-link to="/Parameters-template" class="editButton">Edit</router-link></router-link>
</div><br>
<div class="Panel__status">Status:</div>
</grid-item>
<div id="bottombuttons">
<button id="resetbutton">Reset</button>
<button id="startbutton" #click="duplicate()">New Tile</button>
</div>
</div>
I don't get where is declared the duplicate method extactly. Don't expect it to be available from a template if it's not declared in the component's methods. Try:
methods: {
duplicate() {
/* */
}
}
in the same component. If it needs to be a shared among several components, put this in a mixin.

Render one component several times in different html pages with different text

I'm new to react and I'm trying to render one component in different html files (because I'm working in an existing project), each of them with different text.
I'm thinking of something like this:
class ctaSection extends React.Component{
render(){
return(
<div className="cta-section">
<div className="md:w-9c">
<h5 className="uppercase">{this.props.h5}</h5>
<h3>{this.props.h3}</h3>
</div>
<div className="cta-button">
<a href="#">
<button className="w-full">{this.props.button}</button>
</a>
</div>
</div>
);
}
}
export default ctaSection;
Then, in my index.js, I'm rendering like this, passing the props:
let ctaPage1 = document.getElementById('cta-section-page-1');
let ctaPage2 = document.getElementById('cta-section-page-2');
ReactDOM.render(<CtaSection h3='my text for page 1' h5='my h5 for page 1' button='hello'/>, ctaPage1);
ReactDOM.render(<CtaSection h3='text for page 2' h5='something' button='click me'/>, ctaPage2);
I'm not sure if this is the best and simpler way to do this, because I'm calling ReactDOM.render twice for same component, and I got this error:
Uncaught Invariant Violation: Target container is not a DOM element.
This works fine if I render the component once, but not for multiple instances.
What is the best way to do it?
I've thought about this more, and I'm not experienced with adding React to existing websites, but here's what I'd suggest:
I would have 1 JS file per HTML page that imports CtaSection, each of those files would look like such:
// page1.js
import CtaSection from '../CtaSection'; // or wherever it is
let ctaPage = document.getElementById('cta-section-page');
ReactDOM.render(<CtaSection h3='my text for page 1' h5='my h5 for page 1' button='hello'/>, ctaPage);
You would just need to make sure each html page uses the corresponding JS file.
// page1.html
<body>
<div id="cta-section-page"></div>
<script src="page1.js"></script>
</body>
Repeat for each page.

Javascript Onclick=window.open() function will open a new page every time I refresh the page?

So I have a DIV element that, when pressed, I want to open a new tab in a different window. The only problem is, whenever the page is refreshed or any other div element is pressed, th function is initiated as well and opens a page in another window. I'll include my code below, but I'm not sure why this is happening seeing as how I'm using onClick={window.open("https://www.thechinesewriter.com") Like I said, I only want a new tab to open when the div is pressed, not when any other items on the page are clicked or even when the page itself is refreshed.
import React from "react";
import "./Column1.css";
class Column1 extends React.Component {
render() {
return(
<React.Fragment>
<div className="rectImage">
<img className="imagePost" src={this.props.image} />
</div>
<div onClick={window.open("https://www.thechinesewriter.com")} className="downloadBut1">
<h2>
Source
</h2>
</div>
<div className="downloadBut2">
<h2>
Repository
</h2>
</div>
</React.Fragment>
)
}
}
export default Column1;
You need to call the function as a callback like this.
<div onClick={() => window.open("https://www.thechinesewriter.com")} className="downloadBut1">
Otherwise this gets called every time the component gets rendered.
You use an expression, which will execute everytime the component is rendered.
<div onClick={window.open("https://www.thechinesewriter.com")} className="downloadBut1">
You probably mean to use a function
<div onClick={() => window.open("https://www.thechinesewriter.com")} className="downloadBut1">

Can you have more than one SVG on a page? (using svg-react-loader)

I'm trying to import and display multiple SVGs in the same component, but it's actually just showing the first one duplicated every time, instead of two individual SVGs. Here is my code:
import React, { Component } from 'react';
import Account from '-!svg-react-loader!./svg/Account.svg';
import Alert from '-!svg-react-loader!./svg/Alert.svg';
<div className="col-lg-1">
<Account className="icon" />
</div>
<div className="col-lg-1">
<Alert className="icon" />
</div>
Can we only have one instance of an SVG per page?
For anyone reading this. It appears Sketch was saving the SVGs out with the same id - "#path-1", which was breaking when there were multiple on the page. So, the answer is they need a unique ID.

React.js - Creating Simple Accordion example

I'm relevantly new to React and I am having trouble on how to tackle this logic:
Essentially I am creating a table using flexbox, and I also want it so that when you click on one of the rows, it expands and reveals another row (for example, it will give a small description what it is about).
So far what I have is just the table.
class Application extends React.Component {
render() {
const renderDataRows = (
[
<div key={0} className='row'>
<div className='cell description'> Mortage Bill
</div>
<div className='cell amount'>$0,000,000</div>
<div className='cell amount'>$2.50</div>
<div className='cell amount'v>000%</div>
</div>,
<div key={1} className='row'>
<div className='cell description'> Electric Bill
</div>
<div className='cell amount'>$0,000,000</div>
<div className='cell amount'>$2.50</div>
<div className='cell amount'v>000%</div>
</div>,
]
)
const containerTable = (
<div className='table-container'>
{renderDataRows}
</div>
)
return (
<div>
{containerTable}
</div>
)
}
}
More specifically, what would be the best way to structure the hidden rows? Create as a child of the cells, or siblings?
I am assuming I will need state to keep in track what is current open, etc?
I've attached Codepen link to mess around
This can be done in the following way:
Let all the cells be in a single parent div and let the cell description be another sibling div (although using would be better). Put a class on the sibling div such as hidden. Not add a click handler on the cells div. Whenever this div is clicked, update the state with that div's id/key. Now use this to set the hidden class to the other divs. Compare this.state.key with the current id/key and show or hide accordingly. I am not giving the specific code.
Note: Instead of storing the divs in the renderDataRows, just put the data in it and map over it to create all the divs. That way you can easily manipulate the hidden class and any other variation in a single place without having to update it separately for each row of data.

Categories

Resources