Data passed to handlebars template not showing in the client side - html

I passed a viewData to the handlebar template like this
app.get('/employee/:value', (req, res) => {
let viewData = {};
dataService.getEmployeeByNum(req.params.value).then((data) => {
if (data) {
viewData.employee = data;
} else {
viewData.employee = null;
}
}).catch(() => {
viewData.employee = null;
}).then(dataService.getDepartments).then((data) => {
viewData.departments = data;
for (let i = 0; i < viewData.departments.length; i++) {
if (viewData.departments[i].departmentId == viewData.employee.department) {
viewData.departments[i].selected = true;
}
}
}).catch((err) => {
console.log(err);
viewData.departments = [];
}).then(() => {
if (viewData.employee == null) {
res.status(404).send("Employee not found");
} else {
res.render("employee", { layout: 'main', viewData: viewData })
}
})
});
and try to use it in the client side like this but ain't showing at all
<h2>{{viewData.employee.firstName}} {{ viewData.employee.lastName}} - Employee: {{ viewData.employee.employeeNum}}</h2>
I created an helper function to stringify the viewData object and this showed
{"employee":[{"employeeNum":3,"firstName":"Foster Lewa","lastName":"Billy","email":"louis.jessica86#gmail.com","SSN":"935-74-9918","addressStreet":"8 Midway Park","addressCity":"New York","addressState":"NY","addressPostal":"111","maritalStatus":null,"isManager":true,"employeeManagerNum":1,"status":"Full Time","department":3,"hireDate":"12/02/1999"}],"departments":[{"departmentId":1,"departmentName":null},{"departmentId":2,"departmentName":null},{"departmentId":3,"departmentName":"New Department"}]}
But never worked in the client side (html), what could be wrong ?

Try this one.
<h2>{{viewData.employee.1.firstName}} {{ viewData.employee.1.lastName}} - Employee: {{ viewData.employee.1.employeeNum}}</h2>

The viewData was passed as an array to the template and here is what I did to get the values
<h2>{{viewData.employee.[0].firstName}} {{ viewData.employee.[0].lastName}} - Employee: {{ viewData.employee.[0].employeeNum}}</h2>
Thanks!

Related

*ngIf display then undisplay

