rendering formio custom component is not working - javascript

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

Related

Converting class component to functional component TypeError: users.filter is not a function

Making a employee directory and I'm trying to convert class component into functional component. The nav, search, and table will render but the call to the api isn't working. Getting a
TypeError: users.filter is not a function Here is the class component that works and the in progress functional component. I can't figure out what is different.
import React, { Component } from "react";
import DataTable from "./DataTable";
import Nav from "./Nav";
import API from "../utils/API";
import "../styles/DataArea.css";
export default class DataArea extends Component {
state = {
users: [{}],
order: "descend",
filteredUsers: [{}]
}
headings = [
{ name: "Image", width: "10%" },
{ name: "Name", width: "10%" },
{ name: "Phone", width: "20%" },
{ name: "Email", width: "20%" },
{ name: "DOB", width: "10%" }
]
handleSort = heading => {
if (this.state.order === "descend") {
this.setState({
order: "ascend"
})
} else {
this.setState({
order: "descend"
})
}
const compareFnc = (a, b) => {
if (this.state.order === "ascend") {
// account for missing values
if (a[heading] === undefined) {
return 1;
} else if (b[heading] === undefined) {
return -1;
}
// numerically
else if (heading === "name") {
return a[heading].first.localeCompare(b[heading].first);
} else {
return a[heading] - b[heading];
}
} else {
// account for missing values
if (a[heading] === undefined) {
return 1;
} else if (b[heading] === undefined) {
return -1;
}
// numerically
else if (heading === "name") {
return b[heading].first.localeCompare(a[heading].first);
} else {
return b[heading] - a[heading];
}
}
}
const sortedUsers = this.state.filteredUsers.sort(compareFnc);
this.setState({ filteredUsers: sortedUsers });
}
handleSearchChange = event => {
console.log(event.target.value);
const filter = event.target.value;
const filteredList = this.state.users.filter(item => {
// merge data together, then see if user input is anywhere inside
let values = Object.values(item)
.join("")
.toLowerCase();
return values.indexOf(filter.toLowerCase()) !== -1;
});
this.setState({ filteredUsers: filteredList });
}
componentDidMount() {
API.getUsers().then(results => {
this.setState({
users: results.data.results,
filteredUsers: results.data.results
});
});
}
render() {
return (
<>
<Nav handleSearchChange={this.handleSearchChange} />
<div className="data-area">
<DataTable
headings={this.headings}
users={this.state.filteredUsers}
handleSort={this.handleSort}
/>
</div>
</>
);
}
}
import React, { useState, useEffect } from "react";
import DataTable from "./DataTable";
import Nav from "./Nav";
import API from "../utils/API";
import "../styles/DataArea.css";
const DataArea = () => {
const [users, setUsers] = useState([{}]);
const [order, setOrder] = useState("descend");
const [filteredUsers, setFilteredUsers] = useState([{}]);
const headings = [
{ name: "Image", width: "10%" },
{ name: "Name", width: "10%" },
{ name: "Phone", width: "20%" },
{ name: "Email", width: "20%" },
{ name: "DOB", width: "10%" },
];
const handleSort = (heading) => {
if (order === "descend") {
setOrder((order = "ascend"));
} else {
setOrder((order = "descend"));
}
const compareFnc = (a, b) => {
if (order === "ascend") {
// account for missing values
if (a[heading] === undefined) {
return 1;
} else if (b[heading] === undefined) {
return -1;
}
// numerically
else if (heading === "name") {
return a[heading].first.localeCompare(b[heading].first);
} else {
return a[heading] - b[heading];
}
} else {
// account for missing values
if (a[heading] === undefined) {
return 1;
} else if (b[heading] === undefined) {
return -1;
}
// numerically
else if (heading === "name") {
return b[heading].first.localeCompare(a[heading].first);
} else {
return b[heading] - a[heading];
}
}
};
const sortedUsers = filteredUsers.sort(compareFnc);
setFilteredUsers({ filteredUsers: sortedUsers });
};
let handleSearchChange = (event) => {
console.log(event.target.value);
const filtered = event.target.value;
const filteredList = users.filter((item) => {
// merge data together, then see if user input is anywhere inside
let values = Object.values(item).join("").toLowerCase();
return values.indexOf(filtered.toLowerCase()) !== -1;
});
setFilteredUsers((filteredUsers = filteredList));
};
useEffect(() => {
API.getUsers().then((results) => {
setUsers({
users: results.data.results,
filteredUsers: results.data.results,
});
});
}, []);
return (
<>
<Nav handleSearchChange={handleSearchChange} />
<div className="data-area">
<DataTable
headings={headings}
users={filteredUsers}
handleSort={handleSort}
/>
</div>
</>
);
};
export default DataArea;
The issue is in your useEffect hook where you shoehorn both users and filteredUsers into your users state.
useEffect(() => {
API.getUsers().then((results) => {
setUsers({
users: results.data.results,
filteredUsers: results.data.results,
});
});
}, []);
It should be
useEffect(() => {
API.getUsers().then((results) => {
setUsers(results.data.results);
setFilteredUsers(results.data.results),
});
}, []);
You want to populate both the users state, and separately the filteredUsers state.
An issue with setting the sorting order, you are mutating the order state:
if (order === "descend") {
setOrder((order = "ascend")); // <-- mutates
} else {
setOrder((order = "descend")); // <-- mutates
}
You can simply toggle between the two:
setOrder(order => order === 'ascend' ? 'descend' : 'ascend');
Another issue is at the end of your handleSort function:
const sortedUsers = filteredUsers.sort(compareFnc);
setFilteredUsers({ filteredUsers: sortedUsers });
This will nest the filteredUsers array, and also mutates the array in-place, it should probably use a functional state update to update from the previous state, use array.slice to make a copy, and then call sort.
setFilteredUsers(filteredUsers => filteredUsers.slice().sort(compareFnc));

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();
}
}

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

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.

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()}

