I am fetching data from an API and then displaying it as options in the select boxes. The option chosen from the first select box will populate the options for second select box. and after that we will submit the form which will redirect us to a different page. This whole functionality is working fine.
The scrolling in the select boxes is working fine on keyboard keys press, dragging the scroll bar.
I am stuck at the point that whenever I scroll over the options the page gets scrolled instead of the options dropdown and I don't want to use Jquery as it is not suggested to be used with ReactJs. Is their any option other than Jquery to perform this operation?
import React from 'react';
import { Route, Redirect } from 'react-router'
import { Async } from 'react-select';
import Select from 'react-select'
import { renameKeys } from '../utils'
export class ExplorePage extends React.Component {
constructor() {
super()
this.state = {
cityValue: null,
universityValue: 0,
unselectedUnivValue: [],
os: "",
classes: "",
class2: ""
}
this.universitySelectChange = this.universitySelectChange.bind(this);
this.citySelectChange = this.citySelectChange.bind(this);
this.getCities = this.getCities.bind(this)
this.getUniv = this.getUniv.bind(this)
this.osCheck = this.osCheck.bind(this);
}
osCheck() {
this.state.os = navigator.platform;
console.log(this.state.os);
if (this.state.os == 'Win32') {
this.state.classes = document.getElementsByClassName('Select-placeholder');
for (var i = 0; i < this.state.classes.length; i++) {
this.state.classes[i].classList.add('for-Win32');
}
this.state.class2 = document.getElementsByClassName('Select-value');
for (var i = 0; i < this.state.class2.length; i++) {
this.state.class2[i].classList.add('for-Win32');
}
}
}
componentDidMount() {
this.osCheck();
}
componentWillUnmount() {
this.osCheck();
}
universitySelectChange = (universityValue) => {
this.setState({ universityValue });
}
citySelectChange = (cityValue) => {
this.setState({ cityValue });
this.getUniv(cityValue).then((options) => { this.setState({ unselectedUnivValue: options }) })
}
getCities() {
return fetch(`API`)
.then((response) => response.json())
.then((json) => {
let newKey = { city_id: 'value', name: 'label' }
return {
options: json.response.result.map((item) => renameKeys(item, newKey))
}
})
}
getUniv(cityValue) {
return fetch(`API`)
.then((response) => response.json())
.then((json) => {
let newKey = { university_id: 'value', name: 'label' }
let toReturn = json.response.result.map((item) => renameKeys(item, newKey))
return toReturn
})
}
render() {
return <section id="scroll-section6" className="explore-res img-bg height-70 d-flex align-items-center">
<div className="container">
<div className="row">
<div className="col-lg-12 mt-5 pt-5">
<div className="st-sec-content">
<h1 className="st-sec-heading">EXPLORE RESIDENCES</h1>
<form>
<ul className="res-prop-select-group">
<li>
<div className="city-icon"></div>
<Async
onChange={() => { this.osCheck(), this.citySelectChange }}
loadOptions={this.getCities}
placeholder="Select your City"
removeSelected={this.state.removeSelected}
simpleValue
value={this.state.cityValue}>
</Async>
</li>
<li>
<div className="country-icon"></div>
<Select multi
onChange={() => { this.osCheck(), this.universitySelectChange }}
options={this.state.unselectedUnivValue}
placeholder="Select your College"
removeSelected={this.state.removeSelected}
simpleValue
value={this.state.universityValue}>
</Select>
</li>
<li>
<button className="st-l-hm-btn-1 a-link go mr-0">
<a class="text-white font-weight-light"
href={this.state.cityValue === null ? '/residence' : `/residence/${this.state.cityValue}/${this.state.universityValue}`}
onClick={(e) => {
}}>Go</a></button>
</li>
</ul>
</form>
</div>
</div>
</div>
</div >
</section >
}
}
Have you tried using focus() method
You could use the above focus method on the select ref
or you could also set autofocus prop on the select like so
<Select multi onChange={()=>
{this.osCheck(), this.universitySelectChange }}
autoFocus={true}
options={this.state.unselectedUnivValue}
placeholder="Select your College"
removeSelected={this.state.removeSelected}
simpleValue
value={this.state.universityValue}>
</Select>
Related
When I click Completed/Active how to show the filter icon in Ag-grid?
When I am doing a filter in ag-grid it showing the icon like below
Here is my code.
import React, { Component } from "react";
import { connect } from "react-redux";
import {
deleteTodo,
toggleTodo,
setVisibilityFilter
} from "../actions/actionCreator";
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from "../actions/actionsTypes";
import { bindActionCreators } from "redux";
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';
class Table extends Component {
handleChange = (event) => {
alert(event.target.value)
this.props.setVisibilityFilter(event.target.value)
};
render() {
return (
<div className="col-lg-10 offset-lg-1 col-md-10 col-sm-12 col-xs-12">
<nav style={{ marginTop: "60px" }}>
<ol className="breadcrumb">
<li
className={"breadcrumb-item "+ (this.props.visibilityFilter === SHOW_ALL ? 'active' : '') }
onClick={() => this.props.setVisibilityFilter(SHOW_ALL)}
>
All
</li>
<li
className={"breadcrumb-item "+ (this.props.visibilityFilter === SHOW_COMPLETED ? 'active' : '') }
onClick={() => this.props.setVisibilityFilter(SHOW_COMPLETED)}
>
Completed
</li>
<li
className={"breadcrumb-item "+ (this.props.visibilityFilter === SHOW_ACTIVE ? 'active' : '') }
onClick={() => this.props.setVisibilityFilter(SHOW_ACTIVE)}
>
Active
</li>
</ol>
</nav>
<select onChange={this.handleChange}>
<option value="SHOW_ALL" >All</option>
<option value="SHOW_COMPLETED"> Completed</option>
</select>
{this.props.todos.length !== 0 ? (
<div
className="ag-theme-balham"
style={{ height: '200px', width: '600px' }}
>
<AgGridReact
enableSorting={true}
enableFilter={true}
columnDefs={this.props.todos.columnDefs}
rowData={this.props.todos.rowData}>
</AgGridReact>
</div>
) : (
<div
style={{ marginTop: "50px" }}
className="col-lg-10 col-md-10 col-xs-12 col-sm-12 offset-lg-1"
>
<div className="alert alert-danger" role="alert">
Todo List is empty or Filter results show no results
</div>
</div>
)}{" "}
</div>
);
}
}
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case SHOW_ALL:
return todos;
case SHOW_COMPLETED:
return { ...todos, rowData: todos.rowData.filter(item => item.status === 'Completed')}
case SHOW_ACTIVE:
return { ...todos, rowData: todos.rowData.filter(item => item.status === 'Active')}
default:
throw new Error("Unknown filter: " + filter);
}
};
const mapStateToProps = state => {
return { todos: getVisibleTodos(state.todos, state.visibilityFilter),
visibilityFilter: state.visibilityFilter
};
};
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
deleteTodo,
toggleTodo,
setVisibilityFilter
},
dispatch
);
};
export default connect(mapStateToProps, mapDispatchToProps)(Table);
While working with custom filter, after you apply filter and call params.filterChangedCallback(),
if isFilterActive() function of your filter component returns true, the filter icon will be displayed.
It's all about using the apis provided by ag-grid.
Update:
Instead of applying filter manually on rowData like
case SHOW_COMPLETED:
return { ...todos, rowData: todos.rowData.filter(item => item.status === 'Completed')}
case SHOW_ACTIVE:
return { ...todos, rowData: todos.rowData.filter(item => item.status === 'Active')}
default:
Use gridApi to apply filter.
// Get a reference to the name filter instance
var filterInstance = gridApi.getFilterInstance('status'); // field name
// Set the model for the filter
filterInstance.setModel({
type: 'equals', // verify
filter: 'Active'
});
// Get grid to run filter operation again
gridApi.onFilterChanged();
I have a react app that I made in VS Studio, putting it into codepen, it doesnt seem to load a thing, any suggestions?
I have tried making sure React is linked and checked all of my syntax, no errors on local host but no display in codepen.
I have looked through the code multiple times and I feel its such a silly mistake
https://codepen.io/donnieberry97/pen/EzmOvW
class TodoListt extends React.Component {
state = {};
constructor(props) {
super(props);
this.state = {
userInput: "",
list: [],
editing: false,
};
}
changeUserInput(input) {
this.setState({
userInput: input
})
}
addToList() {
if (this.state.userInput === "") { (alert("Please enter a To-do")); return; };
const { list, userInput } = this.state;
this.setState({
list: [...list, {
text: userInput, key: Date.now(), done: false
}],
userInput: ''
})
}
handleChecked(e, index) {
console.log(e.target.checked);
const list = [...this.state.list];
list[index] = { ...list[index] };
list[index].done = e.target.checked;
this.setState({
list
})
}
handleEditing(e) {
this.setState({
editing: true
})
}
handleRemoved(index) {
const list = [...this.state.list];
list.splice(index, 1);
this.setState({
list
})
}
render() {
var viewStyle = {};
var editStyle = {};
if (this.state.editing) {
viewStyle.display = "none"
}
else {
editStyle.display = "none"
}
return (
<div className="to-do-list-main">
<input
onChange={(e) => this.changeUserInput(e.target.value)}
value={this.state.userInput}
type="text"
/>
<div class="submitButton">
<button onClick={() => { this.addToList(this.state.userInput) }}>Add todo</button>
</div>
{this.state.list.map((list, index) => (
<div className="form">
<ul>
{/* <div style={viewStyle} onDoubleClick={this.handleEditing.bind(t his)}> */}
<li key={list.key}>
<div class="liFlexCheck">
<input type="checkbox" onChange={(e) => this.handleChecked(e, index)} />
</div>
<div class="liFlexText">
<div class="liFlexTextContainer">
<span style={{ textDecoration: list.done ? 'line-through' : 'inherit' }}>
{list.text}
</span>
</div>
</div>
<button onClick={(index) => this.handleRemoved(index)}>Remove</button>
<input
type="text"
style={editStyle}
value={list.text}
/>
</li>
{/* </div> */}
</ul>
</div>
))}
</div>
);
}
}
Remove the import statements, working example.
You shouldn't use import when you got External Scripts.
Also, you got many errors in your code that should be handled, like:
<div class="submitButton">, use className.
Each child in a list should have a unique key prop.
Form field with value prop but without onChange handler.
Check out the logs:
In codpen, you don't need to import the react instead just write code,
here is codepen working one : codepen
from codesandbox, you can learn with all imports also because it doesn't uses any external scripts,
your code will work fine if you add an import to it
that is import ReactDOM from 'react-dom';
codesandbox will show all these suggestions,
here is codesandbox working example: codesandbox
While I'm trying to get in to React, I started a project and got stuck. Maybe some one can help me to find the issue. Bellow I explain what the app should do.
The user types a query in an input-box inside SearchBar.jsx
The SearchBar component passes the query to App.jsx and fires up fetchPhotos function, which starts an API request.
To sort out pagination, the App.jsx imports Pagination.jsx, which calculates the number of pictures in the response and displays pagination buttons.
The above works.
But now if you click on a pagination button, the value for page from Pagination component should be passed to App.jsx and so to fetchPhotos function (runs the API request).
I guess the problem is that the value of page never finds its way to App.jsx and so the API request is missing the value of page.
I spent hours but couldn't find a way to fix it, due to lack of knowledge. Could you please point me to the right direction and show me what is wrong with the code?
App.jsx
import React, { Component } from "react";
import axios from "axios";
import Pagination from "../Pagination";
import SearchBar from "../SearchBar";
import ListItem from "../ListItem";
import "./app.scss";
class App extends Component {
state = {
photos: [],
totalPhotos: 0,
perPage: 30,
currentPage: 1,
query: null
};
componentDidMount() {
this.fetchPhotos("gorilla", this.state.currentPage);
}
fetchPhotos = (inputValue, page) => {
const baseUrl = "https://api.unsplash.com/search/photos";
const options = {
headers: {
Authorization: `Client-ID ${process.env.REACT_APP_UNSPLASH_API_KEY}`
},
params: {
query: inputValue,
page: this.state.page,
per_page: this.state.perPage
}
};
axios
.get(baseUrl, options)
.then(response => {
this.setState({
photos: response.data.results,
totalPhotos: parseInt(response.headers["x-total"]),
currentPage: page,
query: inputValue
});
})
.catch(() => {
console.log("Error");
});
};
render() {
return (
<div className="app">
<SearchBar onSubmit={this.fetchPhotos} />
<Pagination
current={this.state.currentPage}
total={this.state.totalPhotos}
perPage={this.state.perPage}
query={this.state.query}
onPageChanged={query => this.fetchPhotos(this.state.query)}
/>
<List data={this.state.photos} />
</div>
);
}
}
const List = ({ data }) => {
var items = data.map(photo => <ListItem key={photo.id} photo={photo} />);
return <div className="grid">{items}</div>;
};
export default App;
SearchBar.jsx
import React, { Component } from "react";
class SearchBar extends Component {
state = {
inputValue: ""
};
handleFormSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state.inputValue);
};
render() {
return (
<div className="header">
<h1>Search for images on Unsplash</h1>
<form onSubmit={this.handleFormSubmit} className="ui form">
<input
type="text"
placeholder="Type here to search for images"
value={this.state.inputValue}
onChange={e => this.setState({ inputValue: e.target.value })}
/>
</form>
</div>
);
}
}
export default SearchBar;
Pagination.jsx
import React, { Component } from "react";
class Pagination extends Component {
pages() {
var pages = [];
for (var i = this.rangeStart(); i <= this.rangeEnd(); i++) {
pages.push(i);
}
return pages;
}
rangeStart() {
var start = this.props.current - this.props.pageRange;
return start > 0 ? start : 1;
}
rangeEnd() {
var end = this.props.current + this.props.pageRange;
var totalPages = this.totalPages();
return end < totalPages ? end : totalPages;
}
totalPages() {
return Math.ceil(this.props.total / this.props.perPage);
}
nextPage() {
return this.props.current + 1;
}
prevPage() {
return this.props.current - 1;
}
hasFirst() {
return this.rangeStart() !== 1;
}
hasLast() {
return this.rangeEnd() < this.totalPages();
}
hasPrev() {
return this.props.current > 1;
}
hasNext() {
return this.props.current < this.totalPages();
}
changePage(page) {
this.props.onPageChanged(page);
console.log("Page inside Pagination", page);
}
render() {
return (
<div className="pagination">
<div className="pagination__left">
<span
role="button"
className={!this.hasPrev() ? "hidden" : ""}
onClick={e => this.changePage(this.prevPage())}
>
Prev
</span>
</div>
<div className="pagination__mid">
<ul>
<li className={!this.hasFirst() ? "hidden" : ""}>
<span role="button" onClick={e => this.changePage(1)}>
1
</span>
</li>
<li className={!this.hasFirst() ? "hidden" : ""}>...</li>
{this.pages().map((page, index) => {
return (
<li key={index}>
<span
role="button"
onClick={e => this.changePage(page)}
className={this.props.current === page ? "current" : ""}
>
{page}
</span>
</li>
);
})}
<li className={!this.hasLast() ? "hidden" : ""}>...</li>
<li className={!this.hasLast() ? "hidden" : ""}>
<span
role="button"
onClick={e => this.changePage(this.totalPages())}
>
{this.totalPages()}
</span>
</li>
</ul>
</div>
<div className="pagination__right">
<span
className={!this.hasNext() ? "hidden" : ""}
onClick={e => this.changePage(this.nextPage())}
>
Next
</span>
</div>
</div>
);
}
}
Pagination.defaultProps = {
pageRange: 2
};
export default Pagination;
I think your error is at `onChange', because you are giving current state query to fetch instead of the new query:
onPageChanged={query => this.fetchPhotos(this.state.query)}
You should replace it for new query like:
onPageChanged={query => this.fetchPhotos(query)}
EDIT 1:
You can see working it on https://codesandbox.io/s/9ymjj8ko9p?fontsize=14.
The changes is just as I said, on App.jsx:
params fixed passing page from function params and not from
fix onPageChange prop to Pagination like:
onPageChanged={page => this.fetchPhotos(this.state.query, page)}
I have a list of topics and groups being returned from an API call. Topics belongs to at least 1 or more groups. The topics are currently filtered by the groups that are selected. Each group selected is set or removed in the selectedGroups state. I have an input search box which is used to help the user find a topic, when they start typing in the textbox I want a dropdown just below showing if any topic titles match their search input. When they click that topic it should only show that topic in the topics state.
Example.. if I type..
"Jo"
We get a dropdown of topics just below as suggestions and should render as in the dropdown:-
John..
Johnny..
Joan..
etc
Then when we click one of these topics in the dropdown, the state for topics update. So yes it will just show one topic in this case.
I have the search input and onchange method called handleInputChange
I am getting an error: Property 'search' does not exist on type 'PracticeAreas'. and not sure where I should be heading towards getting this to work correctly. Any help would be really grateful, thanks
I have included example data from the API call
And the react script
Main:
import * as React from 'react';
import './PracticeAreas.css';
import IReportGroup from 'src/model/IReportGroup';
import { Loader } from '../loader/Loader';
import Suggestions from './Suggestions'
export interface IGroupTopics {
id: string
name: string,
groups: string[]
}
interface IOwnProps {
}
interface IOwnState {
groups: IReportGroup[],
topics: IGroupTopics[],
selectedGroups: IReportGroup[],
query: string,
}
class PracticeAreas extends React.Component<IOwnProps, IOwnState> {
constructor(props: IOwnProps) {
super(props);
this.state = {
groups: [],
topics: [],
selectedGroups: [],
query: ""
}
}
public render() {
const { topics } = this.state;
return topics.length > 0 ?
this.renderData(topics) :
<Loader />
}
public renderData(data: any) {
return (
<div className="col-md-12 practiceAreas">
<h1>Practice Areas</h1>
<div className="selection-refinement">
<div className="refinement-search">
<form>
<input
placeholder="Search for..."
ref={input => this.search = input}
onChange={this.handleInputChange}
/>
<Suggestions topics={this.state.topics} />
</form>
</div>
</div>
<ul className="list-inline groupedTags">
{this.state.groups.map((item,i) =>
<li key={i}>
<a className={"navigator-tags " + (this.groupInState(item) ? "active" : "")} onClick={() => this.setSelectedGroups(item)}>
{item.name}
</a>
</li>
)}
</ul>
<div className="row practiceAreasContainer">
{this.state.topics.filter(topic => this.topicInGroupSelection(topic)).map((item,i) =>
<div key={i} className="result">
<div className="col-md-6 result-item">
<div className="item-container default shadowed item-content highlight row">
<div className="col-sm-12 no-padding">
<p>Editor: John Sinclair, Eric Draven, Coco Zames</p>
<p>Beiten Burkhardt</p>
<div className="row no-margin">
<div className="col-12 col-sm-10 text-content">
<h3>
<a href="#" >{item.name}</a>
</h3>
<p className="summary">
Summary
</p>
</div>
<div className="col-10 col-sm-2 links-container rhs">
Compare
<div className="divider" />
View
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
<div className="row text-center">
<a className="lex-primary-btn medium-btn">Load more</a>
</div>
</div>
);
}
public handleInputChange = () => {
this.setState({
query: this.search.value
}, () => {
if (this.state.query && this.state.query.length > 1) {
// this.showDropdown()
if (this.state.query.length % 2 === 0) {
this.state.topics
}
} else if (!this.state.query) {
// this.hideDropdown()
}
})
}
public componentDidMount() {
fetch(`.../api/v2/navigator/reports/topics`, {
method: "GET",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}})
.then((res) => res.json()
.then((data) => {
this.setState({
groups: data.groups,
topics: data.data
});
}));
}
public setSelectedGroups = (group: IReportGroup) => {
// remove from state
if (this.groupInState(group)) {
this.setState(state => ({
selectedGroups: state.selectedGroups.filter(t => t.id !== group.id)
}));
// set state
} else {
this.setState(previousState => ({
selectedGroups: [...previousState.selectedGroups, group]
}));
}
}
public topicInGroupSelection = (topic: IGroupTopics) => {
return (this.state.selectedGroups.length > 0 ? this.state.selectedGroups.some(item => topic.groups.some(group => group === item.id)) : true)
}
public groupInState = (group: IReportGroup) => {
return this.state.selectedGroups.some(item => group.id === item.id);
}
}
export default PracticeAreas
Suggestions (which should topics in the state):
import * as React from 'react';
const Suggestions = (props) => {
const options = props.topics.map(r => (
<li key={r.id}>
{r.name}
</li>
))
return <ul>{options}</ul>
}
export default Suggestions
Data ex:
<ReportSelectionCriteriaResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
<Data xmlns:d2p1="http://schemas.datacontract.org/2004/07/">
<d2p1:NavigatorReportSelection>
<d2p1:About>test title 4</d2p1:About>
<d2p1:Groups xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:guid>d21384b5-27be-4bfc-963d-0d2ad40dbbfb</d4p1:guid>
</d2p1:Groups>
<d2p1:Id>2fb2783c-f48e-4d49-8098-0d39e4a16e7a</d2p1:Id>
<d2p1:Name>Test</d2p1:Name>
<d2p1:ParentId i:nil="true"/>
<d2p1:Selected>false</d2p1:Selected>
<d2p1:Type>Topics</d2p1:Type>
<d2p1:Visible>true</d2p1:Visible>
</d2p1:NavigatorReportSelection>
<d2p1:NavigatorReportSelection>
<d2p1:About i:nil="true"/>
<d2p1:Groups xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:guid>2fb2783c-f48e-4d49-8098-0d39e4a16e7a</d4p1:guid>
</d2p1:Groups>
<d2p1:Id>47cb7f1d-2267-426c-9f7f-0df3b9291fb7</d2p1:Id>
<d2p1:Name>Another test topic</d2p1:Name>
<d2p1:ParentId i:nil="true"/>
<d2p1:Selected>false</d2p1:Selected>
<d2p1:Type>Topics</d2p1:Type>
<d2p1:Visible>true</d2p1:Visible>
</d2p1:NavigatorReportSelection>
</Data>
<Groups xmlns:d2p1="http://schemas.datacontract.org/2004/07/">
<d2p1:NavigatorReportSelectionGroup>
<d2p1:Focused>false</d2p1:Focused>
<d2p1:Id>2fb2783c-f48e-4d49-8098-0d39e4a16e7a</d2p1:Id>
<d2p1:Name>Allan's Test group</d2p1:Name>
<d2p1:Order>0</d2p1:Order>
<d2p1:Type>Topics</d2p1:Type>
</d2p1:NavigatorReportSelectionGroup>
<d2p1:NavigatorReportSelectionGroup>
<d2p1:Focused>false</d2p1:Focused>
<d2p1:Id>47cb7f1d-2267-426c-9f7f-0df3b9291fb7</d2p1:Id>
<d2p1:Name>Another test topic group</d2p1:Name>
<d2p1:Order>1</d2p1:Order>
<d2p1:Type>Topics</d2p1:Type>
</d2p1:NavigatorReportSelectionGroup>
</Groups>
</ReportSelectionCriteriaResponse>
I'm trying to make simple CRUD example using react.js as frontend.
I already have add/edit functionality done in a component,
but I want to call this component dynamically on click and show it as a popup or modal window on the same page without redirecting to another route.
Does anyone have experience with doing this using react.js?
This is my parent component code where I show a grid of items displaying cities:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
interface FetchNaseljeDataState {
nasList: NaseljeData[];
loading: boolean;
}
export class FetchNaselje extends React.Component<RouteComponentProps<{}>, FetchNaseljeDataState> {
constructor() {
super();
this.state = { nasList: [], loading: true };
fetch('api/Naselje/Index')
.then(response => response.json() as Promise<NaseljeData[]>)
.then(data => {
this.setState({ nasList: data, loading: false });
});
// This binding is necessary to make "this" work in the callback
this.handleDelete = this.handleDelete.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderNaseljeTable(this.state.nasList);
return <div>
<h1>Naselje Data</h1>
<p>This component demonstrates fetching Naselje data from the server.</p>
<p>
<Link to="/addnaselje">Create New</Link>
</p>
{contents}
</div>;
}
// Handle Delete request for an naselje
private handleDelete(id: number) {
if (!confirm("Do you want to delete naselje with Id: " + id))
return;
else {
fetch('api/Naselje/Delete/' + id, {
method: 'delete'
}).then(data => {
this.setState(
{
nasList: this.state.nasList.filter((rec) => {
return (rec.idnaselje != id);
})
});
});
}
}
private handleEdit(id: number) {
this.props.history.push("/naselje/edit/" + id);
}
// Returns the HTML table to the render() method.
private renderNaseljeTable(naseljeList: NaseljeData[]) {
return <table className='table'>
<thead>
<tr>
<th></th>
<th>ID Naselje</th>
<th>Naziv</th>
<th>Postanski Broj</th>
<th>Drzava</th>
</tr>
</thead>
<tbody>
{naseljeList.map(nas =>
<tr key={nas.idnaselje}>
<td></td>
<td>{nas.idnaselje}</td>
<td>{nas.naziv}</td>
<td>{nas.postanskiBroj}</td>
<td>{nas.drzava && nas.drzava.naziv}</td>
<td>
<a className="action" onClick={(id) => this.handleEdit(nas.idnaselje)}>Edit</a> |
<a className="action" onClick={(id) => this.handleDelete(nas.idnaselje)}>Delete</a>
</td>
</tr>
)}
</tbody>
</table>;
}
}
export class NaseljeData {
idnaselje: number = 0;
naziv: string = "";
postanskiBroj: string = "";
drzava: DrzavaData = { iddrzava: 0, naziv: ""};
drzavaid: number = 0;
}
export class DrzavaData {
iddrzava: number = 0;
naziv: string = "";
}
This is my child component that I want to dynamically show on create new link click:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
import { NaseljeData } from './FetchNaselje';
import { DrzavaData } from './FetchNaselje';
interface AddNaseljeDataState {
title: string;
loading: boolean;
drzavaList: Array<any>;
nasData: NaseljeData;
drzavaId: number;
}
export class AddNaselje extends React.Component<RouteComponentProps<{}>, AddNaseljeDataState> {
constructor(props) {
super(props);
this.state = { title: "", loading: true, drzavaList: [], nasData: new NaseljeData, drzavaId: -1 };
fetch('api/Naselje/GetDrzavaList')
.then(response => response.json() as Promise<Array<any>>)
.then(data => {
this.setState({ drzavaList: data });
});
var nasid = this.props.match.params["nasid"];
// This will set state for Edit naselje
if (nasid > 0) {
fetch('api/Naselje/Details/' + nasid)
.then(response => response.json() as Promise<NaseljeData>)
.then(data => {
this.setState({ title: "Edit", loading: false, nasData: data });
});
}
// This will set state for Add naselje
else {
this.state = { title: "Create", loading: false, drzavaList: [], nasData: new NaseljeData, drzavaId: -1 };
}
// This binding is necessary to make "this" work in the callback
this.handleSave = this.handleSave.bind(this);
this.handleCancel = this.handleCancel.bind(this);
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: this.renderCreateForm(this.state.drzavaList);
return <div>
<h1>{this.state.title}</h1>
<h3>Naselje</h3>
<hr />
{contents}
</div>;
}
// This will handle the submit form event.
private handleSave(event) {
event.preventDefault();
const data = new FormData(event.target);
// PUT request for Edit naselje.
if (this.state.nasData.idnaselje) {
fetch('api/Naselje/Edit', {
method: 'PUT',
body: data,
}).then((response) => response.json())
.then((responseJson) => {
this.props.history.push("/fetchnaselje");
})
}
// POST request for Add naselje.
else {
fetch('api/Naselje/Create', {
method: 'POST',
body: data,
}).then((response) => response.json())
.then((responseJson) => {
this.props.history.push("/fetchnaselje");
})
}
}
// This will handle Cancel button click event.
private handleCancel(e) {
e.preventDefault();
this.props.history.push("/fetchnaselje");
}
// Returns the HTML Form to the render() method.
private renderCreateForm(drzavaList: Array<any>) {
return (
<form onSubmit={this.handleSave} >
<div className="form-group row" >
<input type="hidden" name="idnaselje" value={this.state.nasData.idnaselje} />
</div>
< div className="form-group row" >
<label className=" control-label col-md-12" htmlFor="Naziv">Naziv</label>
<div className="col-md-4">
<input className="form-control" type="text" name="naziv" defaultValue={this.state.nasData.naziv} required />
</div>
</div >
<div className="form-group row">
<label className="control-label col-md-12" htmlFor="PostanskiBroj" >Postanski broj</label>
<div className="col-md-4">
<input className="form-control" name="PostanskiBroj" defaultValue={this.state.nasData.postanskiBroj} required />
</div>
</div>
<div className="form-group row">
<label className="control-label col-md-12" htmlFor="Drzava">Država</label>
<div className="col-md-4">
<select className="form-control" data-val="true" name="drzavaid" defaultValue={this.state.nasData.drzava ? this.state.nasData.drzava.naziv : ""} required>
<option value="">-- Odaberite Državu --</option>
{drzavaList.map(drzava =>
<option key={drzava.iddrzava} value={drzava.iddrzava}>{drzava.naziv}</option>
)}
</select>
</div>
</div >
<div className="form-group">
<button type="submit" className="btn btn-default">Save</button>
<button className="btn" onClick={this.handleCancel}>Cancel</button>
</div >
</form >
)
}
}
I'm assuming I'll have to make css for the create/edit component to make it look like a popup...
EDIT: I would appreciate if someone could make code example using my classes, thanks...
In the parent component set a state on click functionality, say for eg:
this.setState({display: true})
In the parent component render based on condition display child component, say for eg:
<div>{(this.state.display) ? <div><childComponent /></div> : ''}</div>
To display the child component in a modal/popup, put the component inside say a bootstrap or react-responsive-modal. For that, you have to install and import react-responsive-modal and then
In the render method,
return (
<div>
{this.state.toggleModal ? <div className="container">
<Modal open={this.state.toggleModal} onClose={this.onCloseModal} center>
<div className="header">
<h4>{Title}</h4>
</div>
<div className="body">
<div>
{this.state.toggleModal ? <someComponent /> : ''}
</div>
</div>
</Modal>
</div>
: null}
</div>
)
Have your popup component receive a prop from the parent that will tell it if it should be displayed or not, a simple boolean will do the trick. Then, when you want something to show the popup, just change that state in the parent.