Getting "RangeError: Maximum call stack size exceeded" in ReactJS - javascript

I am a beginner at ReactJs.
And I have RangeError to run this code.
I have tried to solve this problem myself, but I couldn't do.
After a lot of testing, I just knew we had errors in this file.
Here is my code in the file.
import React from 'react'
import cookie from 'react-cookie';
import { connect } from 'react-redux';
import { fetchPieData, resetPieData } from '../actions/panel.js';
import PieChart from '../components/PieChart';
import { getCookieDomain } from '../utils/domain';
import PendingOverlay from '../components/PendingOverlay';
import cookiefetch from '../utils/userutils';
import {
companyDropdown as companyDropdownAction,
getCompaniesDropdown,
getCompany
} from '../actions/companies.js';
import {
getFileDropdown,
fileDropdown as fileDropdownAction,
fileSearchDropdown as fileSearchDropdownAction
} from '../actions/files.js';
const cookieDomain = getCookieDomain();
import {
toggleExpiringModal
} from '../actions/ui.js';
import {
checkdatediff
} from '../utils/numbers.js';
import '../assets/library.less'
class Panel extends React.Component {
constructor(props) {
super(props);
this.state = {
fileDropdownTitle: 'FILE',
setFileByCookie: true
};
}
componentWillMount() {
const { dispatch } = this.props;
var roleCookie = cookie.load('role');
roleCookie = roleCookie.toLowerCase();
const accountId = cookiefetch('accountId','');
var accid = accountId.toLowerCase();
const overrideCompany = cookiefetch('overrideCompany', '');
if(overrideCompany != '') {
var title = "FILE ("+overrideCompany+")";
this.setState({fileDropdownTitle: title});
} else {
this.setState({fileDropdownTitle: 'FILE'});
}
var roleCookie = roleCookie.toLowerCase();
if (roleCookie == 'administrator' || roleCookie == "adminread") {
dispatch(getCompaniesDropdown());
} else {
dispatch(getCompany(accid));
dispatch(getFileDropdown(accid));
//dispatch(companyDropdownAction(false, accid, accid));
}
}
componentDidUpdate(nextProps, nextState) {
const { dispatch } = this.props;
const { selectedCompany } = this.props.companies;
const { selectedValue } = this.props.companies.companyDropdown;
const nextSelectedValue = nextProps.companies.companyDropdown.selectedValue;
const nextSelectedDisplay = nextProps.companies.companyDropdown.selectedDisplay;
const fileDropdown = this.props.files.fileDropdown;
const nextFileDropdown = nextProps.files.fileDropdown;
const cookieDomain = getCookieDomain();
if (selectedValue == "" && selectedValue != nextSelectedValue) {
cookie.save('selectedCompany', {selectedDisplay: nextSelectedDisplay, selectedValue: nextSelectedValue, Petstore: nextProps.companies.selectedCompany.activePetstore2}, {domain: cookieDomain});
cookie.save('selectedFile', {selectedDisplay: "Select a FILE", selectedValue: ""}, {domain: cookieDomain});
dispatch(getFileDropdown(nextSelectedValue));
dispatch(fileSearchDropdownAction(false, "Select a FILE", "", ""))
} else if(typeof nextSelectedValue == 'string' && selectedValue != nextSelectedValue) {
cookie.save('selectedCompany', {selectedDisplay: nextSelectedDisplay, selectedValue: nextSelectedValue, Petstore: nextProps.companies.selectedCompany.activePetstore2}, {domain: cookieDomain});
cookie.save('selectedFile', {selectedDisplay: "Select a FILE", selectedValue: ""}, {domain: cookieDomain});
//dispatch(resetPieData());
dispatch(getFileDropdown(nextSelectedValue));
dispatch(fileDropdownAction(false, "Select a FILE", "", ""))
}
else if(nextState.setFileByCookie && typeof nextProps.companies.selectedCompany != 'undefined') {
var nextCompany = nextProps.companies.selectedCompany;
var companyOptions = {isActivePetstore: nextCompany.activePetstore, activePetstore2: nextCompany.activePetstore2,
isActiveGeneral: true, isActivePoc: nextCompany.activePoc, isActiveFormat: nextCompany.activeFormat,
isActiveSiteId: nextCompany.activeSiteId,
subAssembly: nextCompany.subAssembly};
if (nextFileDropdown.selectedDisplay == "List") {
dispatch(fetchPieData(nextFileDropdown.selectedValue, true, companyOptions));
} else if (nextFileDropdown.selectedValue != ""){
dispatch(fetchPieData(nextFileDropdown.selectedValue, false, companyOptions));
}
}
else if (nextFileDropdown.selectedValue != "" && fileDropdown.selectedValue != nextFileDropdown.selectedValue ) {
cookie.save('selectedFile', {selectedDisplay: nextFileDropdown.selectedDisplay, selectedValue: nextFileDropdown.selectedValue}, {domain: cookieDomain});
var companyOptions = {isActiveGeneral: true,isActivePetstore: selectedCompany.activePetstore, activePetstore2: selectedCompany.activePetstore,
isActiveGeneral: selectedCompany.activeGeneral, isActivePoc: selectedCompany.activePoc, isActiveFormat: selectedCompany.activeFormat,
isActiveSiteId: selectedCompany.activeSiteId,
subAssembly: selectedCompany.subAssembly};
if (nextFileDropdown.selectedDisplay == "List") {
dispatch(fetchPieData(nextFileDropdown.selectedValue, true, companyOptions));
} else {
dispatch(fetchPieData(nextFileDropdown.selectedValue, false, companyOptions));
}
}
}
toggleExpiringModal() {
const { dispatch, ui } = this.props;
if (ui.toggleExpiringModal) {
dispatch(toggleExpiringModal(false));
cookie.remove('didLogin', {domain: getCookieDomain()});
}
}
render () {
var companyDropdownComponent = null;
var filesDropdownComponent = null;
var dataType;
var expirationModal = null;
var expirationDate, daysAway, didLogin;
const { ui, companies } = this.props;
const customStyles = {
content : {
top : '40%',
left : '50%',
right : 'auto',
bottom : 'auto',
transform : 'translate(-50%, -50%)',
overflowY : 'hidden',
padding : '20px 20px 30px'
}
};
const isActivePetstore = cookiefetch('isActivePetstore', false);
const roleCookie = cookiefetch('role');
var role = roleCookie.toLowerCase();
const accountId = cookiefetch('accountId', '');
var accid = accountId.toLowerCase();
const overrideCompany = cookiefetch('overrideCompany','');
const { companiesDropdownData, companyDropdown, selectedCompany } = this.props.companies;
const { fileDropdown, filesDropdownData } = this.props.files;
const { pieData } = this.props.panel;
const { table } = this.props.data;
var companyOptions = null;
if (fileDropdown.selectedDisplay == "List") {
dataType = "masterList";
} else {
dataType = "file";
}
if ((role == "administrator" || role == 'adminread') && overrideCompany == '') {
companyDropdownComponent = (
<Dropdown
errorMessage='Please select a company'
error={false}
title="Company"
open={companyDropdown.display}
selectedDisplay={companyDropdown.selectedDisplay}
selectedValue={companyDropdown.selectedValue}
options={companiesDropdownData}
disabled="edit"
onClickAction={companyDropdownAction}
/>
);
}
if (companyDropdown.selectedValue != "") {
filesDropdownComponent = (
<DropdownFiles
errorMessage='Please select a FILE'
error={false}
title={this.state.fileDropdownTitle}
open={fileDropdown.display}
selectedDisplay={fileDropdown.selectedDisplay}
selectedValue={fileDropdown.selectedValue}
options={filesDropdownData}
disabled="edit"
onClickAction={fileDropdownAction}
/>
);
}
if (typeof selectedCompany != 'undefined') {
companyOptions = {isActivePetstore: selectedCompany.activePetstore, activePetstore2: selectedCompany.activePetstore,
isActiveGeneral: true, isActivePoc: true, isActiveFormat: selectedCompany.activeFormat,
isActiveSiteId: selectedCompany.activeSiteId,
subAssembly: selectedCompany.subAssembly};
}
for(var i = 0; i < companies.companies.length; i++) {
if (accountId === companies.companies[i].accountId) {
var dateInMiliseconds = companies.companies[i].expirationDate;
expirationDate = new Date(dateInMiliseconds);
expirationDate = companies.companies[i].expirationDate;
}
}
{ expirationDate != undefined ? daysAway = checkdatediff(expirationDate) : null }
{expirationDate != undefined ? didLogin = cookie.load('didLogin') : null }
if (daysAway < 1 && ui.toggleExpiringModal == true && didLogin) {
expirationModal = (
<Modal
isOpen={ui.toggleExpiringModal}
shouldCloseOnOverlayClick={true}
style={customStyles}
contentLabel="Modal"
>
<div className="custom-modal">
<div className="header-center">Notice</div>
<div className="content">
<p>test</p>
<p>test in <span id="days">{daysAway}</span> days.</p>
<p>test.</p>
</div>
<div className="buttons">
<div className="close" onClick={() => this.toggleExpiringModal()}>Ok</div>
</div>
</div>
</Modal>
);
}
return (
<div id="panel">
{ !isActivePetstore ? <Notification>test</Notification> : null }
{companyDropdownComponent}
{filesDropdownComponent}
<IconLink to="/files" title="Link to Files" type="table"/>
{ pieData != "empty" && pieData != "pending" && fileDropdown.selectedValue != "" ? <PieChart data={pieData} dataType={dataType} table={table} companyOptions={companyOptions}/> : null }
{ pieData != "empty" && pieData == "pending" ? <PendingOverlay/> : null }
{expirationModal}
</div>
)
}
}
function select(state) {
return {
companies: state.companies,
files: state.files,
createFile: state.createFile,
masterList: state.masterList,
panel: state.panel,
data: state.data,
ui: state.ui
}
}
export default connect(select)(Panel);
After running we have above error.

