Converting an Array of Strings to HTML using Reactjs - reactjs

can anyone help me with the proper way to iterate over an array of strings, that will then be placed in a paragraph tag using Reactjs?
The array looks something like:
names = [ "James", "Susan", "Frank" ];
Here is my react component called "Riders" (I've added comments for help on what I'm trying to do):
import React from 'react';
import { Drivers } from '../api/drivers';
// The 'this.props.names' contains an array of names: ["John", "Susan", "John"].
// How would I iterate over the array, pull the names from this array, and then
// have those names rendered in a paragraph tag in a manner like:
// <p>John - Susan - John</p>
// So far I've attempted using template strings and the braces, {} , javascript
// injection. Doing this renders an empty paragraph. Please let know of the proper
// way to complete this task. Any help would be greatly appreciated. :)
export default class Riders extends React.Component {
renderNames() {
let empty = ``
let names = this.props.names;
let namesLength = names.length;
for (var i = 0; i < namesLength; i++) {
empty[i] = empty + `-` + ` ${empty[i]}`
}
return empty;
}
render() {
return (
<div>
<p>{this.renderNames}</p>
</div>
);
}
}

You have some errors in your code.
First of all you need to call renderNames when rendering
<p>{this.renderNames()}</p>
Then renderNames implementation is incorrect.
empty is a string which are immutable in js. You can't mutate one using indices empty[i] = something
You should check that current element is not first. Since you don't want to insert separator before the first element
Whole loop is redundant. There is a special method join to join array of strings with a given separator.
So renderNames could be a simple as return this.props.names.join(' - ')

So this works now! Here's the implementation of the Join method as suggested by #Yury:
import React from 'react';
import { Drivers } from '../api/drivers';
export default class Riders extends React.Component {
renderNames() {
return this.props.riders.join(' - ');
}
render() {
return (
<div>
<p>{this.renderNames()}</p>
</div>
);
}
}
Reference to the "Join()" method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join?v=control

Have a look at the JS .map method https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map?v=control
With that you can just do something like:
let returnString = "";
this.props.names.map((item) => {
//TODO: add something to check if it's the last item
returnString += item + " - "
})

As indicated you should use {this.renderNames()}. Check the below example
export default class React.Component {
constructor(props) {
super(props);
}
renderNames() {
let empty = ``
let names = this.props.names;
let namesLength = names.length;
for (var i = 0; i < namesLength; i++) {
empty = empty + `-` + ` ${names[i]}`
}
return empty;
}
render() {
return(
<div>
{this.renderNames()}
</div>
)
}
}

Related

cannot parseInt in React project keep getting NaN

