Make React Properties not Tied to Specific Variables - reactjs

I'm trying to create a group of react elements through a for loop. However, it seems that, rather than each element getting its own copy of the variables per for loop, they are tied to whatever the variable is at the end of the for loop (where i = 3). How can I prevent this. Thanks.
makeCheckboxes() {
var checkboxes = [];
for(var i = 0; i < this.props.flagNames.length; i++) {
console.log("Making checkbox. i = " + i);
checkboxes.push((
<React.Fragment>
<label><input type="checkbox" name="reportFlags" value="fraud" checked={this.state.reportFlags[i]} onClick={() => this.handleCheck(i)}/>{this.props.flagNames[i]} </label><br />
</React.Fragment>
));
}
return checkboxes;
};

just replace
for(var i = 0; i < this.props.flagNames.length; i++) {
by
for(let i = 0; i < this.props.flagNames.length; i++) {
actually it will create a closure, so it should sove the problem
if you still want to use var you can change your code like this using immediately-invoked function expression iife
for(var i = 0; i < this.props.flagNames.length; i++) {
console.log("Making checkbox. i = " + i);
checkboxes.push((
<React.Fragment>
<label>
<input
type="checkbox"
name="reportFlags"
value="fraud"
checked={this.state.reportFlags[i]}
onClick={((j) => () => this.handleCheck(j))(i)} //here is the iife
/>
{this.props.flagNames[i]}
</label><br />
</React.Fragment>
));
}
return checkboxes;

Related

I wanted to create multiple dynamic input fields in reactjs

<div id="options-container"></div>
<script>
function createInputElements(num) {
const optionsContainer = document.getElementById("options-container");
for (let i = 0; i < num; i++) {
const input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("placeholder", `Input ${i + 1}`);
optionsContainer.appendChild(input);
}
}
const option = 3;
createInputElements(option);
</script>
This is javascript code to create multiple input fields dynamically based on option numbers and wanted to write in react js
You use the useState to do so:
const[option,setOption]=useState(3);
let output=[];
for (let i=0;i<option;i++){
output.push(<input key={"input_"+i} type="text" placeholder={"Input "+(i + 1)}/>)
}
return (
<div id="options-container">
{output}
</div>
);

push object to array of arrays vue re-rendering failing

I have this weird issue where I can't seem to push an object to an array of arrays.
I am able to log the value of groups....but I can't update it.
here's my function to push to the groups array under a given set of conditions
calcExclusion: function(){
this.hideExclusionGroups = true //hides the exclusion groups from app before calculations
for(var i = 0; i < this.exclusionGroups.length; i++){
if(this.numberOfGroups < this.exclusionGroups.length){
alert('could not calculate, there are more exclusion groups than groups')
return
}
for(var j = 0; j < this.exclusionGroups[i].students.length; j++){
if(this.exclusionGroups[i].students.length == 1){
alert ('could not calculate, groups must be bigger than 1')
return
}
//console.log('group number', g,'student to add',this.exclusionGroups[i].students[j])
if(j < this.numberOfGroups){
this.groups[i].push(this.exclusionGroups[i].students[j].first_name)
console.log(this.groups[i])
}
}
}
},
here is where I render the data
<div v-for="(group, index) in groups" class="d-inline-block bg-white p-2 m-2 border rounded">
<span>Group {{ index + 1 }}</span>
<ul>
<li class="groupItems" v-for="student in group">
{{ student.first_name }}
<input type="hidden" :name="'group['+index+']'" :value="student.id">
</li>
</ul>
</div>
I am able to edit 'groups' to some extent but groups is referencing the computed prop here
computed: {
groups: function () {
if(! Number.isInteger(this.numberOfGroups)) {
console.log('mal');
return [];
}
const array = [];
for (let j = 0; j < this.numberOfGroups; j++) {
array[j] = [];
}
let i = 0;
this.students.forEach((student) => {
const x = i % this.numberOfGroups;
if(student.include === false){
array[x].push(student);
}
i++;
});
return array;
},
},
You are updating the results of a computed property. The result is not reactive, that's why you see that your code is updating the groups array, but you don't see any changed in the DOM.
You need to move the logic from calcExclusion inside the computed method for groups.

How to use conditional to generate element on the page

for (var k = 0; k < 10; k++) {
if (k % 2 === 0) {
weatherText = <div className="in_break">
}
weatherText += <div className="eachD" key={k}>
<div>
{
countIt === 0 ? (currDate.getHours() > 12 ? "Tonight" : "Today") : dayOfWeek[weekDay]
}
</div>
<div>
{
getDate
}
</div>
<div>
{
<ReturnIcon />
}
</div>
</div>
if (k % 2 === 0) {
weatherText += </div>
}
}
What I am looking to do is group all the eachD by two inside the `in_break' div
But I keep getting:
Parsing error: Unexpected token 'weatherText = </div>'
This is the layout:
in_break
eachD
eachD
in_break
eachD
eachD
in_break
eachD
eachD
...
Please help me resolve my issue
UPDATED
I hope this find it's way to your demand:
setWeatherTextItems = (countId, currDate, dayOfWeek, weekDay, getDate) => {
// you make sure all the variables such like countId and currDate are available inside this function.
const items = [];
for (var k = 0; k < 10; k++) {
items.push(
<div className="eachD" key={k}>
<div>
{countIt === 0
? currDate.getHours() > 12
? "Tonight"
: "Today"
: dayOfWeek[weekDay]}
</div>
<div>{getDate}</div>
<div>{<ReturnIcon />}</div>
</div>
);
}
return items;
}
renderInBreak = () => {
const items = this.setWeatherTextItems();
const inBreakItems = [];
let breakBlock = [];
let newBreak = false;
items.forEach((textItem, index) => { //1
if(!newBreak) {
breakBlock.push(textItem);
if(index + 1 === items.length){
inBreakItems.push(breakBlock);
}
} else {
inBreakItems.push(breakBlock);
breakBlock = [];
breakBlock.push(textItem);
//without this condition check, the last element will be left out of an odd array length
if(index + 1 === items.length) {
inBreakItems.push(breakBlock)
}
}
if(index % 2) newBreak = true; //false
else newBreak = false; //false
});
return inBreakItems.map(twoTextWeatherItems => (
<div className="in_break">
{twoTextWeatherItems}
</div>
))
}
render(){
<div>
{this.renderInBreak()}
</div>
}
OLD
React is supposed to handle things differently, maybe this will work:
Define a method in your component that will set your items:
setWeatherTextItems = (countId, currDate, dayOfWeek, weekDay, getDate) => {
// you make sure all the variables such like countId and currDate are available inside this function.
const items = [];
for (var k = 0; k < 10; k++) {
items.push(
<div className="eachD" key={k}>
<div>
{countIt === 0
? currDate.getHours() > 12
? "Tonight"
: "Today"
: dayOfWeek[weekDay]}
</div>
<div>{getDate}</div>
<div>{<ReturnIcon />}</div>
</div>
);
}
return items;
}
in your render method, or where you are willing to render these items:
render(){
<div className="in_break">{this.setWeatherTextItems()}</div>
}
Read more about how to render things in a loop.
You can add the conditions you want inside the for loop, or where it makes sense to you.
Not sure if the logic would work in a react environment but as far as I can see from your plain code when you are going to add the 'in_break' div aren't you just assigning the whole whetherText again instead of joining text to it?
Shouldn't this:
if (k % 2 === 0) {
weatherText = </div>
}
be written like this?
if (k % 2 === 0) {
weatherText += </div>
}
Edit following the typo correction:
I tried to run your code on codepen to have a quicker and easier understanding on how to find a solution.
I created an helper function with your code then I returned
<div className="Container" dangerouslySetInnerHTML={{__html: weatherText}}></div>
This enables you to have the result you are looking for. Only the even elements have the 'in_break' class.
Hope this helped and let me know if this is not correct.
Codepen: https://codepen.io/dpgian/pen/EBzRmX

How to dynamically use object property as width in AngularJS (in ng-repeat)?

I cannot get the object's property to be read in ng-style(shape.radius || shape.length). I can't even get 1 to work at the moment, but would like to have an or statement included. Similar to my ng-class.
There is a button to generate shapes, and the shapes were created with a random size. Here is my code:
html:
<div ng-controller='ShapeController as sc'>
<div>
<p><input type="submit" value="Generate Random Shapes" ng-click="sc.generateShapes()"/></p>
<div ng-repeat="shape in sc.shapes">
<div class="shape" ng-class="{circle: shape.radius, square: shape.length}" ng-style="{'width': shape.length}"></div>
</div>
</div>
</div>
script:
var app = angular.module('app', []);
app.controller('ShapeController', function(){
var vm = this;
vm.shapes = [];
vm.randomShapes = [];
vm.width = 30;
function createCircle(radius) {
let circle = new Circle(radius);
vm.shapes.push(circle);
} // end createCircle
function createSquare(length) {
let square = new Square(length);
vm.shapes.push(square);
} // end createSquare
vm.generateShapes = function() {
let times = 50
for (let i = 0; i < times; i++) {
createCircle(getRandomNumber());
}
for (let i = 0; i < times; i++) {
createSquare(getRandomNumber());
}
sort(vm.shapes);
console.log(vm.shapes);
}; // end generateShapes
}); // end controller
function sort(arr) {
arr.sort(function(a,b){
return b.getArea() - a.getArea();
});
} // end sort function
function getRandomNumber() {
return Math.random() * (100-1) + 1;
}
width should be either in px(some unit like em, pt, etc) or %
ng-style="{'width': shape.length + 'px'}"

Angularjs: Filtering using multiple combobox directives on the same data set

I'm trying to use a directive twice and filter using the options created by the directives. For some reason the chemicalsFilter isn't working as expected. If I use either of the filters on the ng-repeat it works but using both together isn't working. I'm wondering if this could be a scope issue within the directives but each seem to return the correct data. It outputs in the console as I expect but the filtering just doesn't work as expected.
Any ideas? If I can get this sorted it will be so much easier creating multiple combo boxes in my project.
This is my example plnkr:
http://plnkr.co/edit/FTPdSSiKSOZiWptfJzuC?p=preview
Original example (both examples do the same thing):
http://democode.6te.net/filterusingdirectives/
<div ng-controller="resultsCtrl">
<div ng-controller="chemicals">
<combo-box url="/filterusingdirectives/php/getChemicals.php" list-name="Select Chemicals" loading-message="loading chemicals ..." combo-box-directive-selected-values="getSelectedChemicalValues"></combo-box>
</div>
<div ng-controller="letters">
<combo-box url="/filterusingdirectives/php/getLetters.php" list-name="Select Letters" loading-message="loading letters ..." combo-box-directive-selected-values="getSelectedLetterValues"></combo-box>
</div>
<div ng-repeat="result in results | chemicalsFilter:selectedChemicalValues | lettersFilter:selectedLetterValues">
letterId: {{result.letterId}}
<br />
chemicalId: {{result.chemId}}
<br />
name: {{result.name}}
<br /><br />
</div>
</div>
inner loops must be replaced with respective selected("selectedLetterValues and selectedChemicalValues") values instead of results.
lettersFilter :
for (var i = 0; i < results.length; i++) {
for (var j = 0; j < selectedLetterValues.length; j++) {
.......
}
}
chemicalsFilter :
for (var i = 0; i < results.length; i++) {
for (var j = 0; j < selectedChemicalValues.length; j++) {
.......
}
}
Updated :
I don't see any other issue apart from logic. May be you have debugged it and thought why filters is executing multiple times, might be this is an issue. here is the explanation
Why your code is not working?
when you click Acetic acid ( for sake of comfort we will go with letterId only)
in chemicalsFilter(results, selectedChemicalValues):
input results=[letterID:10, letterId:20, litterId:30]
selectedChemicalValues=[letterId:20, litterId:30]
for (var i = 0; i < results.length; i++) {
for (var j = 0; j < results.length; j++) {
.......
}
}
output filteredResults = [letterId:20, litterId:30]
in lettersFilter(filteredResults, selectedLetterValues):
input results=[letterId:20, litterId:30]
selectedLetterValues=[letterID:10, letterId:20, litterId:30]
for (var i = 0; i < results.length; i++) {
for (var j = 0; j < results.length; j++) {
.......
}
}
output filteredResults = [letterId:20]
In lettersFilter both outer loop and inner loop are checking size on results.length so it will never get chance to compare 3rd index, so it retruns 2nd index which contains Acetone

Resources