Vue loading data with async await I get post.likes is undefined - javascript

I am loading data from a back end using axios with async await:
onBeforeMount(async () => {
const feed = await axios.get("api/v1/posts/" + loggedUser + "/home/feed/");
feed.data.sort((a, b) => (a.created_at > b.created_at ? 1 : -1));
homefeed.value = feed.data;
filtered.value = feed.data;
});
I have this function to make a user like a post and unlike a post. It must show the one image if it is liked by a user and another image if it's not yet liked by this user.
I get an error post.likes is undefined if I do not add v-if="post.likes" to the containing div. If I do add it to the containing div then no error and on the posts that do have likes it displays correctly, but on the posts that do not have likes it does not display at all so the user is unable to like the post
Here is the HTML
<div class="postLike flex alignCenter" v-if="post.likes">
<div class="postLikeImg" #click="likePost">
<img
class="functionImg mr5"
alt="Like this post"
src="../assets/img/like.png"
#click="likePost"
v-if="post.likes[0] != true"
/>
<img
class="functionImg mr5"
alt="Like this post"
src="../assets/img/liked.png"
#click="unlikePost"
v-if="post.likes[0] == true"
/>
</div>
<div class="postStatsBtn likeTotal">
{{ post.likes[1] }}
</div>
</div>
The button need to display even if there are no likes for the post so how do I get past the post.likes is undefined please?
Why am I getting the error if I load the data with async await?

Related

Data is shown in the console but not in the website Angular

This is my ngOnInit method:
async ngOnInit() {
return this.http.get(this.apiserver.apiUrl + 'negocios/listadoTodos/?negocio=1').subscribe(async (todos:any) => {
this.detalles = todos;
console.log(this.detalles);
});
}
My console:
enter image description here
My Html:
<div class="text-lg font-bold leading-none" *ngFor="let item of detalles">{{item.nombre}} - {{item.sector}}</div>
Im trying to use an api that is on my localhost and idk why at the console it is working but not in the frontend html.
Your API might tacking time to load data so when API call get data it will print data in console but before that your HTML render on browser, so you need to use *ngIf before you *ngFor like this.
<div *ngIf="detalles.length">
<div class="text-lg font-bold leading-none" *ngFor="let item of detalles">
{{item.nombre}} - {{item.sector}}
</div>
</div>

Angular - Image appears while loading

I have a problem, I got an HTML element that acts like a loding spinner, and I would like it not to be displayed. I would to use the observables to be able to load that element only once the data is fully loaded. So far, in my component, i made it like that :
const matchTableList$ = this.matchTablesService.list().pipe(
map(matchTables => {
matchTables = matchTables.sort((a, b) => a.name.toLocaleLowerCase() === b.name.toLocaleLowerCase() ? 0 : a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase() ? -1 : 1);
this.matchTables$.next(matchTables);
}),
catchError( (error: HttpErrorResponse) => {
this.loadingError$.next(true);
return EMPTY;
}),
finalize(() => {
this.prettyMessageData = new PrettyMessageContent();
this.prettyMessageData.title = "hello"
this.prettyMessageData.message = " ";
this.prettyMessageData.withMessage(this.prettyMessageData.message);
})
);
and in my HTML i made :
<div *ngIf="!matchTablesLine" class="justify-content-center">
<pretty-message style="width: 100%;" [data]="prettyMessageData">
</pretty-message>
<div class="d-flex justify-content-center mt-5">
<button class="btn--primary" (click)="createMatchTable()"><i class="add-circle-line"></i>add</button>
</div>
</div>
So the problem here is that, when there is no data, the pretty message is not displayed, and when there is data, the html div is loaded before i got the data, so it's weird to see a button while the page load. I think it is possible to use observables and operators here, but i really don't know which one to use to make this work. Thanks.
Edit : I solved the problem using a simple resolver, which is really helpful in that kind of cases.
I believe you are trying to delay the rendering of the button while the prettyMessageData is undefined. You can achieve this by adding a *ngIf=prettyMessageData on the button div.
<div *ngIf="prettyMessageData" class="d-flex justify-content-center mt-5">
<button class="btn--primary" (click)="createMatchTable()"><i class="add-circle-line"></i>add</button>
</div>

Get and display data from API using JQuery

