Click on browser's back button doesn't work - javascript

My main component Portal.js is as follows :
class Portal extends React.Component {
render() {
const language = this.props.currentLanguage.default;
const allShowrooms = data.getAllLists();
return (
<div className="mainPortal">
<Navigation type="status" />
<Showrooms allLists={allShowrooms} language={language}/>
</div>
);
}
}
When this page loads allShowrooms is as follows:
allShowrooms = [
{
id: 1,
name: "All brands stock sale mei",
expires: "Sat Oktober 01 2016 15:58:59 GMT+0200",
type: "Fixed"
}, {
id: 2,
name: "List number Two",
expires: "Sat November 05 2016 23:59:59 GMT+0200",
type: "Fixed"
}, {
id: 3,
name: "List number Three",
expires: "Tue November 29 2016 23:59:59 GMT+0200",
type: "Unfixed"
}
]
When I click on one of the links in the navigation it goes to the new page. That works fine.
The problem is when I click on back in my browser, to go back to Portal. Then allShowrooms is changed to :
[
{
"id":3,
"name":"All brands stock sale mei",
"expires":"Sat Oktober 01 2016 15:58:59 GMT+0200",
"type":"Fixed"
},
{
"id":3,
"name":"List number Two",
"expires":"Sat November 05 2016 23:59:59 GMT+0200",
"type":"Fixed"
},
{
"id":3,
"name":"List number Three",
"expires":"Tue November 29 2016 23:59:59 GMT+0200",
"type":"Unfixed"
}
]
Thus, the ID for all lists inside allShowrooms is changed to 3. Why??
And then I have problem when I show photos, and the values in the circles, because I get those values via list id. I now, for all lists I have values of the list with id 3.
When I refresh the page, everything is ok.
Any advice?
Update
Data file (from where I get allShowroom = data.getAllLists())
let allLists = [
{
id: 1,
name: "All brands stock sale mei",
expires: "Sat Oktober 01 2016 15:58:59 GMT+0200",
type: "Fixed"
}, {
id: 2,
name: "List number Two",
expires: "Sat November 05 2016 23:59:59 GMT+0200",
type: "Fixed"
}, {
id: 3,
name: "List number Three",
expires: "Tue November 29 2016 23:59:59 GMT+0200",
type: "Unfixed"
}
];
export function getAllLists(){
return allLists;
}
UPDATE 2
Showrooms component is as follows :
render(){
const language = this.props.currentLanguage;
return (
<div>
{this.props.allLists.map( (list, i) => <View key={i} list={list} language={language}/>)}
</div>
)
}
And View component is as follows :
render (){
const list = this.props.list;
const url = list.id;
const remainingTime = this.props.remainingTime;
const language = this.props.language;
return (
<div className="block">
<div className="listName">{list.name}</div>
<div className="listBody">
<div className="counter"> {remainingTime.days} days {remainingTime).hours} : {remainingTime.minutes} : {remainingTime.seconds}</div>
<Circles language={language} list={list} />
<Status list={list}/>
</div>
<Link to={`/showroom/${url}/`}>{language.portal.openShowroom}</Link>
</div>
)
}
And then Circles component
render(){
let {list, language} = this.props;
const allCars = data.getAllCars(); //We get list of all cars
const cars = carData.getCarsInCurrentList(list.id, allCars); //We get all cars, but only from this list
const totalCarsInTheList = cars.length;
const statusTotalCars = data.getUserOnGoingStatus().filter(s => s.listID === list.id && s.userID === userInfo.getUserEmail()).length;
return (
<div className="circles-box">
<div className="circle-left">
<div className="circle-content">
<div className="circle-total-cars">{totalCarsInTheList}</div>
<div className="circle-subtitle">{language.portal.nrCars}</div>
</div>
</div>
<div className="circle-right">
<div className="circle-content">
<div className="circle-total-cars">{statusTotalCars}</div>
<div className="circle-subtitle">{language.portal.status}</div>
</div>
</div>
</div>
);
}

