This question already has answers here:
React 'cannot read property of undefined' when using map
(4 answers)
Closed 5 years ago.
I've just started looking basics of ReactJs. Following is my component to show list of buses. What I want exactly is I want to perform edit/delete operations over buses. But not able to pass busId of corresponding bus to my edit/delete methods.
Following is component code
import React, {Component} from "react";
import { withRouter } from 'react-router-dom'
import {Table,Badge, Label,FormGroup,Container, Row, Col, CardGroup, Card, CardBlock,CardHeader, Button, Input, InputGroup, InputGroupAddon} from "reactstrap";
import {appSettings} from '../../../../Utils/Util.js';
import Pagination from "react-js-pagination";
var axios = require('axios');
class BusList extends React.Component {
constructor(props) {
super(props);
this.state = {
busList:[]
};
this.loadBuses = this.loadBuses.bind(this);
}
componentWillMount() {
this.loadBuses();
}
loadBuses() {
var url = ‘my-api-complete-url-here’;
axios.get(url)
.then((result) => {
var key = 0;
var buses = result.data.map(function(bus,i){
return <tr key={key++}>
<td key={key++}>{bus.id}</td>
<td key={(key++)}>{bus.number}</td>
<td key={(key++)}>
<Button onClick={(e)=>this.editBus(e, bus.id)}>Edit</Button>
<Button onClick={(e)=>this.deleteBus(e, bus.id)}>Delete</Button>
</td>
</tr>
});
this.setState({busList: buses});
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div className="animated fadeIn">
<Table hover responsive striped>
<thead>
<tr>
<th>Sr #</th>
<th>Bus Number</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{this.state.busList}
</tbody>
</Table>
</div>
);
}
editBus(id, e) {
console.log(‘Edit - Bus Id = ' +id);
}
deleteBus(id, e) {
console.log('Delete - Bus Id = ' +id);
}
}
export default BusList;
But when tapped on edit button, I receive this error(
Screenshot)
you're accessing it in wrong order, you're passing (e)=>this.editBus(e, bus.id) and in function you've defined editBus(id, e)
moreover you need to bind(this) at the end of map function
var buses = result.data.map(function(bus,i){
return <tr key={key++}>
<td key={key++}>{bus.id}</td>
<td key={(key++)}>{bus.number}</td>
<td key={(key++)}>
<Button onClick={(e)=>this.editBus(e, bus.id)}>Edit</Button>
<Button onClick={(e)=>this.deleteBus(e, bus.id)}>Delete</Button>
</td>
</tr>
});
Also, you don't need to define key variable. Instead, use second argument i of map function as it is the index of array element.
updated
you need to change your map code with
var buses = result.data.map(function(bus,i){
return <tr key={key++}>
<td key={key++}>{bus.id}</td>
<td key={(key++)}>{bus.number}</td>
<td key={(key++)}>
<Button onClick={(e)=>this.editBus(e, bus.id)}>Edit</Button>
<Button onClick={(e)=>this.deleteBus(e, bus.id)}>Delete</Button>
</td>
</tr>
}.bind(this));
The .bind(this) in the last line does the trick.
Related
I am currently developing a ecommerce project using Laravel and react.js. I want to show the available cactus list in my admin panel. So, I created the table and add data to the table using laravel and react.js. The image is automatically saved to "cactus_Type" folder in the project folder. I want to show all the available cactus types that I have added to Database. So, I have created a table to show the available cactus. Only ID, Name is display on the table, the image is not display.
CactusController I use:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Cactus;
class CactusController extends Controller
{
//
function addCactus(Request $req)
{
$cactus=new Cactus;
$cactus->name=$req->input('name');
$cactus->file_path=$req->file('file')->store('cactus_Type');
$cactus->save();
return $cactus;
}
function Cactuslist()
{
return Cactus :: all();
}
function Cactusdelete($id)
{
$result= Cactus ::where('id',$id)->delete();
if($result)
{
return["result"=>"Cactus has been deleted"];
}
else
{
return["result"=>"Operation Failed"];
}
return $result;
}
}
Migration Cacti Table
public function up()
{
Schema::create('cacti', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('file_path');
$table->timestamps();
});
}
CactusList.js in react.js
import Cactus from './Cactus';
import React ,{useState,useEffect} from 'react';
import {Table} from 'react-bootstrap'
import {Link} from 'react-router-dom'
function CactusList()
{
//Define state
const [data,setData]=useState([]);
useEffect(()=>{
getData();
},[])
async function deleteOperation(id)
{
let result= await fetch("http://localhost:8000/api/Cactusdelete/"+id, {
method:'DELETE'
});
result=await result.json();
console.warn(result)
getData();
}
async function getData()
{
let result= await fetch("http://localhost:8000/api/Cactuslist");
result= await result.json();
setData(result)
}
return(
<div>
<Cactus/>
<div className="col-sm-8 offset-sm-2">
<h1>Available Cactus List</h1>
<Table>
<tr>
<td>Id</td>
<td>Name</td>
<td>Image</td>
<td>Operations</td>
</tr>
{
data.map((item)=>
<tr>
<td>{item.id}</td>
<td>{item.name}</td>
<td><img style={{width:100}} src ={"http://localhost:8000/"+item.file_path}/></td>
<td><span onClick={()=>deleteOperation(item.id)} className="delete">Delete</span></td>
<td>
<Link to={"updateCactus/"+item.id}>
<span className="update">Update</span>
</Link>
</td>
</tr>
)
}
</Table>
</div>
</div>
)
}
export default CactusList
I am getting this error in console
GET http://localhost:8000/cactus_Type/BEOPiwLF3EU9k2ggn8abKxAXgDVDpS38Up7UZ2OZ.jpg 404 (Not Found)
This is how the outcome show,
Available Cactus List Page
Thank you in advance for your help!
I'm browsing characters of the Rick & Morty series app, using vue.js and I'm new to vue.js.
but I'm getting below mentioned error, please help me solve this
Error1 : [Vue warn]: Property or method "list" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option or for class-based components, by initializing the property.
// App.vue file //
<template>
<div id="app">
<Nav />
<CharactersList />
</div>
</template>
<script>
import Nav from './components/Nav.vue'
import CharactersList from './components/CharactersList'
export default {
name: 'App',
components: {
Nav,
CharactersList
}
}
</script>
// CharactersList.vue file //
<template>
<div>
<h1>Rick and Morty characters</h1>
<table border="1px">
<tr>
<td>Character ID</td>
<td>Name</td>
<td>Species</td>
<td>Add to fav</td>
</tr>
<tr v-for="item in list" v-bind:key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}}}</td>
<td>{{item.species}}</td>
<button>Add to fav</button>
</tr>
</table>
</div>
</template>
<script>
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
export default {
name: 'CharactersList',
data: function () {
return {
list: undefined
}
},
mounted () {
Vue.axios.get('https://rickandmortyapi.com/api/character/')
.then((resp) => {
debugger
this.list = resp.data.results
})
}
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
First of all, you don't need to import there Vue and VueAxios, as they are no use there. And second, you need to modify your list variable value from undefined to []
I have changed your CharactersList component code, you can copy and paste all codes, and it will work as the way you want:
CharactersList.vue
<template>
<div>
<h1>Rick and Morty characters</h1>
<table border="1px">
<tr>
<td>Character ID</td>
<td>Name</td>
<td>Species</td>
<td>Add to fav</td>
</tr>
<tr v-for="item in list" v-bind:key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.species}}</td>
<button>Add to fav</button>
</tr>
</table>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'CharactersList',
data: function () {
return {
list: []
}
},
mounted () {
axios.get('https://rickandmortyapi.com/api/character/')
.then((resp) => {
this.list = resp.data.results
})
}
}
</script>
I have a reactjs project that uses react route version 4 and react16.3 . I can navigate to page http://localhost:8000/#/my-list where it will take you to MyList Component , on my list component there is a link to view a single list which behaves like a SPA by changing the state as below .
import React,{Component} from 'react'
class MyList extends Component{
constructor(props){
super(props)
this.state={
canViewItem:false
}
this.viewItem=this.viewItem.bind(this)
}
viewItem(){
this.setState({canViewItem:true})
}
renderDisplay() {
const {canViewItem}=this.state
if(canViewOrder){
return <canViewItem cancel={this.cancel} item={item} />
}
else {
return this.renderMyList()
}
}
renderMyList(){
return(
<table>
<thead>
<tr>
<th>Iten Name</th>
<th>Quantity</th>
<th>More Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>Item 1</td>
<td>10</td>
<td>onClick={() => this.viewItem(item1Obj)}</td>
</tr>
<tr>
<td>Item 2</td>
<td>30</td>
<td>onClick={() => this.viewItem(item2Obj)}</td>
</tr>
</tbody>
</table>
}
render(){
return this.renderDisplay()
}
}
How do i share a link so as it takes me direct to an item page ?
Inside of componentWillMount() evaluate what is being passed in this.props.location.pathname. You should be able to grab the ID # from your URL and update your state.
I don't see how you are determining in your existing code which item they are viewing.
componentWillMount() {
let id = '';
console.log(this.props.location.pathname);
// write a JS function to parse the ID from the URL here and save to 'id'
// then if you have an ID, save whatever you need to state.
if(id !== '') {
this.setState({
canViewItem: true
});
}
}
As a side note, renderDisplay and renderMyList should be included in your constructor.
This is my JSON result
Using Map function to display JSON array elements in reactJs.I have tried with the following code. I'm unable to get results and it says "Cannot read property '_currentElement' of null". Kindly help me to solve this.
import React, { Component } from 'react';
import Header from './js/components/Header';
import './App.css';
import './dist/css/bootstrap.css';
import cookie from 'react-cookie';
import Request from 'superagent';
import { browserHistory } from 'react-router';
export default class Performance extends Component {
constructor() {
super();
this.state = {
fullName : cookie.load('fullName'),
empId : cookie.load('empId'),
userResults : false
};
if(cookie.load('empId') === undefined ){
browserHistory.push('/login')
}
}
getInitialState(){
return {userResults:false};
}
componentDidMount() {
var self = this;
var url = 'http://192.168.1.93:8081/employee/dashboard';
Request
.get(url)
.query({ empId: this.state.empId })
.set('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8')
.set('Authorization', 'Basic aHJtczox')
.set('Accept', 'application/json')
.end(function(err, res){
self.setState({userResults: res.body});
console.log(self.state.userResults);
});
}
render() {
return (
<div>
<Header />
<div className="container ">
<form className="form-signin1">
<h2 className="form-signin-heading">Customer Orientation{this.props.userButtons}</h2>
<table className="table text-center" >
<thead>
<th >Deliverables</th>
</thead>
<tbody>
{
this.state.userResults.response.QuestionSection.map(function(res){
res.question.map(function(res1){
return (
<tr>
<td>{res1.question}</td>
</tr>
)
})
})
}
<tr><td>sdfsdf</td></tr>
</tbody>
</table>
<button className="btn btn-lg btn-primary btn-block" type="button">Sign in</button>
</form>
</div>
</div>
);
}
}
Since this.state.userResults.response doesn't exist initially you get this error. Its is better of performing a check before iterating. Also you need to return the result of inner map function too like
{
this.state.userResults.response && this.state.userResults.response.QuestionSection.map(function(res){
return res.question.map(function(res1){
return (
<tr>
<td>{res1.question}</td>
</tr>
)
})
})
}
I'm writting some test using enzyme but I have some weird behavior. Here is my test :
import React from 'react'
import { TypeTable } from 'routes/Type/components/TypeTable'
import { shallow } from 'enzyme'
import { Table } from 'react-toolbox'
// ...
let _props, _wrapper
beforeEach(() => {
_props = {
getTypes: sinon.spy(),
types: [
{ name: 'type 1'},
{ name: 'type 2'}
]
}
_wrapper = shallow(<TypeTable {..._props} />)
})
it('Should render a <Table>', () => {
expect(_wrapper.is(Table)).to.be.true
})
it('should render 2 rows', () => {
expect(_wrapper.find('tbody').find('tr')).to.have.length(2)
})
The first test is working. The second one is not working (the assertion is failing : expected { Object (root, unrendered, ...) } to have a length of 2 but got 0)
But in my second test, if I print the content of my _wrapper using console.log(_wrapper.html()) I get
'<table data-react-toolbox="table">
<thead>
<tr>
<th>name</th>
</tr>
</thead>
<tbody>
<tr data-react-toolbox-table="row">
<td>type 1</td>
</tr>
<tr data-react-toolbox-table="row">
<td>type 2</td>
</tr>
</tbody>
</table>'
Which seems to be ok and which contains several tr.
Did I missed something ?
shallow will not "render" subcomponents. It is used to test a single component and not its children. I think that using mount instead of shallow will let you test what you want.
Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that your tests aren't indirectly asserting on behavior of child components.