Polling not actually happening, React JS (ES6)

Consider for a moment the following code:
import React from 'react';
import ReactDOM from 'react-dom/dist/react-dom';
import chunk from 'lodash/array/chunk';
class Tweets extends React.Component {
constructor(props) {
super(props);
this.state = {
tweets: null,
error: null,
info: null,
source: null
}
}
componentDidMount() {
this._isMounted = true;
this.startPolling();
}
componentDidUpdate() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
}
componentWillUnmount() {
this._isMounted = false;
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
}
shouldComponentUpdate(nextProps, nextState) {
for (var key in this.state) {
for (var nextKey in nextState) {
if (this.state[key] !== nextState[nextKey]) {
return true
}
}
}
return false;
}
startPolling() {
var self = this;
setTimeout(function() {
self.poll();
if (!self._isMounted) {
return;
}
self._timer = setInterval(self.poll, 10000);
}, 1000);
}
poll() {
console.log('I should be called ....');
var self = this;
var source = null;
if (this.props !== undefined) {
source = this.props.source
}
$.get(source, function(result) {
if (self._isMounted) {
self.setState({
error: null,
tweets: result.data,
source: source
});
}
}).fail(function(response) {
self.setState({
error: 'Could not fetch tweets. Looks like something went wrong.',
});
});
}
checkIfLoading() {
if (this.state.tweets === null &&
this.state.error === null &&
this.state.info === null) {
return true;
}
return false;
}
buildTweets () {
let rows = [];
let currRow;
this.state.tweets.forEach((tweet, i) => {
if(i % 3 === 0) {
currRow = i;
rows[currRow] = [];
}
rows[currRow].push(
<div className='col-lg-4 col-md-6 col-sm-6 col-xs-12' key={tweet.id}>
<div className="white-panel tweet-panel">
<span><strong>{tweet.attributes.user_name}</strong><em>Posted: {tweet.attributes.time_ago}</em></span>
<p><span dangerouslySetInnerHTML={{__html: tweet.attributes.tweet}} /></p>
</div>
</div>
);
});
return rows;
}
render() {
if (this.checkIfLoading()) {
return (<div><i className="fa-li fa fa-spinner fa-spin"></i> One second please, while I fetch some tweets ....</div>);
}
var key = 0;
var tweets = this.buildTweets().map(function(tweetRows){
key += 1;
return (
<div key={key} className="row">
{tweetRows}
</div>
)
});
return (
<div id='tweetRowContainer'>
{tweets}
</div>
);
}
}
var tweetsElement = document.getElementById("tweets");
if (tweetsElement !== null) {
ReactDOM.render(
<Tweets source={"//" + location.hostname + "/api/v1/fetch-tweets"} />,
tweetsElement
);
}
module.exports = Tweets;
What we care about the most is the:
poll() {
console.log('I should be called ....');
...
This gets console logged the first time when the data gets fetched and then is displayed to the page, but as we can see just before this method:
startPolling() {
var self = this;
setTimeout(function() {
self.poll();
if (!self._isMounted) {
return;
}
self._timer = setInterval(self.poll, 10000);
}, 1000);
}
In theory this should be polling .... no?

Categories