if data.getAllLists();is synchronous stuff you can do something like this. Avoid logic in your render, it has to be more pure as possible.
class Portal extends React.Component {
constructor (props, context) {
super(props, context);
this.allShowrooms = data.getAllLists();
this.language = props.currentLanguage.default;
}
render() {
return (
<div className="mainPortal">
<Navigation type="status" />
<Showrooms allLists={this.allShowrooms} language={this.language}/>
</div>
);
}
})

Related

how to arrange images according to date with blockwise in reactjs?

How to arrange the images according to date in blocks? It should show the images with particular date with block and date as header for each block.
import React from "react";
import { MDBContainer, MDBRow, MDBCol } from "mdbreact";
import './App.css';
class App extends React.Component {
state = {
photoIndex: 0,
isOpen: false,
images: [
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(117).jpg", mdate: "9 Jul 2019 3:56 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(98).jpg", mdate: "9 Jul 2019 12:14 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(131).jpg", mdate: "9 Jul 2019 12:14 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(123).jpg", mdate: "9 Jul 2019 12:14 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(118).jpg", mdate: "8 Jul 2019 4:49 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(132).jpg", mdate: "8 Jul 2019 4:48 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(132).jpg", mdate: "8 Jul 2019 4:47 pm"},
{path: "https://mdbootstrap.com/img/Photos/Horizontal/Nature/12-col/img%20(118).jpg", mdate: "1 Jul 2019 1:51 pm"}
]
}
renderImages = () => {
let photoIndex = -1;
const { images } = this.state;
return images.map(imageSrc => {
photoIndex++;
const privateKey = photoIndex;
return (
<MDBCol md="4" key={photoIndex}>
<p style={{marginBottom:"5px"}}> {imageSrc.mdate}</p>
<figure>
<img src={imageSrc.path} alt="Gallery" className="img-fluid" onClick={()=>
this.setState({ photoIndex: privateKey, isOpen: true })
}
/>
</figure>
</MDBCol>
);
})
}
render() {
return (
<MDBContainer className="mt-5">
<div className="mdb-lightbox no-margin">
<MDBRow>
{this.renderImages()}
</MDBRow>
</div>
</MDBContainer>
);
}
}
export default App;
The current output is:
Display images of the that particular date.Date as header and related images of that date it should display below to it.

ReactJS - nested loops with map js

