I need to develop an app for a conference and i'm trying to make this with Ionic2, AngularJS2 and Firebase.
I'm not starting from scratch, I clone this repository : https://github.com/driftyco/ionic-conference-app.
My repository : https://github.com/wowadrien/SFGP
My problem is that I need to filter the session first by day, next by room and then by theme so I add a level in the tree of my json to sort the session by room.
I've change the code of the data provider as this :
processData(data: any) {
this.data = data.json();
this.data.tracks = [];
// loop through each day in the schedule
this.data.schedule.forEach((day: any) => {
// loop through each timeline group in the day
day.groups.forEach((group: any) => {
// loop through each session in the timeline group
group.sessions.forEach((session: any) => {
//loop trough each subsession in the timeline session
session.subsessions.forEach((subsession: any) =>{
subsession.speakers = [];
if (subsession.speakerNames) {
subsession.speakerNames.forEach((speakerName: any) => {
let speaker = this.data.speakers.find((s: any) => s.name === speakerName);
if (speaker) {
subsession.speakers.push(speaker);
speaker.subsessions = speaker.subsessions || [];
speaker.subsessions.push(subsession);
}
});
}
if (subsession.tracks) {
subsession.tracks.forEach((track: any) => {
if (this.data.tracks.indexOf(track) < 0) {
this.data.tracks.push(track);
}
});
}
});
});
});
});
return this.data;
}
It doesn't work and i've tried about 20 differents solutions since last week but none of them was good.
I'm hopeless and lonely in this project so please, I need help !
Adrien
Related
so I am working on a command that makes like a vote embed, and it doesn't really work. when I use (in my case) $repvote #user it doesn't recognize the user or anything.., let me know for any solutions!
if (message.author.bot) return;
if (message.content.startsWith(prefix + "repvote")) {
if (!message.member.hasPermission("MANAGE_ROLES")) return message.channel.send('You do not have that permission! :x:').then(message.react('❌'));
let repUser = message.mentions.members.first()
if(!repUser) return message.channel.send("Please mention the user you want to setup the vote for!").then(message.react('❌')).then(msg => { msg.delete({ timeout: 5000 });
const repVoteEmbed = new Discord.MessageEmbed()
repVoteEmbed.setTitle("Vote for Representative Members :crown:")
repVoteEmbed.setDescription(`User ${repUser} wants to recieve Representative Members :crown: role! Do you agree?`)
repVoteEmbed.setFooter(`Vote by: ${message.author.tag}, started on : ${message.createdAt}`)
message.channel.send({repVoteEmbed}).then(message.react('✔')).then(message.react('❌'))
})
}})```
You missing message.channel.send(embed).then(msg =>....
Message channel send return a promise of the sent message, so you need use it to react
const Discord = require('discord.js');
const bot = new Discord.Client();
bot.on('message', async (message) => {
if (message.author.bot) return;
if (message.content.startsWith(prefix + 'repvote')) {
if (!message.member.hasPermission('MANAGE_ROLES')) return message.channel.send('You do not have that permission! :x:').then(message.react('❌'));
let repUser = message.mentions.members.first();
if (!repUser) {
message.channel.send('Please mention the user you want to setup the vote for!').then((declineMsg) => {
message.react('❌');
declineMsg.delete({
timeout: 5000,
});
});
return;
}
const repVoteEmbed = new Discord.MessageEmbed();
repVoteEmbed.setTitle('Vote for Representative Members :crown:');
repVoteEmbed.setDescription(`User ${repUser} wants to recieve Representative Members :crown: role! Do you agree?`);
repVoteEmbed.setFooter(`Vote by: ${message.author.tag}, started on : ${message.createdAt}`);
message.channel.send(repVoteEmbed).then((msg) => {
msg.react(`✔`).then(() => msg.react('❌'));
});
}
});
I've been trying to implement a method in which you can sort a leaderboard in different ways, by toggling a select element which changes the state, causing the component to re-render.
The problem is that, it can sort the default correctly, but whenever I change the value of the select from default to "z-to-a", it does not seem to be updating.
Note: I've added a few console.log statements, which seem to be behaving weirdly.
My JSX:
import React, { useState, useEffect } from 'react';
import './Leaderboard.css';
import LbRow from '../../components/LbRow/LbRow'; /* A row in the leaderboard*/
import points from '../../data/tree-points.json';
function Leaderboard() {
// Initialize the points as the data that we passed in
const [state, setState] = useState({
points: points,
sortBy: "first-to-last"
});
// Changes the sort method used by the leaderboard
const changeSortBy = (event) => {
var newSort = event.target.value;
// Sorts the data differently depending on the select value
switch(newSort) {
case "first-to-last":
sortDescending("points","first-to-last");
break;
case "z-to-a":
sortDescending("tree_name","z-to-a");
console.log(state.points.treePoints); // Logs incorrectly, still logs the same array as in "first-to-last"
break;
default:
sortDescending("points","first-to-last");
}
// Re-renders the component with new state
setState({
points: state.points,
sortBy: newSort
});
}
/* Updates the leaderboard state to be in descending point order */
const sortDescending = (aspect, sortMethod) => {
console.log(sortMethod); // Logs correctly
// Sorts the data in descending points order
let sortedPoints = [...state.points.treePoints].sort((tree1, tree2) => {
if (tree1[aspect] > tree2[aspect]) { return -1; }
if (tree1[aspect] < tree2[aspect]) { return 1; }
return 0;
});
// Actually updates the state
setState({
points: {
...state.points,
treePoints: sortedPoints
},
sortBy: sortMethod
});
console.log(sortedPoints); // Logs correctly
};
/* Calls sortLb on component mount */
useEffect(() =>{
sortDescending("points", "first-to-last");
}
,[]);
// Attributes used for rendering the leaderboard body
var rank = 0;
const sortedData = state.points;
/* Basically all the active trees with the first tree having the top rank */
const lbBody = sortedData.treePoints.map((sortedData) => {
return (
sortedData.active &&
<LbRow rank={++rank} tree_name={sortedData.tree_name} points={sortedData.points} active={sortedData.active}/>
);
});
return (
<div>
<div className="filters">
{/* Allows user to sort by different methods */}
<label htmlFor="sortBy">Sort by:</label>
<select name="sortBy" className="sortBy" value={state.sortBy} onChange={changeSortBy}>
<option value="first-to-last">First to Last</option>
<option value="z-to-a">Z to A</option>
</select>
</div>
{/* The table with sorted content */}
<div className="table">
{lbBody}
</div>
</div>
);
}
export default Leaderboard;
I'm really confused by this behavior, especially since I have the correctly sorted value and supposedly already updated the state. What could be causing this to happen? THanks
There are 3 things you must note
State updates are batched, ie. when you call setState multiple times within a function, their result is batched together and a re-render is triggered once
State updates are bound by closures and would only reflect in the next re-render and not immediately after calling state updater
State updates with hooks are not merged to you do need to keep merging all values in state yourself
Now since you wish to call the state updater twice, you might as well use the callback approach which will guarantee that your state values from multiple setState calls are not merged, since you don't need them to. Also you must update only the fields that you want to
function Leaderboard() {
// Initialize the points as the data that we passed in
const [state, setState] = useState({
points: points,
sortBy: "first-to-last"
});
// Changes the sort method used by the leaderboard
const changeSortBy = (event) => {
var newSort = event.target.value;
// Sorts the data differently depending on the select value
switch (newSort) {
case "first-to-last":
sortDescending("points", "first-to-last");
break;
case "z-to-a":
sortDescending("tree_name", "z-to-a");
break;
default:
sortDescending("points", "first-to-last");
}
// Re-renders the component with new state
setState(prev => ({
...prev,
sortBy: newSort // overrider just sortByField
}));
}
/* Updates the leaderboard state to be in descending point order */
const sortDescending = (aspect, sortMethod) => {
console.log(sortMethod); // Logs correctly
// Sorts the data in descending points order
let sortedPoints = [...state.points.treePoints].sort((tree1, tree2) => {
if (tree1[aspect] > tree2[aspect]) {
return -1;
}
if (tree1[aspect] < tree2[aspect]) {
return 1;
}
return 0;
});
// Actually updates the state
setState(prev => ({
...prev,
points: {
...state.points,
treePoints: sortedPoints
},
}));
};
/* Calls sortLb on component mount */
useEffect(() => {
sortDescending("points", "first-to-last");
}, []);
// Attributes used for rendering the leaderboard body
var rank = 0;
const sortedData = state.points;
...
}
export default Leaderboard;
Another better way to handle this to avoid complicated is to separate out your states into two useState
function Leaderboard() {
// Initialize the points as the data that we passed in
const [points, setPoints] = useState(points);
const [sortBy, setSortBy] = useState(sortBy);
// Changes the sort method used by the leaderboard
const changeSortBy = (event) => {
var newSort = event.target.value;
// Sorts the data differently depending on the select value
switch(newSort) {
case "first-to-last":
sortDescending("points","first-to-last");
break;
case "z-to-a":
sortDescending("tree_name","z-to-a");
console.log(state.points.treePoints); // Logs incorrectly, still logs the same array as in "first-to-last"
break;
default:
sortDescending("points","first-to-last");
}
// Re-renders the component with new state
setSortBy(newSort);
}
/* Updates the leaderboard state to be in descending point order */
const sortDescending = (aspect, sortMethod) => {
console.log(sortMethod); // Logs correctly
// Sorts the data in descending points order
let sortedPoints = [...state.points.treePoints].sort((tree1, tree2) => {
if (tree1[aspect] > tree2[aspect]) { return -1; }
if (tree1[aspect] < tree2[aspect]) { return 1; }
return 0;
});
// Actually updates the state
setPoints({
...state.points,
treePoints: sortedPoints
});
console.log(sortedPoints); // Logs correctly
};
/* Calls sortLb on component mount */
useEffect(() =>{
sortDescending("points", "first-to-last");
}
,[]);
// Attributes used for rendering the leaderboard body
var rank = 0;
const sortedData = points;
/* Basically all the active trees with the first tree having the top rank */
const lbBody = sortedData.treePoints.map((sortedData) => {
return (
sortedData.active &&
<LbRow rank={++rank} tree_name={sortedData.tree_name} points={sortedData.points} active={sortedData.active}/>
);
});
return (
<div>
<div className="filters">
{/* Allows user to sort by different methods */}
<label htmlFor="sortBy">Sort by:</label>
<select name="sortBy" className="sortBy" value={sortBy} onChange={changeSortBy}>
<option value="first-to-last">First to Last</option>
<option value="z-to-a">Z to A</option>
</select>
</div>
{/* The table with sorted content */}
<div className="table">
{lbBody}
</div>
</div>
);
}
export default Leaderboard;
Here is my problem.
I'm running a method that sends me a json (method = myTableService.getAllTables ()), to create an object (object = this.myTables).
Then I execute the method for each, for each element of this.myTables I execute a new request (request = this.myTableService.getTableStatut (element.theId)).
I retrieve data from a new json to create an object (object = myTableModel).
Each result will be added to this.myTableListProvisory.
The problem is the order of execution.
It execute the console.log before the end of the for each...
This.myTableListProvisory.length and this.myTableList.length return 0.
How to wait for the end of the for each run before running the console.log?
Thank you
ngOnInit() {
this.myTableService.getAllTables()
.subscribe(data => {
this.myTables = data;
this.myTableList = this.getAllTableStatut(this.myTables);
console.log("this.myTableList.length : " + this.myTableList.length);
}, err => {
console.log(err);
})
}
getAllTableStatut(myTables: any) {
this.myTableListProvisoire = [];
myTables.forEach(element => {
this.myTableService.getTableStatut(element.theId)
.subscribe(data => {
this.statut = data;
this.myTableModel = new MyTableModel(element.tableNumber, this.statut.name, element.theId);
this.myTableListProvisoire.push(this.myTableModel);
})
console.log("this.myTableListProvisoire.length : " + this.myTableListProvisoire.length);
})
return this.myTableListProvisoire;
}
Result of console.log
this.myTableListProvisoire.length : 0
this.myTableList.length : 0
UPDATE
I have simplified the code ... I put it in its entirety for the understanding. What I need is to sort the array after it is done. The problem is that I don't know how to use a flatMap method in a query inside a foreach ... I have temporarily placed the sort method inside the subscribe which is a bad solution for the performance. That's why I want to do my sort after the creation of the array. Thank you
export class MyTableComponent implements OnInit {
myTables: any;
statut: any;
myTableModel: MyTableModel;
myTableList: Array<MyTableModel>;
myTableListProvisoire: Array<MyTableModel>;
i: number;
j: number;
myTableModelProvisoire: MyTableModel = null;
constructor(public myTableService: MyTableService) { }
ngOnInit() {
this.myTableService.getAllTables()
.subscribe(data => {
this.myTables = data;
this.myTableList = this.getAllTableStatut(this.myTables);
}, err => {
console.log(err);
})
}
getAllTableStatut(myTables: any) {
this.myTableListProvisoire = [];
myTables.forEach(element => {
this.myTableService.getTableStatut(element.theId)
.subscribe(data => {
this.statut = data;
this.myTableModel = new MyTableModel(element.tableNumber, this.statut.name, element.theId);
this.myTableListProvisoire.push(this.myTableModel);
for (this.j = 0; this.j < this.myTableListProvisoire.length; this.j++) {
for (this.i = 0; this.i < this.myTableListProvisoire.length - 1; this.i++) {
if (this.myTableListProvisoire[this.i].getTableNumber() > this.myTableListProvisoire[(this.i + 1)].getTableNumber()) {
this.myTableModelProvisoire = this.myTableListProvisoire[this.i];
this.myTableListProvisoire[this.i] = this.myTableListProvisoire[(this.i + 1)];
this.myTableListProvisoire[(this.i + 1)] = this.myTableModelProvisoire;
}
}
}
}, err => {
console.log(err);
})
}, err => {
console.log(err);
})
return this.myTableListProvisoire;
}
}
Well Observables are asynchronous actions and will be executed after finishing the current execution block. So when the js engine comes to your
this.myTableService.getTableStatut(element.theId)
.subscribe(data => {
this.statut = data;
this.myTableModel = new MyTableModel(element.tableNumber, this.statut.name, element.theId);
this.myTableListProvisoire.push(this.myTableModel);
})
it will only create a subscription, but the code inside of it will be executed after all the other code in the block. So that's why your console.log is being executed before you get any data. So you need to place it inside the .subscribe block to see the. I think there can be a better solution to get the data, but I don't know the structure of the app, so I can't advice. If you create an example on https://stackblitz.com/ I could probably help you out with a better solution.
I have developed an app which basically has admin and client portal running in separate ports and when an order is placed from client side, the admin dashboard should be able to get the new order shown.
Basically the view has to be refreshed to keep an updated UI.
For which i have referred the below link:
http://beyondscheme.com/2016/angular2-discussion-portal
Below is what i have tried.
order-issue.component.ts
ngOnInit() {
const user_id = {
user_ids: this.user_id
};
// To display the Pending Orders into the table
this.orderService.getAllOrders("Pending").subscribe(data => {
if (data.success && data.Allorders.length != 0) {
for (let i = 0; i < data.Allorders.length; i++) {
this.orderService
.getOrderItemsByNo(data.Allorders[i].orderNo)
.subscribe(subData => {
data.Allorders[i].orderItems = subData;
});
}
this.source = data.Allorders; //To display the data into smart table
this.refreshData(); //For real time refresh
} else {
this.flashMessage.show("No Pending Orders", {
cssClass: "alert-success",
timeout: 300000
});
}
});
private refreshData(): void {
this.commentsSubscription = this.orderService.getAllOrders("Pending").subscribe(data => {
this.data = data;
console.log(data); //able to see the new orders
this.subscribeToData();
});
private subscribeToData(): void {
this.timerSubscription = Observable.timer(5000).first().subscribe(() => this.refreshData());
}
My service(orderService) will get all the orders:
getAllOrders(status) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(`${BASE_URL}/orders/getAllOrdersWithItems`, { status: status }, { headers: headers })
.map(res => res.json());
}
Ok i am able to fix it with below change.
//Function which refreshes the data in real time without page refresh
private refreshData(): void {
this.commentsSubscription = this.orderService.getAllOrders("Pending").subscribe(data => {
this.source = data.Allorders; //Updated here! and it worked
console.log(this.source);
this.subscribeToData(); //On success we call subscribeToData()
});
}
My server is supposed to send me back some data (stored as json) read when asked. To avoid blocking communications, I set-up 2 promises: one to read a file:
function readingfile(survey) {
return new Promise(
function (data_read, err) {
fs.stat(`./data/${survey}.json`, function (err, stat) {
if (err == null) {
fs.readFile(`./data/${survey}.json`, 'utf8', (err, data) => {
data_read((data))
})
} else
console.error(`./data/${survey}.json doesnt exist`)
})
})
}
and one to read all files from a user:
function readingusersurveys(user) {
let questionnaires = [];
let count = 0;
return new Promise(
function (data_read, err) {
user.surveys.forEach((survey) => {
readingfile(survey).then(function (all_surveys) {
count++;
//console.log((all_surveys)) //ok here
questionnaires.push((all_surveys))
if (count == user.surveys.length) {
console.log((questionnaires)) //not ok here (wtf)
data_read((questionnaires))
}
})
})
})
}
and the code snippet that send the data:
[...]
readingusersurveys(req.user).then(function (all_surveys) {
//console.log(all_surveys)
questionnaires.push((all_surveys))
console.log(questionnaires)
if (questionnaires != null) {
res.status(200).json({
questionnaires
});
} else {
res.status(500).json({});
}
})
but when readingusersurveys() return the data read, it get filled with tons of \r\n making the file unreadable. If I try to place a JSON.parse somewhere, I either: enter a infinite loop or the data become unreadable/undefined (eg: {"asset": ["value"]} become {"asset": [Object]}).
I have tried to place a JSON.parse pretty much everywhere to change comportement but no luck. Any idea how to get rid of \r\n and/or what's missing in my code ? :/
After many tries, I found out that it wasn't the JSON.parse the problem but questionnaire.push. It wasn't doing what I though it was doing(adding 2 json array together).
Added the JSON.parse here
function readingusersurveys(user) {
let questionnaires = [];
let count = 0;
return new Promise(
function (data_read, err) {
user.surveys.forEach((survey) => {
readingfile(survey).then(function (all_surveys) {
count++;
questionnaires.push(JSON.parse(all_surveys)) // <-- HERE
if (count == user.surveys.length) {
data_read((questionnaires)) //<-- array of JSON at this point
}
})
})
})
}
[...]
readingusersurveys(req.user).then(function (all_surveys) {
questionnaires = (all_surveys) //<-- pushing an array of JSON into another array was what created problems
if (questionnaires != null) {
res.status(200).json({
questionnaires
});
} else {
res.status(500).json({});
}
})
If I wanted to do a loop there and add more surveys, I needed to use concat() instead
if (questionnaires[0] == null)
questionnaires = all_surveys
else
questionnaires = questionnaires.concat(all_surveys)