Alert is undefined and 'findUser' variable is undefined - javascript

I'm trying to have a JavaScript function return the username of a given user id based into my function. I'm experiencing something very strange tonight - my ReactJS.NET scripts crash, mysteriously only on this particular function (although I can put Javascript alerts in many other parts of my React script, but not all without throwing the same error).
At first, I thought it could've been a binding issue - last time, when I tried binding a similar function in another JSX script, I found this happened because when I declared the function in the constructor of the parent React component with the name of the function slightly mispelled, it was happening all over the place.
Now I can't figure out anything close to what's truly happening with this problem. Here's the function that crashes in particular, either when I try to read the value passed in, or try to call a Javascript alert inside:
getUsername(UserId) {
if (!UserId) {
return;
}
else {
var stringCheck = String(Object.values(UserId));
if (this.usersCollection.data.find(item => item.userId === stringCheck)) {
var idx = this.usersCollection.data.findIndex(item => String(item.userId) == stringCheck);
return this.usersCollection.data[idx].userName;
}
else {
return "Nobody...";
}
}
}
I seem to be binding it properly in the constructor of the parent component, so I'm not sure what's happening:
class Queue extends React.Component {
constructor(props) {
super(props);
this.state = { data: this.props.initialData, closedData: this.props.closedData, selectedData: this.props.initialData };
this.handleTicketSubmit = this.handleTicketSubmit.bind(this);
this.toJavaScriptDate = this.toJavaScriptDate.bind(this);
this.userState = { data: this.props.userData };
this.usersCollection = { data: this.props.userDB };
this.getUsername = this.getUsername.bind(this);
this.serverMsg = { data: this.props.serverMsg };
this.srvMsgRst = { data: this.props.srvMsgRst };
this.showAllTickets = this.showAllTickets.bind(this);
this.showMyTickets = this.showMyTickets.bind(this);
this.checkServerMessage = this.checkServerMessage.bind(this);
}
Here's the render function from which the getUsername function is being passed to my TicketList component:
render() {
var anyClosedItems = this.state.closedData;
return (
<div className="queue">
<button class="btn btn-info active" id="allTix" onClick={this.showAllTickets}>All Tasks</button>
<button class="btn btn-info" id="myTix" onClick={this.showMyTickets}>My Tasks</button>
<h1>Affirm Queue</h1>
<TicketList data={this.state.selectedData} getTicket={this.props.navUrl} renderDate={this.toJavaScriptDate} checkUser={this.getUsername} />
<div id="noTixNotice" style={{display: 'none'}}><h3>There are no open tasks.</h3></div>
<hr/>
<h1>Closed Items</h1>
{anyClosedItems.length == 0 ? <div><h3>There are currently no closed items today.</h3></div> : <TicketList data={this.state.closedData} getTicket={this.props.navUrl} renderDate={this.toJavaScriptDate} checkUser={this.getUsername} />}
</div>
);
}
Finally, here's the ticketList component itself:
class TicketList extends React.Component {
render() {
const ticketNodes = this.props.data.map(ticket => (
<TicketRow key={ticket.id} ticketLoad={this.props.getTicket+"/"+ticket.id}>
<td>{ticket.summary}</td> <td> {ticket.description}</td><td>{this.props.renderDate({ value: ticket.currentApptTime })}</td><td>{this.props.checkUser({ UserId: ticket.userOwnerId })}</td>
</TicketRow>
));
const ticketRaw = this.props.data.map(ticket => (
<tr>
<td>{ticket.summary}</td><td>{ticket.description}</td><td>{this.props.renderDate({ value: ticket.currentApptTime })}</td><td>{ticket.userOwnerId}</td>
</tr>
));
return (
<div className="ticketList">
<table id="affirmTable" className="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Summary</th><th>Description</th><th>Appt Time</th><th>Owner</th>
</tr>
</thead>
<tbody>
{ticketNodes}
</tbody>
</table>
</div>
);
}
}
I still think it's probably a problem with the JavaScript function for some weird reason, because as soon as I comment everything inside of getUsername, it's fine, but when I try to load the page with ANY code (JavaScript alert for instance), the page will crash with the "undefined" message:
TypeError: Cannot read property 'find' of undefined
Can someone let me know what could be going on here? I'm pretty stumped.

Related

How do I give React methods to the onClick handler of an html component?

I'm trying to change the HTML received from a database to respond to custom onClick handlers. Specifically, the HTML I pull has divs called yui-navsets which contain yui_nav page selectors and yui_content page contents. I want to click an li in yui_nav, set that li's class to "selected", set the existing content to display:none, and set the new content to style="".
To do this, I have created a function updateTabs which inputs the index of the chosen yui and the new page number, set that li's class to "selected", set the existing content to display:none, and set the new content to style="". This function works: I tried running updateTabs(2, 3) in componentDidUpdate, and it worked fine, changing the content as requested. I want to assign updateTabs to each of the lis, and I attempt to do so in my componentDidMount after my axios request.
However, I keep getting the error: TypeError: this.updateTabs is not a function. Please help?
Page.js:
import React, { Component } from 'react';
import axios from 'axios';
class Page extends Component {
constructor(props) {
super(props);
this.state = {
innerHTML: "",
pageTags: [],
};
console.log(this.props.url);
}
componentDidMount() {
console.log(this.props.url);
axios
.get(
this.props.db_address + "pages?url=" + this.props.url,
{headers: {"Access-Control-Allow-Origin": "*"}}
)
.then(response => {
this.setState({
innerHTML: response.data[0].html,
pageTags: response.data[1]
});
console.log(response);
// Check for yui boxes, evade the null scenario
var yui_sets = document.getElementsByClassName('yui-navset');
if (yui_sets !== null) {
let yui_set, yui_nav, yui_content;
// Iterate through the navs of each set to find the active tabs
for (var yui_set_count = 0; yui_set_count < yui_sets.length; yui_set_count ++) {
yui_set = yui_sets[yui_set_count];
yui_nav = yui_set.getElementsByClassName('yui-nav')[0].children;
yui_content = yui_set.getElementsByClassName('yui-content')[0].children;
let tab_count;
// Give each nav and tab and appropriate ID for testing purposes
for (tab_count = 0; tab_count < yui_nav.length; tab_count ++) {
yui_nav[tab_count].onclick = function() { this.updateTabs(yui_set_count); }
yui_nav[tab_count].id = "nav-"+ yui_set_count.toString() + "-" + tab_count.toString()
yui_content[tab_count].id = "content-"+ yui_set_count.toString() + "-" + tab_count.toString()
}
}
}
})
.catch(error => {
this.setState({ innerHTML: "ERROR 404: Page not found." })
console.log(error);
});
}
updateTabs(yui_index, tab_index){
// Get all yuis
var yui_sets = document.getElementsByClassName('yui-navset');
let yui_set, yui_nav, yui_content
yui_set = yui_sets[yui_index];
yui_nav = yui_set.getElementsByClassName('yui-nav')[0].children;
yui_content = yui_set.getElementsByClassName('yui-content')[0].children;
// Identify the current active tab
var current_tab_found = false;
var old_index = -1;
while (current_tab_found == false) {
old_index += 1;
if (yui_nav[old_index].className === "selected") {
current_tab_found = true;
}
}
// Identify the new and old navs and contents
var yui_nav_old = yui_nav[old_index]
var yui_nav_new = yui_nav[tab_index]
var yui_content_old = yui_content[old_index]
var yui_content_new = yui_content[tab_index]
// Give the new and old navs and contents their appropriate attributes
yui_nav_old.className = "";
yui_nav_new.className = "selected";
yui_content_old.style = "display:none";
yui_content_new.style = "";
}
render() {
return (
<div className="Page">
<div className="Page-html col-12" dangerouslySetInnerHTML={{__html:this.state.innerHTML}} />
<div className="Page-footer">
<div className="d-flex flex-wrap btn btn-secondary justify-content-around">
{this.state.pageTags.map(function(pageTag){return(
<div className="pd-2" key={pageTag.id}>
{pageTag.name}
</div>
)})}
</div>
<div className="d-flex justify-content-center" >
<div className="p-2">Discuss</div>
<div className="p-2">Rate</div>
<div className="p-2">Edit</div>
</div>
<div className="d-flex justify-content-around App">
<div className="p-2">
Unless otherwise stated, the content
of this page is licensed under <br />
<a href="http://creativecommons.org/licenses/by-sa/3.0/"
target="_blank" rel="noopener noreferrer">
Creative Commons Attribution-ShareAlike 3.0 License
</a>
</div>
</div>
</div>
</div>
)
}
}
export default Page
Instead of function with function keyword use arrow functions and it will be solved as follows
You have
yui_nav[tab_count].onclick = function() { this.updateTabs(yui_set_count); }
But use
yui_nav[tab_count].onclick = () => { this.updateTabs(yui_set_count); }
Use this in componentDidMount method
You have to bind the updateTabs method in the constructor:
constructor(props) {
super(props);
...
this.updateTabs = this.updateTabs.bind(this);
}
You should use arrow functions in order to call this method with the correct contetxt:
yui_nav[tab_count].onclick = () => { this.updateTabs(yui_set_count); }

react throws type error for undefined object before ternary can check if object is undefined

LONG STORY SHORT: I would like for it to load the object in the nested array IF it is not equal to undefined but react throws typeError
I have this component that takes props from a parent component. Essentially I have an array that contains chat information and when I try to access it in this child component I get some very strange behaviour.
for example if I console log(props.conversations) I get my array which looks like this: conversations[{host, members[{ username }], log[{ author, content, timestamp }]}].
if I console log (props.conversations[0]) ill get the first object in that array. But if I console log (props.conversations[0].log) I get undefined. And thats fine because at the start the state will not be defined or contain anything, so I put a ternary operator as shown below in the code props.conversations[props.index].log[0] == null ?
but all i get is TypeError: Cannot read property 'log' of undefined at the ternary function.
Maybe I am not understanding this correctly or maybe it how react functions?
Again I would like for it to load the object in the nested array IF it is not equal to undefined.
Highly appreciate the help. The most important part is the friends component. I only show the other ones to show the state being passed down.
function Friends(props) {
console.log(props.conversations[props.index]);
return (
<div className="friend">
<img className="friendavatar" src={require("./static/bobby.jpg")}></img>
<div className="friendname">{props.username}</div>
<span className="iswatchingtitle"> is watching <strong>{props.watching}</strong></span>
<div className="friendchat" onClick={props.togglechat}>
{props.conversations[props.index].log[0] == null ?
<div>undefined</div>
:
<div>defined!</div>
}
</div>
</div>
)
}
social component
function Social(props) {
return (
<div>
<div className="userquickdash row">
<div className="usernamedash">{props.username}</div>
<div className="logout"><a href="/users/logout" onClick={props.fetchlogout}>logout</a></div>
</div>
<div>
<form className="search-form-flex" method="GET" action="/search">
<input className="user-search" id="search" type="search" placeholder=" Search users..." name="usersearch"></input>
</form>
</div>
<div className='friendchatcontainer' refs='friendchatcontainer'>
{/* Append friends from social bar state (props.friends). For each friend return appropriate object info to build Friends div using Friends(props) function above. */}
{props.friends.map(function(friend, index) {
// Shortens length of video title if length of string is over 48.
let friendWatching = function friendWatchingLengthSubstring() {
if (friend.watching.length > 57) {
let friendWatching = friend.watching.substring(0, 54) + '...';
return friendWatching;
} else {
friendWatching = friend.watching;
return friendWatching;
}
};
return (
<Friends username={friend.username}
watching={friendWatching()}
key={index}
index={index}
togglechat={props.togglechat}
conversations={props.conversations}
/>
)
})}
</div>
</div>
)
}
socialbar component
class Socialbar extends Component {
constructor(props) {
super(props);
this.state = { isLoggedIn: (cookies.get('loggedIn')),
sidebarximgSrc: sidebarcloseimg,
sidebarStatus: 'open',
username: cookies.get('loggedIn'),
friends: friends,
users: {},
conversations: [],
};
}
// function to run when mongodb gets information that state has changed.
// test if the current state is equal to new object array.
// then do something.
appendFriends() {
}
componentDidMount() {
if (this.state.sidebarStatus === 'open') {
document.getElementsByClassName('maindash')[0].classList.add('maindashwide');
this.openSideBar();
} else {
document.getElementsByClassName('maindash')[0].classList.remove('maindashwide');
this.closeSideBar();
}
// check for user logged in cookie, if true fetch users.
if (this.state.isLoggedIn) {
this.fetchUsers();
}
this.getFriendConversations();
};
getFriendConversations() {
// build loop function that updates state for conversations based on length of friends array in state.
var conversationsArray = this.state.conversations;
for (var i = 0; i < friends.length; i++) {
console.log(aconversationbetweenfriends[i]);
conversationsArray.push(aconversationbetweenfriends[i]);
}
this.setState({conversations: conversationsArray});
}
render() {
let sidebar;
const isLoggedIn = this.state.isLoggedIn;
if (!isLoggedIn) {
sidebar = <Login />
} else {
sidebar = <Social username={this.state.username} friends={this.state.friends} fetchlogout={this.fetchlogout} togglechat={this.togglechat} conversations={this.state.conversations} />
}
return (
<div>
<div className="sidebar sidebar-open" ref="sidebar">
<div className="sidebarcontainer">
{sidebar}
</div>
</div>
<div className="sidebarx sidebarxopen" ref="sidebarx" onClick={this.toggleSideBar}>
<img className="sidebaropenimg" src={this.state.sidebarximgSrc} ref='sidebarximg'></img>
</div>
</div>
);
}
};
It is not a good idea to access the element directly before validation.
Use something like this:
props.conversations[props.index] && props.conversations[props.index].log[0]
Tip: User object destructuring and default props.
You need to compare for undefined like this :
{props.conversations[props.index].log[0] === undefined ?
<div>undefined</div>
:
<div>defined!</div>
}
Also, You can go to below link for sandbox running example.
Sandbox link for example to show how you should check for undefined
Hi first of all check your {props.index} print this value. if it is proper then try this out.
{
props.conversations[props.index] ?
props.conversations[props.index].log[0] ? <div>defined!</div>:<div>Undefined</div>
:
<div>Undefined</div>
}
This will check if props.conversations[props.index] is defined then and then only try to process props.conversations[props.index].log[0]. So you will not get TypeError: Cannot read property 'log' of undefined at the ternary function.

Problem passing down function as a prop in ReactJs

class ReturnTempPassword extends React.Component {
constructor(props) {
super(props);
console.log(JSON.stringify(this.props));
}
render() {
return (
<div>
{ /* change code below this line */ }
<p>Your temporary password is: <strong>{}</strong></p>
{ /* change code above this line */ }
</div>
);
}
};
class ResetPassword extends React.Component {
constructor(props) {
super(props);
this.pwdGen = this.pwdGen.bind(this);
}
// returns a random string as password
pwdGen(m){
var m = m || 9, str="", r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';;
for(var i=0; i<m; i++) {
str+= r.charAt(Math.floor(Math.random()*r.length));
}
return str;
}
render() {
return (
<div>
<h2>Reset Password</h2>
<h3>We've generated a new temporary password for you.</h3>
<h3>Please reset this password from your account settings ASAP.</h3>
{ /* change code below this line */ }
<ReturnTempPassword data={"data"} pass={this.pwdGen} />
{ /* change code above this line */ }
</div>
);
}
};
I'm sending down a function as a prop and want to access it in the child component ReturnTempPassword. But data is available as prop but not pass. Not sure what am i doing wrong?
FYI, this is a freecodecamp task, which I'm trying to solve in my own way.
Link to task is here:
Please help me to correct the mistake.
you do everything right
Add a call your function
class ReturnTempPassword extends React.Component {
constructor(props) {
super(props);
console.log(JSON.stringify(this.props));
}
render() {
return (
<div>
{ /* change code below this line */ }
<p>Your temporary password is: <strong>{this.props.pass(5)}</strong></p>
{ /* change code above this line */ }
</div>
);
}
};
class ResetPassword extends React.Component {
constructor(props) {
super(props);
}
// returns a random string as password
pwdGen(m){
var m = m || 9, str="", r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';;
for(var i=0; i<m; i++) {
str+= r.charAt(Math.floor(Math.random()*r.length));
}
return str;
}
render() {
return (
<div>
<h2>Reset Password</h2>
<h3>We've generated a new temporary password for you.</h3>
<h3>Please reset this password from your account settings ASAP.</h3>
{ /* change code below this line */ }
<ReturnTempPassword data={"data"} pass={this.pwdGen} />
{ /* change code above this line */ }
</div>
);
}
};
And this code this.pwdGen = this.pwdGen.bind(this); are not needed
Update Since other people have provided solutions I can provide mine :)
In the task actually, they don't want you to create a random password text. They just want you to pass a "text" as a prop, named tempPassword. You want to use a function here. This is OK but I don't if it passes the test.
You can use this function in two ways.
You can pass it as a prop to the child.
You can use it directly in the parent.
Is there any specific reason you want to use in the child? I think, no.
So you can use it in the parent like:
<ReturnTempPassword pass={this.pwdGen()} />
and in the child:
<p>Your temporary password is: <strong>{this.props.pass}</strong></p>
As you can see since you can do it without passing your function to your child component. Also, you don't need to bind the function since it is not using this here, also it is not being called with a callback. It just a simple method and also can be totally separate from your class.
I've provided an example below like that. You don't need to pass the function as a prop here. In this way, you can use it anywhere. For example, you can put this function in a file then export it. When you need it, you can import it anywhere easily. This function doesn't need to belong to the class itself.
But, if you want to pass it as a prop, #mariamelior's answer shows how you can do this.
// returns a random string as password
function pwdGen(m) {
var m = m || 9,
str = "",
r = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < m; i++) {
str += r.charAt(Math.floor(Math.random() * r.length));
}
return str;
}
class ReturnTempPassword extends React.Component {
render() {
return (
<div>
{/* change code below this line */}
<p>
Your temporary password is: <strong>{this.props.pass}</strong>
</p>
{/* change code above this line */}
</div>
);
}
}
class ResetPassword extends React.Component {
render() {
return (
<div>
<h2>Reset Password</h2>
<h3>We've generated a new temporary password for you.</h3>
<h3>Please reset this password from your account settings ASAP.</h3>
{/* change code below this line */}
<ReturnTempPassword data={"data"} pass={pwdGen()} />
{/* change code above this line */}
</div>
);
}
}
ReactDOM.render(<ResetPassword />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Filter through a list to display data based on the status of user task

I am trying to filter through an array and display data based on the click event. There are three buttons that control different actions.
1.Button rollers display all the individuals who are rolling
2.Buttons non-rollers display lazy peeps who don't roll.
3.Buttons All display all the rollers and non-rollers.
I am trying to figure out if there is any way to display all rollers with the same filterRollers() function. I understand just resetting the state of rollingData back to the original value in a different function would do the trick but I am trying to limit to using one function. I will appreciate Any suggestion regarding the best practices . Thank you
var data =[
{ name="adam", task="roll" ,isrolling=true},
{ name="jack", task="roll" ,isrolling=false},
{ name="r2d2", task="roll" ,isrolling=true},
{ name="spidy", task="roll" ,isrolling=false}
]
this.state={
rollingState=data,
rollingData=data
}
filterRollers(status) {
let list = this.state.rollingState.filter(roll => {
return roll.isrolling === status
})
this.setState({
rollingData:list
})
}
render(){
return(
<div>
<button onClick={this.filterRollers(true)}>rollers </button>
<button onClick={this.filterRollers(false)}>non-rollers </button>
<button onClick={this.filterRollers(something)}> All </button>
{this.state.rollingData.map(roll=>{
return <Something roll={roll}/>
}
)}
</div>
)
}
When you want to show all the rollers, you can just call the function without any parameters. And then at the beginning of filterRollers function you can check if the parameter is undefined. If it is, just return all the data. If not, filter:
filterRollers(status) {
let list;
if(typeof status !== 'undefined'){
list = this.state.rollingState.filter(roll => {
return roll.isrolling === status
})
} else{
list = data.slice();
}
this.setState({
rollingData:list
})
}
Call the function like this, when you want to show all the rollers:
<button onClick={this.filterRollers()}> All </button>

Pull data from IndexedDB into array and output it via ReactJS

My actual Javascript code is the following:
var schoolsData = new Array();
myDB.schools
.each(function(school) {
console.log('"' + school.title + '" wird auf den Array gepusht.');
schoolsData.push(new Array(school.title, schools.schoolnumber, school.address, school.principal, school.email, school.creationdate, school.lastupdate, school.comment));
});
var SchoolsRender = React.createClass({
render: function() {
return (
<tr>
{this.props.list.map(function(listValue){
return <td>{listValue}</td>;
})}
</tr>
)
}
});
ReactDOM.render(<SchoolsRender list={schoolsData} />, document.getElementById('schoolsDATA'));
As you can see I am trying to pull data from my local IndexedDB database (I am using dexieJS) and put it via ReactJS into a table element but nothing appears. Where is the point?
Edit: I think the problem is basically that I'm trying to output that 3D array. Is there any simple and elegant solution?
Add another component RowRender to render single row. Modify SchoolsRender component accordingly.
var RowRender = React.createClass({
render: function() {
return (
<tr>
<td>{this.props.title}</td>
<td>{this.props.schoolnumber}</td>
<td>{this.props.address}</td>
<td>{this.props.principal}</td>
</tr>
)
}
});
var SchoolsRender = React.createClass({
render: function() {
return (
<table>
{this.props.list.map(function(listValue,index){
return <RowRender key={index} title={listValue.title} schoolnumber={listValue.schoolnumber} address={listValue.address} title={listValue.address} />;
})}
</table>
)
}
});

Categories