I'm trying to have a nested map but i'm getting an undefined error.
So i'm passing the profile props to Link router in navbar.jsx, profile: this.state.profile. Then I fetching the data in profilePage.jsx, where I want to pass the data in an element.
Profile json has 3 components -> experience, education, and skills. So i need to have a nested loop for the data to show up in the element. For example; calling `{experience.company} so the company name will show up.
When i called the profile page, in the console i see profile.experience getting called but then it goes undefined:
(3) [{...}, {...}, {...}] "passing"
undefined "passing"
I tried different ways, splitting the json components but still getting the same error. I know it's mapping issue but I'm not sure if I'm missing something, maybe in React; new to React so learning as much as I can through errors. Your help will be appreciated!
Eventually I want the profile page to look like this:
Education
Company A
August 2016 - present
salesman
Company B
Feb 2016 - August 2016
developer
Company C
August 2012 - October 2015
clerk
Education
school A
fall 2015
mathematics
school B
may 2008
business
Skills
tools: html, css, js, sql
profilePage.jsx
import React, { Component } from "react";
import ProfileItem from "./profileItem"
class Profile extends Component {
render(){
// let profile = this.props.location.profile.map((experience) => <li>{experience.experience}</li>);
// console.log(profile);
const experience = this.props.location.profile.map((profile,idx) => {
console.log(profile.experience, 'passing');
return profile.experience.map((experience,idx) =>
<div>
<p key={idx}>{experience.company}</p>
</div>
);
});
}
}
export default Profile;
navbar.jsx
import React, { Component } from "react";
import { Link } from "react-router-dom";
class Navbar extends Component {
constructor(props){
super(props);
this.state = {
profile: [
{'experience': [
{
'company': 'company A',
'date': 'August 2016 - Present',
'jobTitle': 'salesman'
},
{
'company': 'company B',
'date': 'February 2016 - August 2016',
'jobTitle': 'Developer'
},
{
'company': 'company C',
'date': 'August 2012 - October 2015',
'jobTitle': 'clerk'
}
]},
{'education': [
{
'school': 'shcool A',
'date': 'Fall 2015',
'degree': 'mathematics'
},
{
'school': 'school B',
'date': 'May 2008',
'degree': 'business'
}
]},
{'skills': [
{
'Tools': 'HTML, CSS, Javascript, SQL, Python'
}
]}
],
experience: [],
education: [],
skills: []
};
}
render(){
return (
<div className="navFrame">
<Link to="/">
<div className="topNav"><div className="navBar"><h3>name</h3></div></div>
</Link>
<Link to="/projects">
<div className="rightNav"><div className="navBar"><h3>Projects</h3></div></div>
</Link>
<Link to="/contact">
<div className="bottomNav"><div className="navBar"><h3>Contact</h3></div></div>
</Link>
<Link to={{pathname: '/profile', profile: this.state.profile}}>
<div className="leftNav"><div className="navBar"><h3>Profile</h3></div></div>
</Link>
</div>
);
}
}
export default Navbar;
Try to run this on browser's console =>
From your given Json:
var response = {profile: [
{'experience': [
{
'company': 'company A',
'date': 'August 2016 - Present',
'jobTitle': 'salesman'
},
{
'company': 'company B',
'date': 'February 2016 - August 2016',
'jobTitle': 'Developer'
},
{
'company': 'company C',
'date': 'August 2012 - October 2015',
'jobTitle': 'clerk'
}
]},
{'education': [
{
'school': 'shcool A',
'date': 'Fall 2015',
'degree': 'mathematics'
},
{
'school': 'school B',
'date': 'May 2008',
'degree': 'business'
}
]},
{'skills': [
{
'Tools': 'HTML, CSS, Javascript, SQL, Python'
}
]}
],
experience: [],
education: [],
skills: []
}
when we try to run response.profile.map() it will iterate over all the elements present in this array
response.profile.map(ele => console.log(ele)) will give 3 elements i.e. experience, education and skills
now within an inner block of your code when you will iterate over this element for the first time you will get experience key as defined but for next two iterations it will fail since the key is not present. you can add a filter in between the way I've done below !
const experience = this.props.location.profile
.filter(profile => profile.hasOwnProperty("experience"))
.map((profile, idx) => {
return profile.experience.map((experience, idx) => (
<div>
<p key={idx}>{experience.company}</p>
</div>
));
});
Hope this might help !

Detailed Explanation on how to use ListView renderSectionHeader

const users =
[
{
name: "Joy soap",
customerName: "Salomy",
date: "19 March 2018",
time: "08:46am",
amount: 3000,
status: "paid",
number: 24,
images:
"https://snack1.amazonaws.com/~asset/9d799c33cbf767ffc1a72e53997218f7"
},
{
name: "Closeup tooth paste",
customerName: "Salomy",
date: "19 March 2018",
time: "08:46am",
amount: 3000,
status: "paid",
number: 20,
images:
"https://1.amazon4d99c3d76575cc03c2a7f816280"
},
{
name: "Iman Powder",
customerName: "Emanbe",
date: "20 March 2018",
time: "11:25am",
amount: 3000,
status: "paid",
number: 12,
images:
"https://1.amazonaws.com/~asset/ee06c63d01543a44631c3421df6ee5fa"
},
{
name: "John Bellion",
customerName: "Okonkwo Chioma",
date: "20 March 2018",
time: "08:46am",
amount: 3000,
status: "paid",
number: 3,
images:
"https://sn1.amazonaws.com/~asset/ee06c63d01543a44631c3421df6ee5fa"
}
];
Please I have an array of objects like the above that I want to render in a ListView with a Section Header function pointing to user.date... I want it to render a list of all the items on 19 March 2018, and then render the items on 20 March 2018 under the header also.
I have used ListView several times but I have never been able to use the section header in this way with the above arrays of object. Please a detailed explanation would be greatly appreciated. I know its probably a simple task to some of you but please be kind. I need a renderSectionHeader() function that can organize the data with respect to their dates so I can render it in my listview like this
`<ListView
ref={ref => (this.scrollView = ref)}
onContentSizeChange={() => {
this.scrollView.scrollToEnd({ animated: false});
}}
dataSource={this.state.userDataSource}
renderRow={this.renderRow.bind(this)}
renderSectionHeader={this.renderSectionHeader.bind(this)}
/>`
An example of what I want is here but I want to know how it can be done with the above array
ListView is no longer available in React-Native. You can use FlatList. Its very simple then ListView as well.
1) Import FlatList from react-native:
import { FlatList } from 'react-native';
2) Copy Below code into your render() method.
<FlatList
horizontal={true/false}
style={YOUR_COSTOM_STYLE}
data={YOUR_ARRAY}
renderItem={this.renderItem.bind(this)}
keyExtractor={(item, index) => String(index)}
/>
3) You do necessary stuff for your cell in renderItem method.
// Render Methods
renderItem({ item }) {
return (
// DO_YOUR_STUFF
);
}
You can more detail about FlatList from here.
One more example for header in FlatList

How to display html content dynamically when clicking a button in ReactJS?

I have made 2 buttons and 1 input box which displays date from JSON data. When I click on increment or decrement buttons it should display the data.available_slots[0].data_slots
If data.available_slots[this.state.counter].data_slots === 0 then it should display "No slot available today" besides input box.
data.js:
const data = {
"template_type": "slot_picker",
"selection_color": "#000000",
"secondary_color": "#808080",
"title": "Available Slots for Dr. Sumit",
"available_slots": [
{
"date": "Wed, Dec 06",
"date_slots": [
]
},
{
"date": "Thu, Dec 07",
"date_slots": [
]
},
{
"date": "Fri, Dec 08",
"date_slots": [
]
},
{
"date": "Sat, Dec 09",
"date_slots": [
]
},
{
"date": "Today",
"date_slots": [
{
"hour": "8",
"hour_slots": [
{
"08:10 AM": "slotId001"
},
{
"08:50 AM": "slotId005"
}
]
},
{
"hour": "3",
"hour_slots": [
{
"03:00 PM": "slotId005"
},
{
"03:30 PM": "slotId007"
}
]
}
]
},
{
"date": "Tomorrow",
"date_slots": [
]
},
{
"date": "Wed, Dec 13",
"date_slots": [
{
"hour": "4",
"hour_slots": [
{
"04:30 PM": "slotId105"
},
{
"04:50 PM": "slotId106"
}
]
},
{
"hour": "5",
"hour_slots": [
{
"05:30 PM": "slotId202"
},
{
"05:45 PM": "slotId208"
}
]
}
]
}
]
};
export default data;
datepicker.js:
import React, { Component } from 'react';
import data from './data';
import './datepicker.css';
class DatePicker extends Component {
constructor(props){
super(props);
this.state = {
counter:0
};
}
increment(){
if(this.state.counter < 6){
this.setState(prevState => ({counter: prevState.counter + 1}))
}
if(data.available_slots[this.state.counter].data_slots === 0){
return(
<p>No slots available for today</p>
)
}else{
return(
<p>Slots available for today</p>
)
}
}
decrement(){
if(this.state.counter > 0){
this.setState(prevState => ({counter: prevState.counter-1}))
}
if(data.available_slots[this.state.counter].data_slots === 0){
return(
<p>No slots available for today</p>
)
}else{
return(
<p>Slots available for today</p>
)
}
}
render() {
return (
<div>
<div id="center">
<div className="title">
<p>Pick a Date</p>
</div>
<div className="increment">
<button type="button" className="btn btn-success" id="plus" onClick={this.increment.bind(this)}>+</button>
</div>
<div className="display">
<input type="text" id="date" value={data.available_slots[this.state.counter].date}/>
</div>
<div className="decrement">
<button type="button" className="btn btn-danger" id="minus" onClick={this.decrement.bind(this)}>-</button>
</div>
<div className="submit">
<button type="button" class="btn btn-primary" id="submit">Set Date</button>
</div>
</div>
<div id="slotinfo">
</div>
</div>
);
}
}
export default DatePicker;
When I click on plus/minus buttons for that day it should display if the slot is available for that day or not. So the increment() and decrement() functions are not returning the <p> elements besides input box.
Screenshot:
increment and decrement functions are just returning the <p> elements and doesn't know where to display them.
Move the logic to render "No slots available for today" or "Slots available for today" inside the render function based on the state variable this.state.counter. The logic inside increment and decrement methods can be removed.
increment(){
if(this.state.counter < 6){
this.setState(prevState => ({counter: prevState.counter + 1}))
}
}
decrement(){
if(this.state.counter > 0){
this.setState(prevState => ({counter: prevState.counter - 1}))
}
}
And in the render function,
<div id="slotinfo">
{ data.available_slots[this.state.counter].date_slots.length === 0 ?
<p>No slots available for today</p> : <p>Slots available for today</p> }
</div>

window.open is not working in IE to download an event

I'm trying to create an ICS file on click of buttons inside each of my divs.
This works fine in Chrome and Firefox. However, it fails to work on IE.
What's wrong with the code in 'window.open'?
Also, how do I change the name of th file based on the event ID?
Here's the code
angular.module('myApp', []).controller('myCtrl', function($scope){
$scope.card = [{
Name: "New Year Celebration",
Description: "",
Venue: "",
StartDate: "Fri Dec 29 2017 23:30:00 GMT+0530",
EndDate: "Sat Dec 30 2017 00:30:00 GMT+0530",
EventID: "1"
}, {
Name: "25th Anniversary Celebration",
Description: "25th Anniversary Celebration of organization",
Venue: "Auditorium",
StartDate: "Wed May 31 2017 17:30:00 GMT+0530",
EndDate: "Wed May 31 2017 20:30:00 GMT+0530",
EventID: "2"
}, {
Name: "Annual Day",
Description: "",
Venue: "",
StartDate: "Fri Oct 13 2017 14:30:00 GMT+0530",
EndDate: "Fri Oct 13 2017 17:30:00 GMT+0530",
EventID: "3"
}];
$scope.add = function(eventObj) {
$scope.eventID= this.eventObj.EventID;
$scope.startDate= this.eventObj.StartDate;
$scope.endDate= this.eventObj.EndDate;
$scope.venue= this.eventObj.Venue;
$scope.subject= this.eventObj.Name;
$scope.result= this.eventObj.Description;
//console.log(this);
$scope.icsMSG = "BEGIN:VCALENDAR\nVERSION:2.0\nBEGIN:VEVENT\nDTSTART:" + $scope.startDate +"\nDTEND:" + $scope.endDate +"\nLOCATION:" + $scope.venue + "\nSUMMARY:" + $scope.subject + "\nDESCRIPTION:"+ $scope.result +"\nEND:VEVENT\nEND:VCALENDAR";
window.open("data:text/calendar;charset=utf8," + escape($scope.icsMSG),"_self");
};
});
.event {
height: 150px;
width: 250px;
border: 1px solid lightgrey;
background-color: skyblue;
margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="eventObj in card" class="event">
Subject: <span>{{eventObj.Name}}</span>
<br /><br />
Venue:<span>{{eventObj.Venue}}</span>
<br /><br />
Date:<span>{{eventObj.StartDate | date:'fullDate'}}</span>
<br /><br />
<button ng-click="add(eventObj.EventID)">Add to Outlook</button>
</div>
</div>
Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements in IE.
The solution is to use navigator.msSaveBlob to generate the file and prompt the user to save it. Refer this answer
You could also use something like downloadify instead of data URLs (would work for IE as well) as mentioned here

Categories