So guys, I need to get this API data: https://api.github.com and put it on a HTML file.
So here is the JavaScript code I'm writing:
async function getData()
{
//await the response of the fetch call
let response = await fetch('https://api.github.com');
//proceed once the first promise is resolved.
let data = await response.json()
//proceed only when the second promise is resolved
let newData = data.results;
return newData;
}
//call getData function
getData()
.then(function(result){
$.each(result, (index, user) => {
$('#character').append(`
<div class='card'>
<img
src=${user.image}
alt=''
class='round-img'
/>
<h4 class='card-name'>${user.name}</h4>
<input id="collapsible" class="toggle" type="checkbox">
<label for="collapsible" class="lbl-toggle">
<i class='fas fa-chevron-down'> </i>
</label>
</input>
</div>
`)
});
})
So I'm getting the users info, but I need to display it on a list with limited quantity of users per page. How can I do that?
If you can use an external library, then Data Table is one good library that will give you search, filter, sort, and pagination capability. you just neet to create the table and pass the id of that table to the Data Table library. It will take care of your requirements. You can set max items per page.
https://datatables.net/examples/basic_init/zero_configuration.html
instead of .each(), loop 'result' with a for loop.
var i;
for(i=0;i<(offset+(page*8)+1);i++){
//use result[i] in your html
}
offset if how many records you are in (so 0 for first page)
page is page num (so 1 for first page)
Looking at the documentation you provided.
The API will automatically paginate the responses. You will receive up to 20 documents per page.
The info field on the response will give you some useful information about the dataset, including how many pages there are, the next page & the count of documents.
info: {
count: 493,
pages: 25,
next: "https://rickandmortyapi.com/api/character/?page=2",
prev: ""
}

React dynamically create buttons based on number of results