Related

Wrong input validation

I want to validate all of my inputs in react
My validation code looks like this:
let isValid = {
name: false,
address: false,
postcode: false,
phone: false,
email: false
};
const validateInput = (e) => {
let currentInput = e.target
if (currentInput.name === 'name') {
if (currentInput.value !== 'undefined' && currentInput.value.match(/^[a-zA-Z]+$/)) {
isValid.name = true;
} else {
isValid.name = false;
}
}
if (currentInput.name === 'address') {
if (currentInput.value !== 'undefined') {
isValid.address = true;
} else {
isValid.address = false;
}
}
if (currentInput.name === 'postcode') {
if (currentInput.value !== undefined && currentInput.value.match(/^[0-9]+[-]+[0-9]+$/) && currentInput.value.length > 4) {
isValid.postcode = true;
} else {
isValid.postcode = false;
}
}
if (currentInput.name === 'phone') {
if (currentInput.value !== 'undefined' && currentInput.value.match(/^[0-9]+$/) && currentInput.value.length > 7) {
isValid.phone = true;
} else {
isValid.phone = false;
}
}
if (currentInput.name === 'email') {
if (currentInput.value !== 'undefined' && currentInput.value.match(/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)) {
isValid.email = true;
} else {
isValid.email = false;
}
}
console.log(isValid)
}
For example when i type correct value in "Name" isValid.name gets value true, then when i write somethink in "address" isValid.address gets true, but isValid.name false
How to fix it?
{requiredInformations.map((el) => (
<>
<Label>{el.label}</Label>
<Input type={el.type} name={el.name} required onChange={(e) => { getInputValue(e); validateInput(e) }} />
</>
))}
I suggest you try to use react-joi library for validation React-Joi-Validation
Its easy and simple to use, and you can achieve what you are trying here in your code by just reading the first page on their npm package main page.
You need to get yourself familiar with terms like "state"
, "props", "component lifecycle", etc. Build a simple component using a guide on youtube, you can find plenty of them.
Meanwhile, here is a simple component that validates inputs:
function App() {
const [name, setName] = React.useState('');
const [address, setAddress] = React.useState('');
const isValid = React.useMemo(() => {
const result = {
name: false,
address: false,
};
if (name.match(/^[a-zA-Z]+$/)) {
result.name = true;
} else {
result.name = false;
}
if (address !== '') {
result.address = true;
} else {
result.address = false;
}
return result;
}, [name, address]);
return (
<div>
<input
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
{isValid.name ? <p>Name is valid</p> : <p>Name is invalid</p>}
<br />
<input
placeholder="Address"
value={address}
onChange={(e) => setAddress(e.target.value)}
/>
{isValid.address ? <p>Adress is valid</p> : <p>Adress is invalid</p>}
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root">
</div>

How to trigger event when timer count downs to 0

I have a parent component which has timer component inside it. Timer starts at 15 minutes and count downs till 0. When my timer shows time as 0 I want to trigger a submit button event, submit button is inside Quiz Component (Quiz Component is also a child component of Parent Component). I found probably I can use MutationObserver when p tag changes. I am not sure whether it's the correct and only approach or there is better way to achieve this.
Parent Component:
import React, { Component } from 'react';
import '../css/App.css'
import Quiz from './Quiz';
import Timer from './Timer';
import { connect } from 'react-redux';
import { ActionTypes } from '../redux/constants/actionTypes';
import { saveQuizAll, getQuizIndex } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onQuizLoad: payload => dispatch({ type: ActionTypes.QuizLoad, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class QuizContainer extends Component {
state = {
quizes: [
{ id: 'data/class1.json', name: 'Class 1' },
{ id: 'data/class2.json', name: 'Class 2' },
{ id: 'data/class3.json', name: 'Class 3' },
{ id: 'data/class4.json', name: 'Class 4' },
],
quizId: 'data/class1.json'
};
pager = {
index: 0,
size: 1,
count: 1
}
componentDidMount() {
console.log('componentDidMount');
this.load(this.state.quizId);
}
load(quizId, isValReload) {
console.log('In load');
let url = quizId || this.props.quizId;
if (isValReload) {
let quiz = this.props.quizAll.find(a => url.indexOf(`${a.id}.`) !== -1);
console.log('In load quiz : ', quiz);
this.pager.count = quiz.questions.length / this.pager.size;
this.props.onQuizLoad(quiz);
this.props.onPagerUpdate(this.pager);
}
else {
fetch(`../${url}`).then(res => res.json()).then(res => {
let quiz = res;
quiz.questions.forEach(q => {
q.options.forEach(o => o.selected = false);
});
quiz.config = Object.assign(this.props.quiz.config || {}, quiz.config);
this.pager.count = quiz.questions.length / this.pager.size;
this.props.onQuizLoad(quiz);
this.props.onPagerUpdate(this.pager);
});
}
}
//This event implements restriction to change class without finishing curretnly selectd class
onClassClick = (e) => {
let qus = this.props.quiz.questions;
// console.log(qus);
let isNotAllAns = qus.some((q, i) => {
var isNot = false;
if (q.answerType.id !== 3 && q.answerType.id !== 4) {
isNot = (q.options.find((o) => o.selected === true)) === undefined;
}
else {
// console.log('q', q);
isNot = ((q.answers === "" || q.answers.length === 0));
}
return isNot;
});
if (isNotAllAns) {
alert('Please complete the quiz.');
e.stopPropagation();
}
}
/*
saveQuizAll(_quizAll, _quiz) {
let allQuiz = [];
// , _quizAll, _quiz;
// if (true) {
// _quiz = this.quiz;
// _quizAll = this.quizAll;
// }
console.log(this, _quiz, _quizAll);
if (_quiz.questions.length !== 0) {
if (_quizAll.length !== undefined) {
console.log('Not Initial Setup Splice', _quiz.id);
allQuiz = _quizAll;
const qIndex = this.getQuizIndex(_quiz.id.toString());
if (qIndex > -1) {
allQuiz.splice(qIndex, 1, _quiz);
}
else {
allQuiz.splice(_quizAll.length, 0, _quiz);
// allQuiz.splice(this.props.quizAll.length-1, 0, this.props.quizAll, this.props.quiz);
}
}
else {
allQuiz[0] = _quiz;
}
return allQuiz;
// if (true) {
// this.onQuizChange(allQuiz);
// }
}
}
*/
onChange = (e) => {
// console.log(this.props.quizAll, this.props.quizAll.length);
let allQuiz = [];
allQuiz = saveQuizAll(this.props.quizAll, this.props.quiz);
//below code converted into saveQuizAll funstion
/*
if (this.props.quizAll.length !== undefined) {
console.log('Not Initial Setup Splice', this.props.quiz.id);
allQuiz = this.props.quizAll;
const qIndex = this.getQuizIndex(this.props.quiz.id.toString());
if (qIndex > -1) {
allQuiz.splice(qIndex, 1, this.props.quiz);
}
else {
allQuiz.splice(this.props.quizAll.length, 0, this.props.quiz);
// allQuiz.splice(this.props.quizAll.length-1, 0, this.props.quizAll, this.props.quiz);
}
}
else {
allQuiz[0] = this.props.quiz;
}
*/
// console.log('allQuiz Out - ', allQuiz);
this.props.onQuizChange(allQuiz);
console.log('Check QuizAll - ', this.props.quizAll);
const aQuiz = JSON.parse(JSON.stringify(this.props.quizAll));
this.setState({ quizId: e.target.value });
if (aQuiz.length !== undefined && getQuizIndex(this.props.quizAll, e.target.value) > -1) {
// console.log(aQuiz.findIndex(a => e.target.value.indexOf(`${a.id}.`) !== -1));
this.load(e.target.value, true);
}
else {
this.setState({ quizId: e.target.value });
this.load(e.target.value, false);
}
}
// getQuizIndex(qID) {
// return this.props.quizAll.findIndex(a => (qID.indexOf(`${a.id}.`) !== -1 || qID.indexOf(`${a.id}`) !== -1));
// }
render() {
return (
<div className="container">
<header className="p-2">
<div className="row">
<div className="col-6">
<h3>DADt Application</h3>
</div>
<div className="col-6 text-right">
<label className="mr-1">Select Quiz:</label>
<select onChange={this.onChange} onClick={this.onClassClick}>
{this.state.quizes.map(q => <option key={q.id} value={q.id}>{q.name}</option>)}
</select>
</div>
</div>
</header>
<Timer duration={900}/>
<Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} />
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(QuizContainer);
Here is my Timer Component
import React, { Component } from 'react'
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 0
};
}
tick() {
this.setState((prevState) => ({
seconds: prevState.seconds + 1
}));
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const { duration } = this.props;
let timeLeft = duration - this.state.seconds;
timeLeft = Number(timeLeft);
let minutes = Math.floor(timeLeft % 3600 / 60);
let seconds = Math.floor(timeLeft % 3600 % 60);
let minutesDisplay = minutes > 0 ? minutes + (minutes === 1 ? " : " : " : ") : "";
let secondsDisplay = seconds > 0 ? seconds + (seconds === 1 ? "" : "") : "";
return <p className="badge badge-success">Time Left: {minutesDisplay}{secondsDisplay}</p>;
}
}
export default Timer;
Quiz Component:
import React, { Component } from 'react';
import { ActionTypes } from '../redux/constants/actionTypes';
import Review from './Review';
import Questions from './Questions';
import Result from './Result';
import { connect } from 'react-redux';
// import { saveQuizAll } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.mode, ...state.pager, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onSubmit: payload => dispatch({ type: ActionTypes.QuizSubmit, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class Quiz extends Component {
move = (e) => {
let id = e.target.id;
let index = 0;
if (id === 'first')
index = 0;
else if (id === 'prev')
index = this.props.pager.index - 1;
else if (id === 'next') {
index = this.props.pager.index + 1;
}
else if (id === 'last')
index = this.props.pager.count - 1;
else
index = parseInt(e.target.id, 10);
if (index >= 0 && index < this.props.pager.count) {
let pager = {
index: index,
size: 1,
count: this.props.pager.count
};
this.props.onPagerUpdate(pager);
}
}
saveStore(e) {
let allQuiz = [];
console.log(this, e);
allQuiz = this.props.saveAll(e.props.quizAll, e.props.quiz);
console.log(allQuiz);
this.props.onQuizChange(allQuiz);
}
setMode = (e) => this.props.onSubmit(e.target.id);
// setMode(e) {
// console.log('in mode',e);this.props.onSubmit(e.target.id);
// }
renderMode() {
console.log('Inside here', this.props.mode);
if (this.props.mode === 'quiz') {
return (<Questions move={this.move} />)
} else if (this.props.mode === 'review') {
return (<Review quiz={this.props.quiz} move={this.move} />)
} else {
console.log('Before Results');
const divSel = document.querySelector('div.col-6.text-right');
// console.log('divSel', divSel);
if (divSel) {
divSel.style.display = "none";
}
return (<Result questions={this.props.quizAll || []} />)
}
}
render() {
return (
<div>
{this.renderMode()}
{(this.props.mode !== 'submit') &&
<div>
<hr />
<button id="quiz" className="btn btn-primary" onClick={this.setMode}>Quiz</button>
<button id="review" className="btn btn-primary" onClick={this.setMode}>Review</button>
<button id="submit" className="btn btn-primary" onClick={(e) => {this.setMode(e); this.saveStore(this)}}>Submit Quiz</button >
</div >}
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Quiz);
I think you can have two approaches.
1. The "react" way
In the Parent component:
// ...
constructor(props) {
// ...
this.state = {
timeExpired: false
};
}
const onTimeExpired = () => {
this.setState({timeExpired: true});
}
// ...
render() {
return (
<div className="container">
{ // ... }
<Timer duration={900} onTimeExpired={onTimeExpired}/>
<Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} triggerSubmit={this.state.timeExpired} />
</div>
);
}
In the Timer component:
// ...
componentDidUpdate() {
if (this.state.seconds === this.props.duration) {
this.props.onTimeExpired();
}
}
// ...
In the Quiz component:
// ...
componentDidUpdate() {
if (this.props.triggerSubmit) {
// Do whatever you do on submit
}
}
// ...
2. The "quick and dirty" way:
In the Timer component
// ...
componentDidUpdate() {
if (this.state.seconds === this.props.duration) {
const quizForm = document.getElementById('quizFormId');
quizForm && quizForm.submit();
}
}
// ...
Provide a prop method onTimeFinished in your Timer component. Then in your render function you can add
{ !(this.props.duration-this.state.seconds) && this.props.onTimeFinished() }
Reference: React Conditional Rendering
try this:
Parent Component:
// state
state = {
triggerSubmit: false
}
// functions
doSubmit = () => {
this.setState({ triggerSubmit: true });
}
resetSubmit = () => {
this.setState({ triggerSubmit: false });
}
// jsx
<Timer duration={900} doSubmit={this.doSubmit} />
<Quiz
quiz={this.state.quiz}
quizId={this.state.quizId}
saveAll={saveQuizAll}
mode={this.state.mode}
resetSubmit={this.resetSubmit}
triggerSubmit={this.state.triggerSubmit} />
Timer Component:
// function
doSubmit = (timeLeft) => {
if (timeLeft === 0) {
this.props.doSubmit();
}
}
// jsx
<p className="badge badge-success"
onChange={() => {this.doSubmit(timeLeft)}>
Time Left: {minutesDisplay}{secondsDisplay}
</p>
Quiz Component:
// state
state = {
triggerSubmit: this.props.triggerSubmit
}
// function
triggerSubmit = () => {
if (this.state.triggerSubmit) {
your trigger submit code here...
this.props.resetSubmit();
}
}

Onclick method in React is effecting every list item in a table, should only affect the one which is clicked

I have a tsx file which creates a table of comments. When the page is rendered, an array of information representing comments is gathered. A Set containing the indexes of the comments in the array, which is part of the state, determines whether a link under the comment reads 'show more' or 'show less'. Once that link is clicked, the index of the comment is added to the Set, and the state is updated with the addition of that index to the Set, if the Set contains the index of a comment when the state is updated, it should read 'show less'. The problem is when I click that link, it changes the link of each list element in the table, not just one.
import * as React from "react";
import { LocalizationInfo } from "emt-localization";
import { DateHandler } from "../handlers/date-handler";
import { UserIcon } from "./user-icon";
import { OnDownloadDocument } from "../models/generic-types";
import { getUserString } from "../models/user";
import { ClaimAction, ActionDetails, ReasonActionDetails, CommentDetails, DocumentDetails } from "../models/action";
const stateChangeActions = new Set<string>([
'Dispute',
'Rejection',
'SetUnderReview',
'Approval',
'Recall',
'Submission',
'RequestPartnerAction'
]);
const fiveMinutes = 5 * 60 * 1000;
const underscoreRegex = /_[^_]*_/g;
const actionTypeClassMap: {[actionType: string]: string} = {
'Submission': 'success',
'RequestPartnerAction': 'warn',
'Rejection': 'warn',
'Approval': 'success',
'Recall': 'warn',
'Dispute': 'warn',
'SetUnderReview': 'info',
'CustomerConsentDeclined': 'rejected'
};
const maxShortLength = 100;
interface ActionsProps {
readonly localization: LocalizationInfo;
readonly actions: ClaimAction[];
readonly onDownloadDocument: OnDownloadDocument;
readonly isInternalFacing: boolean;
readonly isHistoryPaneDisplay: boolean;
}
class ActionsState {
readonly expandedComments = new Set<number>();
}
export class Actions extends React.Component<ActionsProps, ActionsState> {
constructor(props: ActionsProps) {
super(props);
this.state = new ActionsState();
}
render():JSX.Element {
const loc = this.props.localization;
const isInternalFacing = this.props.isInternalFacing;
const toTime = (action:ClaimAction) => new Date(action.timeStamp).getTime();
const sortBy = (a:ClaimAction, b:ClaimAction) => toTime(b) - toTime(a);
const actions = this.props.actions.filter(action => {
if (isDocumentDetails(action.details)) {
if (action.actionType == 'DocumentSubmission' && action.details.documentType == 'Invoice') {
return false;
}
}
return true;
});
actions.sort(sortBy);
const grouped = groupActions(actions);
return (
<ul className={`claim-actions ${this.props.isHistoryPaneDisplay ? '' : 'user-comment-box'}`}>
{grouped.map((actions, index) => {
let actionClass = '';
actions.forEach(action => {
actionClass = actionClass || actionTypeClassMap[action.actionType];
});
const first = actions[0];
const icon = actionClass == 'success' ?
sequenceIcon('complete') :
actionClass == 'warn' ?
sequenceIcon('action-required') :
actionClass == 'rejected' ?
sequenceIcon('rejected') :
actionClass == 'info' ?
sequenceIcon('editing') :
<UserIcon
user={first.user}
isInternalFacing={isInternalFacing}
/>;
const elements = actions.map((action, actionIndex) => this.renderAction(action, actionIndex));
return (
<li className={actionClass} key={index}>
{icon}
<div className="win-color-fg-secondary">
<span className="claim-action-name win-color-fg-primary">
{ getUserString(first.user, isInternalFacing) }
</span>
<span className="text-caption">
{loc.piece("HistoryItemTitle", 0)}
{DateHandler.friendlyDate(first.timeStamp, true)}
</span>
</div>
{elements}
</li>
)
})}
</ul>
)
}
private renderAction(action:ClaimAction, actionIndex:number):JSX.Element|null {
const strings = this.props.localization.strings;
if (action.actionType == 'AddComments' || action.actionType == 'AddInternalComments') {
return this.renderComment((action.details as CommentDetails).comments, actionIndex);
}
const document = isDocumentDetails(action.details) ? action.details : null;
const documentLink = document ?
(key:number) =>
<a
key={key}
onClick={() => this.props.onDownloadDocument(document.documentId, document.name)}>
{document.name}
</a>
: null;
const locKey = `History_${action.actionType}`;
const localizedFlat = strings[locKey] || "";
const localized = replaceUnderscores(localizedFlat, documentLink);
const reason = (action.actionType === 'RequestPartnerAction' || action.actionType === 'Rejection') && action.details ? (action.details as ReasonActionDetails).reasonCode : '';
const reasonString = reason.charAt(0).toUpperCase() + reason.slice(1)
if (localized) {
return (
<div key={actionIndex}>
<div className="claim-action">
<span className="text-caption">{localized}</span>
</div>
<div className="claim-action">
{ reasonString && <span className="text-caption"><strong>{strings['ReasonLabel']}</strong>{` ${strings[reasonString]}`}</span> }
</div>
</div>
);
}
console.error(`Unknown action type ${action.actionType}`);
return null;
}
private renderComment(comment: string, actionIndex: number): JSX.Element {
const strings = this.props.localization.strings;
const canShorten = comment.length > maxShortLength;
const shouldShorten = canShorten && !this.state.expandedComments.has(actionIndex);
const shortened = shouldShorten ?
comment.substring(0, maxShortLength) + "\u2026" :
comment;
const paragraphs = shortened
.split('\n')
.map(s => s.trim())
.filter(s => s);
const elements = paragraphs.map((comment, i) =>
<div className="claim-comment" key={i}>
{comment}
</div>
);
const toggle = () => {
const next = new Set<number>(this.state.expandedComments);
if (next.has(actionIndex)) {
next.delete(actionIndex)
}
else {
next.add(actionIndex);
}
this.setState({ expandedComments: next });
}
const makeLink = (locKey:string) =>
<a
onClick={toggle}>{strings[locKey]}</a>;
const afterLink = canShorten ?
shouldShorten ?
makeLink('ShowMore') :
makeLink('ShowLess') :
null;
return (
<React.Fragment key={actionIndex}>
{elements}
{afterLink}
</React.Fragment>
);
}
}
// Function groups actions together under some conditions
function groupActions(actions:ClaimAction[]):ClaimAction[][] {
const grouped:ClaimAction[][] = [];
actions.forEach(action => {
if (grouped.length) {
const lastGroup = grouped[grouped.length - 1];
const timeDifference = new Date(lastGroup[0].timeStamp).getTime() - new Date(action.timeStamp).getTime();
if (stateChangeActions.has(lastGroup[0].actionType) && action.actionType == 'AddComments' && timeDifference < fiveMinutes) {
lastGroup.push(action);
return;
}
}
grouped.push([action]);
});
return grouped;
}
function isDocumentDetails(details:ActionDetails|null): details is DocumentDetails {
return !!details && (details.$concreteClass == 'InvoiceActionDetails' || details.$concreteClass == 'DocumentActionDetails');
}
function sequenceIcon(className: string):JSX.Element {
return (
<div className="sequence sequence-status claims-icon">
<div className={`step ${className}`} />
</div>
);
}
function replaceUnderscores(str: string, documentLink: ((k:number)=>JSX.Element)|null, startKey: number=0):JSX.Element[] {
if (!str) {
return [];
}
const match = underscoreRegex.exec(str);
if (!match) {
return replaceDocumentLink(str, documentLink, startKey);
}
const firstText = str.substring(0, match.index);
const middleText = match[0].substring(1, match[0].length - 1);
const lastText = str.substring(match.index + match[0].length);
const first = replaceUnderscores(firstText, documentLink, startKey);
const middle = [<strong className={'claims-emphasis'} key={startKey + first.length}>{middleText}</strong>];
const last = replaceUnderscores(lastText, documentLink, startKey + first.length + 1);
return first.concat(middle, last);
}
function replaceDocumentLink(str: string, documentLink: ((k:number)=>JSX.Element)|null, startKey: number=0):JSX.Element[] {
const replaceIndex = str.indexOf('{0}');
if (replaceIndex >= 0 && documentLink) {
return [
<React.Fragment key={startKey}>{str.substring(0, replaceIndex)}</React.Fragment>,
documentLink(startKey+1),
<React.Fragment key={startKey + 2}>{str.substring(replaceIndex+3)}</React.Fragment>
];
}
return [<React.Fragment key={startKey}>{str}</React.Fragment>];
}

rendering formio custom component is not working

I have one formio js file like checkbox.js,and i register that component into my custom_formio component as follows...
checkbox.js
import _ from 'lodash';
import BaseComponent from 'formiojs/components/base/Base';
export default class CheckBoxComponent extends BaseComponent {
static schema(...extend) {
return BaseComponent.schema({
type: 'checkbox',
inputType: 'checkbox',
label: 'Checkbox',
key: 'checkbox',
dataGridLabel: true,
labelPosition: 'right',
value: '',
name: ''
}, ...extend);
}
static get builderInfo() {
return {
title: 'Checkbox',
group: 'basic',
icon: 'fa fa-check-square',
documentation: 'http://help.form.io/userguide/#checkbox',
weight: 50,
schema: CheckBoxComponent.schema()
};
}
get defaultSchema() {
return CheckBoxComponent.schema();
}
get defaultValue() {
return this.component.name ? '' : (this.component.defaultValue || false).toString() === 'true';
}
get hasSetValue() {
return this.hasValue();
}
elementInfo() {
const info = super.elementInfo();
info.type = 'input';
info.changeEvent = 'click';
info.attr.type = this.component.inputType || 'checkbox';
info.attr.class = 'form-check-input';
if (this.component.name) {
info.attr.name = `data[${this.component.name}]`;
}
info.attr.value = this.component.value ? this.component.value : 0;
return info;
}
build() {
if (this.viewOnly) {
return this.viewOnlyBuild();
}
if (!this.component.input) {
return;
}
this.createElement();
this.input = this.createInput(this.element);
this.createLabel(this.element, this.input);
if (!this.labelElement) {
this.addInput(this.input, this.element);
}
this.createDescription(this.element);
this.restoreValue();
if (this.shouldDisable) {
this.disabled = true;
}
this.autofocus();
this.attachLogic();
}
get emptyValue() {
return false;
}
isEmpty(value) {
return super.isEmpty(value) || value === false;
}
createElement() {
let className = `form-check ${this.className}`;
if (!this.labelIsHidden()) {
className += ` ${this.component.inputType || 'checkbox'}`;
}
this.element = this.ce('div', {
id: this.id,
class: className
});
this.element.component = this;
}
labelOnTheTopOrLeft() {
return ['top', 'left'].includes(this.component.labelPosition);
}
labelOnTheTopOrBottom() {
return ['top', 'bottom'].includes(this.component.labelPosition);
}
setInputLabelStyle(label) {
if (this.component.labelPosition === 'left') {
_.assign(label.style, {
textAlign: 'center',
paddingLeft: 0,
});
}
if (this.labelOnTheTopOrBottom()) {
_.assign(label.style, {
display: 'block',
textAlign: 'center',
paddingLeft: 0,
});
}
}
setInputStyle(input) {
if (!input) {
return;
}
if (this.component.labelPosition === 'left') {
_.assign(input.style, {
position: 'initial',
marginLeft: '7px'
});
}
if (this.labelOnTheTopOrBottom()) {
_.assign(input.style, {
width: '100%',
position: 'initial',
marginLeft: 0
});
}
}
createLabel(container, input) {
const isLabelHidden = this.labelIsHidden();
let className = 'control-label form-check-label';
if (this.component.input
&& !this.options.inputsOnly
&& this.component.validate
&& this.component.validate.required) {
className += ' field-required';
}
this.labelElement = this.ce('label', {
class: className
});
this.addShortcut();
const labelOnTheTopOrOnTheLeft = this.labelOnTheTopOrLeft();
if (!isLabelHidden) {
// Create the SPAN around the textNode for better style hooks
this.labelSpan = this.ce('span');
if (this.info.attr.id) {
this.labelElement.setAttribute('for', this.info.attr.id);
}
}
if (!isLabelHidden && labelOnTheTopOrOnTheLeft) {
this.setInputLabelStyle(this.labelElement);
this.setInputStyle(input);
this.labelSpan.appendChild(this.text(this.component.label));
this.labelElement.appendChild(this.labelSpan);
}
this.addInput(input, this.labelElement);
if (!isLabelHidden && !labelOnTheTopOrOnTheLeft) {
this.setInputLabelStyle(this.labelElement);
this.setInputStyle(input);
this.labelSpan.appendChild(this.text(this.addShortcutToLabel()));
this.labelElement.appendChild(this.labelSpan);
}
this.createTooltip(this.labelElement);
container.appendChild(this.labelElement);
}
createInput(container) {
if (!this.component.input) {
return;
}
const input = this.ce(this.info.type, this.info.attr);
this.errorContainer = container;
return input;
}
set dataValue(value) {
const setValue = (super.dataValue = value);
if (this.component.name) {
_.set(this.data, this.component.key, setValue === this.component.value);
}
return setValue;
}
get dataValue() {
const getValue = super.dataValue;
if (this.component.name) {
_.set(this.data, this.component.key, getValue === this.component.value);
}
return getValue;
}
get key() {
return this.component.name ? this.component.name : super.key;
}
getValueAt(index) {
if (this.component.name) {
return this.inputs[index].checked ? this.component.value : '';
}
return !!this.inputs[index].checked;
}
getValue() {
const value = super.getValue();
if (this.component.name) {
return value ? this.setCheckedState(value) : this.setCheckedState(this.dataValue);
}
else {
return value;
}
}
setCheckedState(value) {
if (!this.input) {
return;
}
if (this.component.name) {
this.input.value = (value === this.component.value) ? this.component.value : 0;
this.input.checked = (value === this.component.value) ? 1 : 0;
}
else if (value === 'on') {
this.input.value = 1;
this.input.checked = 1;
}
else if (value === 'off') {
this.input.value = 0;
this.input.checked = 0;
}
else if (value) {
this.input.value = 1;
this.input.checked = 1;
}
else {
this.input.value = 0;
this.input.checked = 0;
}
if (this.input.checked) {
this.input.setAttribute('checked', true);
}
else {
this.input.removeAttribute('checked');
}
return value;
}
setValue(value, flags) {
flags = this.getFlags.apply(this, arguments);
if (this.setCheckedState(value) !== undefined) {
return this.updateValue(flags);
}
}
getView(value) {
return value ? 'Yes' : 'No';
}
destroy() {
super.destroy();
this.removeShortcut();
}
}
custom_formio.component.ts
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { FormioAuthService } from 'angular-formio/auth';
import { Formio } from 'formiojs';
import { CheckBoxComponent }from './Checkbox'
#Component({
selector: 'app-custom_formio',
templateUrl: './custom_formio.component.html',
styleUrls: ['./custom_formio.component.less']
})
export class CustomFormioComponent {
title = 'app';
offlineCount = 0;
offlineMode: any = null;
offlineError = '';
constructor(private auth: FormioAuthService, private router: Router) {
this.auth.onLogin.subscribe(() => {
this.router.navigate(['/home']);
});
this.auth.onLogout.subscribe(() => {
this.router.navigate(['/auth/login']);
});
this.auth.onRegister.subscribe(() => {
this.router.navigate(['/home']);
});
Formio.registerComponent('custom_formio', CheckBoxComponent);
}
}
but i don't know what code i have to write in custom_formio.component.html to render the custom checkbox component into my application.
custom_formio.component.html
<div class="m-content">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__body">
<div id="custom_formio"></div>
</div>
</div>
</div>
but it is not working,can any one help...
It's the ES5 class CheckBoxComponent that should contain the custom HTML you want to rendrer providing it in Build() using super class BaseComponent method renderTemplate().
Custom formio components should be created with native html so you can not use angular components.
But, there is a solution using new angular feature (Angular elements aka web compoenents)
Check-out avan2s's angular project
https://github.com/avan2s/angular-app-starterkit
useful: https://github.com/formio/angular-formio/issues/201

React JS Rendering List after built

I am trying to build a dynamic NavBar component that renders from React Routes, I am receiving routes as props and then building an array to render as a Navigation component but html is not at all rendering
Here is the code
import React from 'react';
import { Link } from 'react-router';
class NavBarComponent extends React.Component {
constructor() {
super();
this.routeList = [];
}
_getDisplayName(route) {
let name = null;
if (typeof route.getDisplayName === 'function') {
name = route.getDisplayName();
}
if (route.indexRoute) {
name = name || route.indexRoute.displayName || null;
} else {
name = name || route.displayName || null;
}
//check to see if a custom name has been applied to the route
if (!name && !!route.name) {
name = route.name;
}
//if the name exists and it's in the excludes list exclude this route
//if (name && this.props.excludes.some(item => item === name)) return null;
if (!name) {
name = "";
}
return name;
}
_checkAddRoutes(route, isRoot) {
let name = this._getDisplayName(route);
let exist = this.routeList.find(y => y.path === route.path);
if (exist == null && name && route.path) {
if (!isRoot) {
name = '/' + name;
}
this.routeList.push({ "path": route.path, "name": name });
}
}
_buildRoutes(routes) {
routes.forEach((_route) => {
let isRoot = routes[1] && !routes[1].hasOwnProperty("path");
let route = Object.assign({}, _route);
if (typeof _route.prettifyParam === 'function') {
route.prettifyParam = _route.prettifyParam;
}
if (isRoot && !route.path) {
route.path = '/';
}
this._checkAddRoutes(route, isRoot);
if (isRoot && route.childRoutes && route.childRoutes.length) {
let cls = this;
route.childRoutes.forEach(chilRoute => {
cls._checkAddRoutes(chilRoute);
});
}
});
}
renderListItem(item) {
return <li> <Link to="/about" activeClassName="sui-active">{item.name}</Link> </li>;
}
renderList() {
if (this.routeList && this.routeList.length) {
return this.routeList.map(item => this.renderListItem(item));
}
return [];
}
render() {
this._buildRoutes(this.props.routes);
return (
<ul className="sui-navbar sui-border sui-round">
{this.renderList}
</ul>
);
}
}
NavBarComponent.propTypes = {
routes: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
};
module.exports = NavBarComponent;
Yah,
I found it I have to call as function
{this.renderList()}

Categories