Ok, so I am currently trying to add items from an object together prices to be exact. When I try to actually parse the items with parseInt,I keep getting NaN.
I have tried to replicate it on repl.it and it works fine, also I have tried to use Number instead of parseInt and same results.
class Cart extends Component {
constructor(props) {
super(props);
this.add = this.add.bind(this);
}
componentDidMount() {
this.props.getCart();
}
add(array) {
let num = [];
let parse = [];
console.log(array);
for (let i = 0; i < array.length; i++) {
parse.push(array[i].price);
}
console.log(parse);
for (let i = 0; i < parse.length; i++) {
num.push(parseInt(parse[i]));
}
console.log(num);
let sum = num.reduce((acc, val) => {
return acc + val;
}, 0);
console.log(sum);
}
render() {
const { cart } = this.props.itemReducer;
this.add(cart);
I do have a few console.log's
first one does show my obj's
the second show's that I pulled my numbers in the variable["$379.99", "$1,499.99"]
the third one where I actually do the parseInt function is when i get [NaN, NaN]`
There is a $ sign in your string. Remove the sign and try
let nanNum = parseInt("$1477")
console.log(nanNum) //This will print NaN
let parsedNum = parseInt("$147,7.05".replace(/[^0-9\.]+/g,""))
console.log(parsedNum)
This is because of ["$379.99", "$1,499.99"], here items in array contains $ which is not a number (NaN) causing the error.
Instead of this,
num.push(parseInt(parse[i]));
You can do this,
num.push(Number(parse[i].replace(/[^0-9.]/g, "")));
Demo

React - How to separately assign click event to bunch of div's generated in loop

I am trying to create my own Game of Life in React. Currently have created a map with divs that will be separate cells in future when I finish my project. I also wanted to attach click event to each cell, but for some reason when I click single cell, the entire set of cells is affected. Can you please check why this happens? Also, can you please let me know if my approach is correct? Here is my index.js code:
class Board extends React.Component {
constructor(props){
super(props);
this.state = {isToggleOn: true};
this.changeState = this.changeState.bind(this);
}
changeState() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
createMap = (cols, total) => {
let table = []; let nL = ''; let idRow = 0; let idCol = 0;
for (let i = 0; i < total; i++) {
idCol++;
if (i%cols === 0){
nL = 'newLine';
console.log(i%cols);
idRow += 1;
idCol = 0;
}
else {
nL = '';
}
let toggledBackground = (this.state.isToggleOn ? 'test' : '');
table.push(<div id={"row-"+idRow+"-"+idCol} className={nL+" square "+toggledBackground} onClick={this.changeState}></div>);
}
return table;
}
render() {
return(
<div>
{this.createMap(COLS, FIELDS)}
</div>
);
}
}
All of them are highlighted because they all share the same state, the easiest solution would be to make a separate component for the squares and pass down the needed data as props.
This will allow you to have separate state for every single cell.
I assume FIELDS is the total number of cells (e.g for a 10x10 board, that would make FIELDS = 100). If that's the case, then you could bind the current index for each iteration to the said cell you are pushing in.
This way, you'll know which cell was clicked.
onClick={() => this.changeState(i)}
You'll also need to add a parameter to the actual function declaration, and save the state for that particular cell:
changeState(index) {
this.setState(prevState => {
let arr = prevState.cellStates.slice();
arr[index] = !arr[index];
return {cellStates: arr};
});
}
Of course, this requires you to have an array, not a single boolean:
this.state = {cellStates: Array(FIELDS).fill(false)};
and finally for your styles:
let toggledBackground = (this.state.cellStates[i] ? 'test' : '');

how to make sure two random numbers are not the same in javascript

I am learning React and Javascript, I am writing a small app that have 40 squares with different colors and every second 2 colors will randomly change, everything works fine but I have one minor problem. How can I change my code so that if two numbers are the same one of them will be regenerated? I tried to use if like this
import React from 'react';
import ReactDom from 'react-dom';
const totalColor=40;
const Box=(props)=>{...}
class RandomColorApp extends React.Component{
constructor(props){
super(props);
const boxes = new Array(totalColor).fill().map(this.randomColor,this);
this.state={boxes}
setInterval(()=>{
const randomIndex1=Math.floor(Math.random()*3)
const randomIndex2=Math.floor(Math.random()*3)
if(randomIndex1!==randomIndex2){
console.log(randomIndex1,randomIndex2)
}
},1000);
}
randomColor(){...}
render(){...}
}
RandomColorApp.defaultProps={colors:[...]}
ReactDom.render(<RandomColorApp/>,document.getElementById('app'));
but the problem is, the whole process will be delayed by 1 second before it regenerates new numbers, and also is there a way I can refactor the code so I do not have to repeat Math.floor(Math.random()*3) too much in case I need more than 2 random numbers, thank you verymuch
below is my full code just in case it can help
import React from 'react';
import ReactDom from 'react-dom';
const totalColor=4;
const Box=(props)=>{
const style={
width: '180px',
height: '180px',
display: 'inline-block',
backgroundColor: props.color
}
return <div style={style}/>
}
class RandomColorApp extends React.Component{
constructor(props){
super(props);
const boxes = new Array(totalColor).fill().map(this.randomColor,this);
this.state={boxes}
setInterval(()=>{
const boxes=this.state.boxes.slice();
const randomIndex1= Math.floor(Math.random()*boxes.length);
const randomIndex2= Math.floor(Math.random()*boxes.length);
boxes[randomIndex1]=this.randomColor();
boxes[randomIndex2]=this.randomColor();
this.setState({boxes});
//const randomIndex1=Math.floor(Math.random()*3)
//const randomIndex2=Math.floor(Math.random()*3)
//if(randomIndex1!==randomIndex2){
// console.log(randomIndex1,randomIndex2)
//}
},1000);
}
randomColor(){
let colorIndex=Math.floor(Math.random()*this.props.colors.length)
return this.props.colors[colorIndex];
}
render(){
const boxes=this.state.boxes.map((color,index)=>(
<Box key={index} color={color}/>
))
return(
<div className='RandomColorApp'>
{boxes}
</div>
);
}
}
RandomColorApp.defaultProps={...}
ReactDom.render(<RandomColorApp/>,document.getElementById('app'));
First define below function to generate a random number in the given range which is not equal to the except value.
randomNumber = (max, min, except) => {
let num = Math.floor(Math.random() * (max - min +1)) + min;
return (num === except) ? randomNumber(max, min, except) : num;
}
After that use below code in your setInterval() method
const randomIndex1 = randomNumber(0, totalColor, -1);
const randomIndex2 = randomNumber(0, totalColor, randomIndex1)
In this case, randomIndex1 will never be equal to randomIndex2
To get a list of distinct numbers, you can use an array and shuffle it:
a=new Array(10).fill(1);
a=a.map((x,i)=>i);
a=a.sort(()=>{return 2*Math.random()-1});
for (let i=0;i<a.length;i++) console.log(a[i]);
Ok, this function will take a rangeMin, rangeMax, and selectionCount, and return an array containing selectionCount unique values from the range. It will not validate that Min != max, etc. This is efficient for non-large values of (rangeMax - rangeMin), and is much more efficient than random selection and testing when selectionCount is a non-trivial portion of (rangeMax - rangeMin).
var getSelections = function( rangeMin, rangeMax, selectionCount ) {
// make array containing all values possible
var arr=Array.from({length: (rangeMax-rangeMin)+1 }, (v, k) => k+rangeMin);
arr=arr.sort(()=>{return 2*Math.random()-1}); // shuffle the array
return arr.slice( 0, selectionCount );
}
var values = getSelections( 1, 40, 2 );
console.log( "2 values from 1-40" );
console.log( values );
var morevalues = getSelections( 1, 8, 5 );
console.log( "5 values from 1-8" );
console.log( morevalues );
//declare an array to add the numbers
let myArr = [];
//loop through the array to add up to 6 numbers ()
while (myArr.length < 6){
//assign random number to a variable
let random = Math.floor(Math.random()* 25) + 1;
//check if the number assigned to the variable exist in myArr[]
if(myArr.indexOf(random) > -1) {
console.log('Matching number ' + random + ', getting a new one');
//if number exist don't push the number and go back to the head of while loop
continue;
}
//if number doesn't exist push it to end of myArr[]
myArr.push(random);
}
console.log(myArr);

Angular2 #Injectable not working

I have an #Injectable class with a get-function in Service.ts create. This function should return one Array and also get any array. But it returns null. If I write this directly in a #Component, then it does get the array. What am I doing wrong?
service.ts
#Injectable()
export class Arr_selected {
private arr = [];
get(arr_selected: any[]){
for(let key in arr_selected) {
if (arr_selected.hasOwnProperty(key)) {
this.arr.push([key]);
return this.arr;
}
}
console.log(this.arr);
}
}
component.ts
import {Arr_selected} from './service.ts';
export class Component implements DoCheck, OnChanges, OnInit {
....
constructor( public arr_selected: Arr_selected)
.....
ngOnInit{
let chk = this.ChkBoxValue;
let arr = [];
/// **this not working Array is null**/////
arr=(this.arr_selected.get(this.ChkBoxValue));
/// **this is working Array is not null**////
for (let key in this.ChkBoxValue) {
if (this.ChkBoxValue.hasOwnProperty(key)) {
arr.push(this.ChkBoxValue[key]);
}
}
console.log(arr);
}}
i thinks below should work
#Injectable()
export class Arr_selected {
get(arr_selected: any[]){
arr = [];
for(let key in arr_selected) {
if (arr_selected.hasOwnProperty(key)) {
arr.push([key]);
return this.arr;
}
}
console.log(this.arr);
}
I think the "this" operator is causing the problem for you . You have arr also defined in the component . this might be conflicting which arr to use.
Above code you have written your file name as service.ts
and importing from ./servece.ts
import {Arr_selected} from'./servece.ts;
May be its typing error here ,
also are you adding your service in provider of component ?.

AS3 array indexOF

I am working on a game and have trouble with this array. There is all fruits on the stage which is generated from the array fruit. When the appel will hit the basket, we will count them. The melon is not to be counted. How do i find out if the current fruit is an appel or a melon?
var array_fruit:Array = new Array(appel1_mc, appel2_mc, melon_mc);
var appelsOnstage:Array = new Array();
var appelsCollected:Number = 0;
for (var i:int = 0; i<10; i++) {
var pickappels = array_fruit[int(Math.random()* array_fruit.length)];
var spel_appels:MovieClip = new pickappels();
addChild(spel_appels);
spel_appels.x = (Math.random() * 800) + 100;
spel_appels.y = Math.random() * -500;
spel_appels.speed = Math.random() * 10 + 2;
appelsOnstage.push(spel_appels);
}
stage.addEventListener(Event.ENTER_FRAME, catchappels);
function catchappels(e:Event):void {
for (var i:int = appelsOnstage.length-1; i > -1; i--) {
var currentfruit:MovieClip = appelsOnstage[i];
if (currentfruit.hitTestObject(basket_mc)) {
if(array_fruit.indexOf(currentfruit) == melon_mc ){
trace("melon");
} else {
trace("no melon");
appelsCollected++;
}
}
}
}
a_fruit.indexOf(currentfruit) = -1 all the time
The problem here is the confusion between classes and objects.
a_fruit holds classes, which are to be instantiated by this code
var pickappels = array_fruit[int(Math.random()* array_fruit.length)];
var spel_appels:MovieClip = new pickappels();
appelsOnstage holds objects of those classes and is filled here
appelsOnstage.push(spel_appels);
Classes and objects are - excuse the pun! - apples and oranges, very different things.
A class is like a blueprint for a building or a recipe for a meal. You cannot compare objects with classes and expect them to be the same.
Instead, you should find the class of an object, and then compare this class to another class. For this, you use the is operator. Something like
if(currentfruit is melon_mc)
should do the trick to tell you if you have a melon or not.
indexOf is going to return an int value. See my edit to your code below.
if (currentfruit.hitTestObject(basket_mc)) {
if(array_fruit.indexOf(currentfruit) == 2 ){
trace("melon");
} else {
trace("no melon");
appelsCollected++;
}
}
indexOf takes two arguments. The first is the exact element you are searching for. The second argument is the index position to start the search from. The default is position 0.
See the API documentation here. (Always good to give these a quick read first).
You should use is operator here, for better coding. What if you'd change the positions of classes in your arrays?
if ((currentfruit is appel1_mc) || (currentfruit is appel2_mc)) {
// apple
}
Just in pseudo code to figure a possible way to deal with this issue.
On the timeline :
import com.fruits.Fruit;
import com.fruits.Melon;
import com.fruits.Apple
var fruit_1:Melon = new Melon();
var fruit_2:Apple = new Apple();
if(fruit_1 is Melon){
trace("anyway my SuperclassName is : " + fruit_1.getType());
trace (fruit_1.getMyType());
trace("");
}
if(fruit_2 is Apple){
trace("anyway my SuperclassName is : " + fruit_2.getType());
trace (fruit_2.getMyType());
trace("");
}
in com.Fruit.as :
package com.fruits {
public class Fruit {
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
public function Fruit() {
trace ("I'm a Fruit");
}
public function getType():String{
var type:String = getQualifiedSuperclassName(this)
var str:String = (type);
return str;
}
}
}
In com.Melon :
package com.fruits {
public class Melon extends Fruit {
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
public function Melon() {
super();
trace ("Melon says : ");
trace (" because I'm Fruit and not happy to be a Melon");
trace("");
}
public function getMyType():String{
var type:String = getQualifiedClassName(this)
var str:String = ("Im a " + type);
trace("Class said : I worth nothing because I'm an Fruit and not proud to be an Melon");
str += "\n" + "but in fact I'm a " + getQualifiedSuperclassName(this)
return str;
}
}
}
In com.Apple :
package com.fruits {
public class Melon extends Fruit {
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
public function Melon() {
super();
trace ("Melon says : ");
trace (" because I'm Fruit and not happy to be a Melon");
trace("");
}
public function getMyType():String{
var type:String = getQualifiedClassName(this)
var str:String = ("Im a " + type);
trace("Class said : I worth nothing because I'm an Fruit and not proud to be an Melon");
str += "\n" + "but in fact I'm a " + getQualifiedSuperclassName(this)
return str;
}
}
}
This is just an idea, tell me more about your target and if this may help You...
Best regards Nicolas.
PS : I'm sorry but my English is really bad. so I tried to figure me the issue...
You may perhaps forget about indexOf and use addChild anytime You want to set an object/instance over another one....
So You don't have to check about the indexes.
addChild(some old Child) will make the "old Child" be on the the last index (over the other instances).
Sorry I didn't wrote your code but the title said that you want to check if the fruit is a Melon or an Apple...
Sorry if I misunderstood. :(

Resources