var statement throwing error in react.js - reactjs

So im trying to create a counter to determine if a verticle bar should be rendered in my component but everytime I try to create the counter variable outside of the map function it throws an error:
return (
<div className={css.classNames.div} style={css.styles.div}>
{ var counter = [];
this.props.children.map(function(child){
counter.push('1')
if (counter.length !== this.props.children.length){
return <li className={css.classNames.list}>{child}</li>;
} else {
return <li className={css.classNames.list}>{child}</li>;
}
}.bind(this))
}
</div>
);
There must be a way to do it. Does anyone know the problem?

Move the var counter = []; to before the return.
var counter = [];
return (
<div className={css.classNames.div} style={css.styles.div}>
{this.props.children.map(function(child){
counter.push('1')
if (counter.length !== this.props.children.length){
return <li className={css.classNames.list}>{child}</li>;
} else {
return <li className={css.classNames.list}>{child}</li>;
}
}.bind(this))}
</div>
);

Related

React Loop Through FileList and Display

I am trying to loop through a FileList in React and not having any luck.
I have read this article on Can't use forEach with Filelist and with it's help I am able to print to the console. And this Loop inside React JSX article to help with the loop part however I am not able to display any results.
renderEligibilityDocs(e) {
var proctorDocChanges = this.state.proctorDocChanges;
var files = proctorDocChanges[313];
console.log("files", files);
if (files) {
var post = Array.from(files).forEach(file => {
return (
<div key={file.name}>
<h2>file: {file.name}</h2>
</div>
);
});
Array.from(files).forEach(file => console.log("Print to Console " + file.name));
return <div>
{post}
</div>;
} else {
return <div>
<span>No Files Uploaded</span>
</div>;
}
}
What is the concept that I am missing to display the files in the H tag?
If you want to capture or render the output you should use map instead of forEach.
forEach executes a function for each element but it doesn't do anything with the return values, whereas map builds an array from them.
if (files) {
return Array.from(files).map(file => {
return (
<div key={file.name}>
<h2>file: {file.name}</h2>
</div>
);
});
}
else {
...
}
The forEach method doesn't return anything. This is fine for your second loop where you just want to do a console.log, but your first loop needs to return something - you should use map there.
You can also move the map statement into the return statement:
if (files) {
return (
<div>
{Array.from(files).map(f => (
<h2 key={f.name}>file: {f.name}</h2>
)}
</div>
)
}

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 get distinct value using lodash in ReactJS?

How to get distinct value using lodash in ReactJS? Now I'm getting all the data. But how to avoid printing duplicate data? Actually it is a filter box. So data repetition I've to avoid. Can anyone help me out?
Function:
comboClick () {
var apiBaseUrl = "http://api.eventsacross-stage.railsfactory.com/api/";
var input = this.state.search_event;
let self = this;
axios.get(apiBaseUrl+'v1/events/?on_dashboard=false'+input)
.then(function (response) {
let events = response.data.events;
self.setState({events: events});
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
Jsx Part:
<div className="dropdown text-center">
<button
className="btn btn-default dropdown-toggle"
type="button"
data-toggle="dropdown"
style={{width: "50%"}}
onClick={this.comboClick.bind(this)}>
Place
<span className="caret"></span>
</button>
<ul className="dropdown-menu">
{this.state.events.map(function (event, i) {
return (
<div key={i}>
{event.locations.map(function (locations, j) {
return (
<li key={j}><p>{locations.city}</p></li>
)
})}
</div>
)
})}
</ul>
</div>
You can use _.uniqBy, as per documentation:
This method is like _.uniq except that it accepts iteratee which is
invoked for each element in array to generate the criterion by which
uniqueness is computed. The order of result values is determined by
the order they occur in the array. The iteratee is invoked with one
argument: (value).
I've added an example:
var locations =
[
{city:"city1"},
{city:"city2"},
{city:"city3"},
{city:"city1"},
];
var locationsUnique = _.uniq(locations, 'city');
console.log(locationsUnique);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
UPDATE:
From the method shared in the comments I'm guessing that what you want to do is something like:
comboClick() {
var apiBaseUrl = "api.eventsacross-stage.railsfactory.com/api/";
var input = this.state.search_event;
let self = this;
axios.get(apiBaseUrl + 'v1/events/?on_dashboard=false' + input).then(function(response) {
let events = response.data.events;
for (var i = 0; i < response.data.events_count; i++) {
var obj = response.data.events[i];
console.log(obj.locations);
//Assuming that obj.locations has the locations that you want to display
var locationsUnique = _.uniq(obj, 'city'); //Added this line
console.log(locationsUnique); //Added this line
}
for (var j = 0; j <= obj; j++) {}
self.setState({events: events});
}).catch(function(error) {
console.log(error);
});
}

Display element in angular based on condition in array of objects

I have the following element.
<div> My element</div>
and the following object:
$scope.myObject = {'life_log' : [{status: 'ALIVE'},{status: 'DEAD'}]}
How can I display the element ONLY if all status is ALIVE.
I know how to use ng-show on a variable but what about a condition like this?
You'll have to create a function that loops through your array and checks if all the statuses are 'ALIVE'. Or just use a reduce method on the array:
$scope.allStatusesAreAlive = $scope.myObject.life_log.reduce(function(a, b) {
if (a === false) return false;
if (b.status === 'DEAD') return false;
return true;
}, true);
Then you can display your element if $scope.allStatusesAreAlive is true:
<div ng-if="allStatusesAreAlive"> My element</div>
You can do something like this
angular.forEach($scope.myObject.life_log, function(item){
if(item.status !=='ALIVE'){
$scope.isAlive = false;
break;
}else{
$scope.isAlive = true;
}
});
then in your html
<div data-ng-if="isAlive">My element</div>
Check the following link
https://plnkr.co/edit/ermeKk1dBX8D54pL7vHQ?p=preview
angular code:
$scope.myObject = {'life_log' : [{status: 'ALIVE'},{status: 'DEAD'}]}
$scope.val=true;
for(i=0;i<$scope.myObject.life_log.length;i++){
if($scope.myObject.life_log[i].status != "ALIVE")
$scope.val=false;
}
html code:
<div ng-show="val">My element</div>
// This is here to make it configurable
$scope.keys = Object.keys($scope.myObject);
// In this case you have the "life_log" key
$scope.keys.forEach(k => {
$scope.myObject[k].forEach((d) => {
// our object here is myObject["life_log"];
// obj is a temp array to check the amount of statuses that are dead
var obj = [];
d["allAlive"] = d.status.forEach( s =>{
if(s == 'DEAD'){
obj.push("Dead");
}
});
if(obj.length > 0){
d.allAlive = false
}else{
d.allAlive = true;
}
});
});
<div ng-if="myObject[o].allAlive>
ALL ALIVE
</div>

InfiniteScroll - AngularJS not working

Edit:
Just for checking purposes, I also did a console.log inside the nextPage function, to check if it's being triggered:
$scope.nextPage = function() {
var captureLength = $scope.captures.length;
console.log('TRIGGER');
if($scope.busy) {
return;
}
...
}
};
And it seems I'm getting a infinite loop, but I can't see why.
=================================
I'm trying to implement infinitescroll into a view but for some reason it's only loading the initial 4 images and not triggering the rest.
Here is my code:
CTRL:
/* ----------------------- Variables ----------------------- */
$scope.auth = auth;
$scope.captures = [];
$scope.following = [];
$scope.allData = [];
$scope.busy = true;
var page = 0;
var step = 4;
$scope.nextPage = function() {
var captureLength = $scope.captures.length;
if($scope.busy) {
return;
}
$scope.busy = true;
$scope.captures = $scope.captures.concat($scope.allData.splice(page * step, step));
page++;
$scope.busy = false;
if($scope.captures.length === 0) {
$scope.noMoreData = true;
}
};
/* ----------------------- Process Data ----------------------- */
$q.all({follows: findFollow(), users: getUsers(), captures: getAllCaptures()}).then(function(collections) {
var follows = collections.follows;
var users = collections.users;
var captures = collections.captures;
follows.filter(function(follow) {
return follow.follower_id === auth.profile.user_id;
}).forEach(function(follow) {
users.filter(function(user) {
return user.user_id === follow.followed_id;
}).forEach(function(user) {
$scope.following.push(user);
});
});
follows.filter(function(follow) {
return follow.follower_id === auth.profile.user_id;
}).forEach(function(follow) {
captures.filter(function(capture){
return follow.followed_id === capture.userId;
}).forEach(function(capture){
console.log(capture);
$scope.allData.push(capture);
});
});
$scope.nextPage();
$scope.busy = false;
});
/* ----------------------- Retrieve Services - Data ----------------------- */
function findFollow() {
return userApi.findFollow().then(function(res) {
return res.data;
});
}
function getUsers() {
return userApi.getUsers().then(function(res) {
return res.data.users;
});
}
function getAllCaptures() {
return captureApi.getAllCaptures().then(function(res) {
return res.data;
});
}
Partial:
<div class="col-md-8">
<div class="well main-well">
<h3 class="page-header-h3">Following Dashboard:</h3>
<hr />
<h4 align="center" ng-show="!captures.length">
<strong>The people that you are following, have not posted anything yet.. Yikes!</strong>
<br /><br />
Quickly, go follow more people!</h4>
<div class="row" infinite-scroll="nextPage()" infinite-scroll-disabled="busy || noMoreData" infinite-scroll-distance="0.1">
<ul class="dynamic-grid" angular-grid="captures" ag-id="gallery">
<li data-ng-repeat="capture in captures | orderBy :'created_at':true" class="grid">
<a ui-sref="detail({id: capture._id})">
<img ng-src="{{capture.picture}}" class="grid-img" />
<span class="follow-capture-info">
<span class="follow-capture-name"><span class="glyphicon glyphicon-user"></span>
{{capture.author}}
<span class="following-capture-time">ยท
<span class="glyphicon glyphicon-time"></span>
<span am-time-ago="capture.created_at"></span>
</span>
</span>
</span>
</a>
</li>
</ul>
</div>
<div ng-show="busy">Loading more...</div>
</div>
Anyone know where I went wrong?
Thanks.

Resources