I write this after asking that: Observable need a click to load on html page
The solution was good but the problem now is that I have every same id display because precedently I did :
getFeederArray(): Observable<Array<string>> {
let toReturn: Array<string> = [];
var subject = new Subject<Array<string>>();
this.getUser().subscribe(user => {
this.orders = this.db.collection("orders", ref => {
return ref
.where("clientId", "==", user.id)
}).valueChanges({ idField: 'id' }) as Observable<Order[]>;
this.orders.subscribe(orders => {
orders.forEach(order => {
if(toReturn.indexOf(order.feederId) == -1) { <---- to not have twice the same order
toReturn.push(order.feederId);
}
})
})
subject.next(toReturn);
})
return subject.asObservable();
}
And now I have :
getFeederArray(): Observable<string[]> {
return this.getUser().pipe(
switchMap((user) => {
this.orders = this.db
.collection("orders", (ref) => ref.where("clientId", "==", user.id))
.valueChanges({ idField: "id" }) as Observable<Order[]>;
return this.orders;
}),
map((orders) => orders.map((order) => order.feederId))
);
}
Which no need a click no more, so the display is normal, but we can have twice the same order.
So I tried in my html :
<section class="mobile" fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="20px" *ngFor="let id of _feedersId | async">
<div *ngIf="this.isAlreadyDisplayed(id)">
{{ cl(id) }}
<app-feeder-card
[feederId] = "id"
[clientId] = "this.uid"
></app-feeder-card>
</div>
</section>
With those functions in the .ts:
// push in array
pushAlreadyDisplayed(str: string) {
this.alreadyDisplayed.push(str);
}
// boolean already displayed
isAlreadyDisplayed(str: string): boolean {
const bool = this.alreadyDisplayed.includes(str);
if(bool) {
return !bool;
} else {
this.pushAlreadyDisplayed(str);
return !bool;
}
}
cl(str: string) {
console.log(str);
}
But a problem occurs : my page well console.log the ids (and that's good, there is no twice the same), but this part in the HTML :
{{ cl(id) }}
<app-feeder-card
[feederId] = "id"
[clientId] = "this.uid"
></app-feeder-card>
is only showed for less than 1 second and than disapear...
I don't understand why, and so I don't know how to solve my problem...
Thank you for your time
Well, when you use pushAlreadyDisplayed() you make changes to alreadyDisplayed.
This thing cus to re-render the component, and on the 2nd iteration the ID is
marked as arealy renderd aleady.
A better solution is to reduce the array from the duplicates

I have an issue with circular reference to JSON using reactjs

I want to serialize circular reference to JSON
This is the part generating the JSON array and it causes a circular reference because it creates a child inside an element and I want to display the result.
const mappedData = this.state.treeData
.filter(data => data.title === "Category")
.map(categ => {
const { id, title, children, subtitle, type } = categ;
function getChildren(children) {
return children
? children.map(child => {
if (child.title === "Item" || child.title === "Group") {
const data = {
id: child.id,
name: child.subtitle,
type: child.type,
children: getChildren(child.children),
child_id: child.children
? child.children.map(child => child.id)
: []
};
if (data.children.length === 0) delete data.children;
if (data.child_id.length === 0) delete data.child_id;
return data;
} else {
return {
id: child.id,
name: child.subtitle,
type: child.type
};
}
})
: [];
}
const data = {
id: id,
name: subtitle,
type: type,
children: getChildren(children),
child_id: children ? children.map(child => child.id) : []
};
if (data.children.length === 0) delete data.children;
if (data.child_id.length === 0) delete data.child_id;
return data;
});
The HTML part that calls the stringify method
<div className="json">
<p> {JSON.stringify(mappedData)}</p>
</div>
I found a Replacer that it works but the JSON result is too long for what I need
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(circularReference, getCircularReplacer());
And here's the result :
[{"id":"7a69fc68","name":{"type":"input","key":null,"ref":null,"props":{"className":"inputSubs","type":"text","placeholder":"Category Name"},"_owner":{"tag":1,"key":null,"stateNode":{"props":{},"context":{},"refs":{},"updater":{},"notificationAlert":{"current":{"props":{},"refs":{"notifications":{"__reactInternalInstance$6qqi1p3qi9b":{"tag":5,"key":null,"elementType":"div","type":"div","return":{"tag":1,"key":null,"return":{"tag":5,"key":null,"elementType":"div","type" .. etc
Any Help ?

state district json binding react

I want to display display list of districts from the json, receiving the following error
'TypeError: suggestion.districts.slice(...).toLowerCase is not a function'
json file.
How can I get the list of districts details, so that I can perform autocomplete using downshift?
any help appreciated.
json format
{
"states":[
{
"state":"Andhra Pradesh",
"districts":[
"Anantapur",
"Chittoor",
"East Godavari",
]
},
{
"state":"Arunachal Pradesh",
"districts":[
"Tawang",
"West Kameng",
"East Kameng",
]
},
}
component
import React, { Component } from 'react'
import statedist from "./StateDistrict.json";
const suggestions = statedist.states;
/*.... */
function getSuggestions(value, { showEmpty = false } = {}) {
// const StatesSelected=props.StatesSelected;
const inputValue = deburr(value.trim()).toLowerCase();
const inputLength = inputValue.length;
let count = 0;
//console.log(StatesSelected)
return inputLength === 0 && !showEmpty
? []
: suggestions.filter(suggestion => {
const keep =
count < 5 &&
suggestion.districts.slice(0, inputLength).toLowerCase() === inputValue;
if (keep) {
count += 1;
}
return keep;
});
}
function renderSuggestion(suggestionProps) {
const {
suggestion,
index,
itemProps,
highlightedIndex,
selectedItem
} = suggestionProps;
const isHighlighted = highlightedIndex === index;
const isSelected = (selectedItem || "").indexOf(suggestion.districts) > -1;
return (
<MenuItem
{...itemProps}
key={suggestion.districts[0]}
selected={isHighlighted}
component="div"
style={{
fontWeight: isSelected ? 500 : 400
}}
>
{suggestion.districts[0]} -- how can I get all the values instead of one here
</MenuItem>
);
}
class autoCompleteState extends Component {
constructor(props) {
super(props);
this.state = {
SelectedState:'',
}
// this.showProfile = this.showProfile.bind(this)
}
setSelectedDistrict = (newState) => {
this.setState({ SelectedState: newState });
console.log(newState)
this.props.onDistrictSelected(newState);
}
render() {
const { classes, } = this.props;
console.log(this.state.SelectedState)
const StatesSelected=this.props.StateList;
return (
<div>
<DownshiftMultiple
classes={classes}
setSelectedDistrict={this.setSelectedDistrict}
StatesSelected={StatesSelected}
/>
</div>
)
}
}
export default withStyles(Styles)(autoCompleteState);
I want the district details to come as suggestion like state in the below image
Currently, you are doing this:
suggestion.districts.slice(0, inputLength).toLowerCase() === inputValue;
This is throwing an error because .slice is copying inputLength items from your districts array and then trying to call .toLowerCase() on that array.
If I understand correctly, you are trying to filter your districts according to the inputValue. One way of doing this would be to use reduce on the districts array like this:
suggestion.districts.reduce((acc,curr)=>curr.substring(0,inputLength)===inputValue?[...acc,curr.substring(0,inputLength)]:acc, [])
If you only want the first 5 then you can slice the result of this:
suggestion.districts.reduce((acc,curr,index)=>index<5&&curr.substring(0,inputLength)===inputValue?[...acc,curr.substring(0,inputLength)]:acc, [])

Object from Observable then Array from Observable inside a foreach. how to order it?Asynchronous Angular 4/5

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.

NodeJS: Array and/or JSON filled with \r\n when using promises

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)