I am working in a Spring application that uses react. Currently I have a json that contains several users based on certain criteria. The number of users can vary, but I would like to create several buttons for each user returned that links to the users profile. the url is just '/profile/username'
format of json
[{"user":{"principal":"cat#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"cat#sitter.com","zipcode":"98077","firstname":"cat","password":"abc123","sitterFlag":"true","ownerFlag":"false","lastname":"sitter","username":"catsitter","preferredPet":"Cat"},"momento":"cat#sitter.com"},"password":"$2a$10$ltnL.mFqo7hatj69Ls76xeegjhEX0D4At9m1rlBHbQtDrV8MdSeAS","momento":"cat#sitter.com"},{"user":{"principal":"test#pets.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"test#pets.com","zipcode":"98077","firstname":"test","password":"abc123","sitterFlag":"false","ownerFlag":"false","lastname":"pets","username":"testpets"},"momento":"test#pets.com"},"password":"$2a$10$wDhS6Mb8syhC0YIqgVG2qu8J6lA.1T.UprMYwAX6O7Xb3YMhgX3bO","momento":"test#pets.com"},{"user":{"principal":"test#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"test#sitter.com","zipCode":"98077","firstname":"test","password":"abc123","lastname":"sitter","username":"testsitter"},"momento":"test#sitter.com"},"password":"$2a$10$DuIeWFSzhtAjX3lr8xBNiu2kV9kAJ/PQ6pB/EzkB7FkGWfRbwxkzy","momento":"test#sitter.com"},{"user":{"principal":"sit#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"sit#sitter.com","zipCode":"98077","firstname":"sit","password":"abc123","lastname":"sitter","username":"imasitter"},"momento":"sit#sitter.com"},"password":"$2a$10$2NKOQkGZO/jUer3UjNGzdugUhkMV1pJ1eT8NQjSPRto9/cRdm56sO","momento":"sit#sitter.com"},{"user":{"principal":"a#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"a#sitter.com","zipCode":"98077","firstname":"a","password":"abc123","lastname":"sitter","username":"asitter"},"momento":"a#sitter.com"},"password":"$2a$10$8x1uVqR28x5rwNrydieSyu1ILifBJ5n0dUsZI5tJ6MoUWMqXxrmeq","momento":"a#sitter.com"}]
I currently have it working if I hard code for each user:
<div className="container padded">
<div className="row">
<div className="col-6 offset-md-3">
<h2>Suggested Sitters</h2>
<button onClick={() => this.suggestSitter(this.props.user.principal)}>Click</button>
<hr/>
<div>
Sitters:
</div>
<Link to={this.setProfile(this.state.sitter ? this.state.sitter[1].user.attributes.username: ' ')} >
<button type="button">{this.state.sitter ? this.state.sitter[1].user.attributes.username: ' '}</button>
</Link>
</div>
</div>
</div>
the setProfile works like this:
setProfile(theUser) {
return '/profile/' + theUser;
}
Clicking a button will redirect to that user's profile page.
So basically, instead of hardcoding n buttons, I would like to dynamically create n buttons and each will link to '/profile/username/ for each user returned.
suggestSitter function:
suggestSitter(user){
var _this = this;
console.log('user', user);
axios.get('/api/user/suggest_sitter', { params: { principal: user } })
.then(function(response) {
console.log('Response: ' + JSON.stringify(response));
_this.setState({
sitter: response
});
})
.catch(function (e) {
console.log('Error: ' + e);
});
}
You can map the data to an array of Link (provide an unique key for it too):
{this.state.sitter.map((e) => (
<Link key={e.someUniqueProperty} to={this.setProfile(e.user.attributes.username)}>
<button type="button">{e.user.attributes.username}</button>
</Link>
))}
Suppose your data is:
const data = [
{user: {...}, attribute: {...}},
{user: {...}, attribute: {...}},
...
]
Now, you can follow these steps:
Create a stateless/stateful component(depending on your use case): UserButton or any other meaningful name:
const UserButton = () => (
<div className="container padded">
<div className="row">
<div className="col-6 offset-md-3">
/*...Add your remaining JSX....*/
</div>
</div>
</div>
)
Now in your parent component(from where you are actually rendering the data), you can do the following:
renderUserButtons = () => {
return data.map((userData) => (
<UserButton key="Some-unique-id-can-be-anything" PASS_YOUR_PROPS_HERE/>
))
}
render() {
return (
<div>
...
{this.renderUserButtons()}
...
</div>
);
}
Obviously, you don't need multiple components for this, but splitting it into smaller components looks good, easier to maintain and easier to test. Again it's my personal preference. You can use the convention whatever is best for you.
To create any UI component from some array, you can always use map function like below.
Array of JSON Object
let users = [{"name":"ABC"},{"name":"DEF"},{"name":"GHI"}];
Map Function
let userList = users.map((user,index)=>{return (<div>{index} - {user.name}<div>)})
this will give you following output:
0 - ABC
1 - DEF
2 - GHI
in map function user is the reference to one by one users from the array. Index is the key for each value from array (ex. 0,1,2....).
We are returning a JSX object from the return statement.
You can now use userList variable in render's return. Like below..
render(){ let userList = "...."; return(<div>{userList}</div>
I hope this would help.

Mapping APi in react project

I am working on React/Redux e-commerce project, I want to display company logo badge in PLP(Product Listing Page) whether the product is fullified by company or not, The code is working fine in PLP (Product listing page) but when I navigate back to home page than it gives an error, can any one help me and guide me where I am doing wrong, My all code, API response and Error is attached below.
const price = (
<div
className={styles.productPrice}
itemProp="offers"
itemScope
itemType="http://schema.org/Offer"
>
<span className={styles.sellingPrice} itemProp="price">
{product.offer.salePrice
? I18n.formatCurrency(product.offer.salePrice, { valueClass: styles.priceValue })
: I18n.formatCurrency(product.offer.price, { valueClass: styles.priceValue })}
</span>
{product.offer.salePrice && <span className={styles.preReduction}>
<span>{'productBox.pre-reduction', {}, 'was'}</span> {I18n.formatCurrency(product.offer.price)}
</span>}
</div>
);
const productName = (lines) =>
<Shiitake lines={lines} throttleRate={200} className={styles.productName}>
{product.name}
</Shiitake>;
const brandName = product.brand && product.brand.name ?
<Shiitake lines={1} throttleRate={200} className={styles.brandName}>
{product.brand.name}
</Shiitake> : '';
const soldBy = <div className={styles.sellerCtr}>
{ product && catalog && catalog.hits[0].is_fbn &&
<div className={styles.sellerFulfillmentCtr}>
<ShippingBadges showFulfillment />
</div>
}
</div>
Above constants are displayed via this code
<div className={styles.productDetailsContainer}>
{brandName}
{productName(LINES_TO_SHOW)}
{showAdditionalInfo &&
<div>
{hasReviews &&
<div className={styles.ratingBadgesCtr}>
<StarsIconRating
size={11}
score={parseInt(product.review.score) || 0}
count={parseInt(product.review.count) || 0}
showCount
/>
</div>}
</div>}
{product.offer && price}
{soldBy}
</div>}
API Response
Error Screen
The error indicates that, for some reason, your catalog object doesn't have a .hits array. The provided code doesn't, as far as I can see, explain why that would be the case.
You should be able to stop the error (or generate a new error further down) by changing product && catalog && catalog.hits[0].is_fbn to product && catalog && catalog.hits && catalog.hits[0].is_fbn. (Checking that the hits array exists before we try to access index 0) . But that would also mean that the <ShippingBadges > components won't be rendered. I'm not sure what the correct behavior is here.
If this data (catalog.hits) is saved in (and read from) Redux state, then it's surprising that it would disappear just because you navigate somewhere (unless you have some action clearing the state). You could debug Redux state related issues with Redux devtools (for Firefox or Chrome), and/or by putting breakpoints and/or console.logs in the mapStateToProps function you may use to connect Redux to the component that fails.
If, on the other hand, the issue is that this code (the one that generates the error) shouldn't even run when you navigate to "home page", then the issue could be something else entirely.
Try to see in your life cycle, because in that first render your catalog.hits can be undefined because it's not loaded completely. Try
before render if(catalog.hits !== undefined).

Categories